diff --git a/android/deapexer.go b/android/deapexer.go index 9290481d4..bed657464 100644 --- a/android/deapexer.go +++ b/android/deapexer.go @@ -69,6 +69,8 @@ import ( // The information exported by the `deapexer` module, access it using `DeapxerInfoProvider`. type DeapexerInfo struct { + apexModuleName string + // map from the name of an exported file from a prebuilt_apex to the path to that file. The // exported file name is the apex relative path, e.g. javalib/core-libart.jar. // @@ -76,6 +78,11 @@ type DeapexerInfo struct { exports map[string]WritablePath } +// ApexModuleName returns the name of the APEX module that provided the info. +func (i DeapexerInfo) ApexModuleName() string { + return i.apexModuleName +} + // PrebuiltExportPath provides the path, or nil if not available, of a file exported from the // prebuilt_apex that created this ApexInfo. // @@ -95,9 +102,10 @@ var DeapexerProvider = blueprint.NewProvider(DeapexerInfo{}) // for use with a prebuilt_apex module. // // See apex/deapexer.go for more information. -func NewDeapexerInfo(exports map[string]WritablePath) DeapexerInfo { +func NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath) DeapexerInfo { return DeapexerInfo{ - exports: exports, + apexModuleName: apexModuleName, + exports: exports, } } @@ -133,3 +141,20 @@ type RequiresFilesFromPrebuiltApexTag interface { // Method that differentiates this interface from others. RequiresFilesFromPrebuiltApex() } + +// FindDeapexerProviderForModule searches through the direct dependencies of the current context +// module for a DeapexerTag dependency and returns its DeapexerInfo. If there is an error then it is +// reported with ctx.ModuleErrorf and nil is returned. +func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo { + var di *DeapexerInfo + ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) { + p := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo) + di = &p + }) + if di != nil { + return di + } + ai := ctx.Provider(ApexInfoProvider).(ApexInfo) + ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName) + return nil +} diff --git a/apex/apex.go b/apex/apex.go index 2d153e2c0..5294b6c17 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1545,7 +1545,7 @@ func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.Platform type javaModule interface { android.Module BaseModuleName() string - DexJarBuildPath() android.Path + DexJarBuildPath() java.OptionalDexJarPath JacocoReportClassesFile() android.Path LintDepSets() java.LintDepSets Stem() string @@ -1559,7 +1559,7 @@ var _ javaModule = (*java.SdkLibraryImport)(nil) // apexFileForJavaModule creates an apexFile for a java module's dex implementation jar. func apexFileForJavaModule(ctx android.BaseModuleContext, module javaModule) apexFile { - return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath()) + return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath().PathOrNil()) } // apexFileForJavaModuleWithFile creates an apexFile for a java module with the supplied file. diff --git a/apex/apex_test.go b/apex/apex_test.go index 2a2a1f45f..420489e68 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4799,9 +4799,10 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { transform := android.NullFixturePreparer checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) { + t.Helper() // Make sure the import has been given the correct path to the dex jar. p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency) - dexJarBuildPath := p.DexJarBuildPath() + dexJarBuildPath := p.DexJarBuildPath().PathOrNil() stem := android.RemoveOptionalPrebuiltPrefix(name) android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.", ".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar", @@ -4809,6 +4810,7 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { } checkDexJarInstallPath := func(t *testing.T, ctx *android.TestContext, name string) { + t.Helper() // Make sure the import has been given the correct path to the dex jar. p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency) dexJarBuildPath := p.DexJarInstallPath() @@ -4819,6 +4821,7 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { } ensureNoSourceVariant := func(t *testing.T, ctx *android.TestContext, name string) { + t.Helper() // Make sure that an apex variant is not created for the source module. android.AssertArrayString(t, "Check if there is no source variant", []string{"android_common"}, @@ -4856,8 +4859,11 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { // Make sure that dexpreopt can access dex implementation files from the prebuilt. ctx := testDexpreoptWithApexes(t, bp, "", transform) + deapexerName := deapexerModuleName("myapex") + android.AssertStringEquals(t, "APEX module name from deapexer name", "myapex", apexModuleName(deapexerName)) + // Make sure that the deapexer has the correct input APEX. - deapexer := ctx.ModuleForTests("myapex.deapexer", "android_common") + deapexer := ctx.ModuleForTests(deapexerName, "android_common") rule := deapexer.Rule("deapexer") if expected, actual := []string{"myapex-arm64.apex"}, android.NormalizePathsForTesting(rule.Implicits); !reflect.DeepEqual(expected, actual) { t.Errorf("expected: %q, found: %q", expected, actual) diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index 3e19014a3..cb7d3d113 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -22,6 +22,7 @@ import ( "android/soong/android" "android/soong/java" + "github.com/google/blueprint/proptools" ) @@ -737,7 +738,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { func getDexJarPath(result *android.TestResult, name string) string { module := result.Module(name, "android_common") - return module.(java.UsesLibraryDependency).DexJarBuildPath().RelativeToTop().String() + return module.(java.UsesLibraryDependency).DexJarBuildPath().Path().RelativeToTop().String() } // TestBootclasspathFragment_HiddenAPIList checks to make sure that the correct parameters are diff --git a/apex/deapexer.go b/apex/deapexer.go index 2c1835aa4..8c9030a85 100644 --- a/apex/deapexer.go +++ b/apex/deapexer.go @@ -15,6 +15,8 @@ package apex import ( + "strings" + "android/soong/android" ) @@ -75,6 +77,17 @@ type Deapexer struct { inputApex android.Path } +// Returns the name of the deapexer module corresponding to an APEX module with the given name. +func deapexerModuleName(apexModuleName string) string { + return apexModuleName + ".deapexer" +} + +// Returns the name of the APEX module corresponding to an deapexer module with +// the given name. This reverses deapexerModuleName. +func apexModuleName(deapexerModuleName string) string { + return strings.TrimSuffix(deapexerModuleName, ".deapexer") +} + func privateDeapexerFactory() android.Module { module := &Deapexer{} module.AddProperties(&module.properties, &module.selectedApexProperties) @@ -113,7 +126,8 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) { // apex relative path to extracted file path available for other modules. if len(exports) > 0 { // Make the information available for other modules. - ctx.SetProvider(android.DeapexerProvider, android.NewDeapexerInfo(exports)) + di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports) + ctx.SetProvider(android.DeapexerProvider, di) // Create a sorted list of the files that this exports. exportedPaths = android.SortedUniquePaths(exportedPaths) @@ -131,6 +145,6 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) { for _, p := range exportedPaths { command.Output(p.(android.WritablePath)) } - builder.Build("deapexer", "deapex "+ctx.ModuleName()) + builder.Build("deapexer", "deapex "+apexModuleName(ctx.ModuleName())) } } diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 4833a644b..d59f8bfec 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -176,13 +176,15 @@ func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) { name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) if java.IsBootclasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag { // If the exported java module provides a dex jar path then add it to the list of apexFiles. - path := child.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath() - if path != nil { + path := child.(interface { + DexJarBuildPath() java.OptionalDexJarPath + }).DexJarBuildPath() + if path.IsSet() { af := apexFile{ module: child, moduleDir: ctx.OtherModuleDir(child), androidMkModuleName: name, - builtFile: path, + builtFile: path.Path(), class: javaSharedLib, } if module, ok := child.(java.DexpreopterInterface); ok { @@ -629,10 +631,6 @@ func createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerNam ) } -func deapexerModuleName(baseModuleName string) string { - return baseModuleName + ".deapexer" -} - func apexSelectorModuleName(baseModuleName string) string { return baseModuleName + ".apex.selector" } diff --git a/java/androidmk.go b/java/androidmk.go index 71370c9b1..1914595dc 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -29,8 +29,8 @@ func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries { if hostDexNeeded { var output android.Path - if library.dexJarFile != nil { - output = library.dexJarFile + if library.dexJarFile.IsSet() { + output = library.dexJarFile.Path() } else { output = library.implementationAndResourcesJar } @@ -44,8 +44,8 @@ func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries { func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_IS_HOST_MODULE", true) entries.SetPath("LOCAL_PREBUILT_MODULE_FILE", output) - if library.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile) + if library.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile.Path()) } entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar) @@ -106,8 +106,8 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if library.installFile == nil { entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true) } - if library.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile) + if library.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", library.dexJarFile.Path()) } if len(library.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled) @@ -207,8 +207,8 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) - if prebuilt.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile) + if prebuilt.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path()) } entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) @@ -227,12 +227,12 @@ func (prebuilt *DexImport) AndroidMkEntries() []android.AndroidMkEntries { } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - OutputFile: android.OptionalPathForPath(prebuilt.dexJarFile), + OutputFile: android.OptionalPathForPath(prebuilt.dexJarFile.Path()), Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - if prebuilt.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile) + if prebuilt.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path()) } if len(prebuilt.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled) @@ -279,8 +279,8 @@ func (binary *Binary) AndroidMkEntries() []android.AndroidMkEntries { func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetPath("LOCAL_SOONG_HEADER_JAR", binary.headerJarFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", binary.implementationAndResourcesJar) - if binary.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile) + if binary.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", binary.dexJarFile.Path()) } if len(binary.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled) @@ -336,8 +336,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_MODULE", app.installApkName) entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall) entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage) - if app.dexJarFile != nil { - entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile) + if app.dexJarFile.IsSet() { + entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile.Path()) } if app.implementationAndResourcesJar != nil { entries.SetPath("LOCAL_SOONG_CLASSES_JAR", app.implementationAndResourcesJar) diff --git a/java/app.go b/java/app.go index a62e442ac..2fd646322 100755 --- a/java/app.go +++ b/java/app.go @@ -476,7 +476,7 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.Module.compile(ctx, a.aaptSrcJar) } - return a.dexJarFile + return a.dexJarFile.PathOrNil() } func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath { @@ -1305,7 +1305,8 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName) } clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional, tag.implicit, - lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts()) + lib.DexJarBuildPath().PathOrNil(), lib.DexJarInstallPath(), + lib.ClassLoaderContexts()) } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{dep}) } else { diff --git a/java/base.go b/java/base.go index 78aaa19cf..579085b8a 100644 --- a/java/base.go +++ b/java/base.go @@ -276,6 +276,87 @@ func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleCont return false } +// OptionalDexJarPath can be either unset, hold a valid path to a dex jar file, +// or an invalid path describing the reason it is invalid. +// +// It is unset if a dex jar isn't applicable, i.e. no build rule has been +// requested to create one. +// +// If a dex jar has been requested to be built then it is set, and it may be +// either a valid android.Path, or invalid with a reason message. The latter +// happens if the source that should produce the dex file isn't able to. +// +// E.g. it is invalid with a reason message if there is a prebuilt APEX that +// could produce the dex jar through a deapexer module, but the APEX isn't +// installable so doing so wouldn't be safe. +type OptionalDexJarPath struct { + isSet bool + path android.OptionalPath +} + +// IsSet returns true if a path has been set, either invalid or valid. +func (o OptionalDexJarPath) IsSet() bool { + return o.isSet +} + +// Valid returns true if there is a path that is valid. +func (o OptionalDexJarPath) Valid() bool { + return o.isSet && o.path.Valid() +} + +// Path returns the valid path, or panics if it's either not set or is invalid. +func (o OptionalDexJarPath) Path() android.Path { + if !o.isSet { + panic("path isn't set") + } + return o.path.Path() +} + +// PathOrNil returns the path if it's set and valid, or else nil. +func (o OptionalDexJarPath) PathOrNil() android.Path { + if o.Valid() { + return o.Path() + } + return nil +} + +// InvalidReason returns the reason for an invalid path, which is never "". It +// returns "" for an unset or valid path. +func (o OptionalDexJarPath) InvalidReason() string { + if !o.isSet { + return "" + } + return o.path.InvalidReason() +} + +func (o OptionalDexJarPath) String() string { + if !o.isSet { + return "" + } + return o.path.String() +} + +// makeUnsetDexJarPath returns an unset OptionalDexJarPath. +func makeUnsetDexJarPath() OptionalDexJarPath { + return OptionalDexJarPath{isSet: false} +} + +// makeDexJarPathFromOptionalPath returns an OptionalDexJarPath that is set with +// the given OptionalPath, which may be valid or invalid. +func makeDexJarPathFromOptionalPath(path android.OptionalPath) OptionalDexJarPath { + return OptionalDexJarPath{isSet: true, path: path} +} + +// makeDexJarPathFromPath returns an OptionalDexJarPath that is set with the +// valid given path. It returns an unset OptionalDexJarPath if the given path is +// nil. +func makeDexJarPathFromPath(path android.Path) OptionalDexJarPath { + if path == nil { + return makeUnsetDexJarPath() + } + return makeDexJarPathFromOptionalPath(android.OptionalPathForPath(path)) +} + // Module contains the properties and members used by all java module types type Module struct { android.ModuleBase @@ -310,7 +391,7 @@ type Module struct { implementationAndResourcesJar android.Path // output file containing classes.dex and resources - dexJarFile android.Path + dexJarFile OptionalDexJarPath // output file containing uninstrumented classes that will be instrumented by jacoco jacocoReportClassesFile android.Path @@ -1265,12 +1346,13 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex) + + j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), j.implementationJarFile, j.dexProperties.Uncompress_dex) // Encode hidden API flags in dex file, if needed. dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile) - j.dexJarFile = dexOutputFile + j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) // Dexpreopting j.dexpreopt(ctx, dexOutputFile) @@ -1280,7 +1362,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // There is no code to compile into a dex jar, make sure the resources are propagated // to the APK if this is an app. outputFile = implementationAndResourcesJar - j.dexJarFile = j.resourceJar + j.dexJarFile = makeDexJarPathFromPath(j.resourceJar) } if ctx.Failed() { @@ -1470,7 +1552,7 @@ func (j *Module) ImplementationJars() android.Paths { return android.Paths{j.implementationJarFile} } -func (j *Module) DexJarBuildPath() android.Path { +func (j *Module) DexJarBuildPath() OptionalDexJarPath { return j.dexJarFile } diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index b13e2dba4..79c73ca87 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -954,23 +954,11 @@ func (module *prebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx and return nil } - var deapexerModule android.Module - ctx.VisitDirectDeps(func(module android.Module) { - tag := ctx.OtherModuleDependencyTag(module) - // Save away the `deapexer` module on which this depends, if any. - if tag == android.DeapexerTag { - deapexerModule = module - } - }) - - if deapexerModule == nil { - // This should never happen as a variant for a prebuilt_apex is only created if the - // deapexer module has been configured to export the dex implementation jar for this module. - ctx.ModuleErrorf("internal error: module does not depend on a `deapexer` module") - return nil + di := android.FindDeapexerProviderForModule(ctx) + if di == nil { + return nil // An error has been reported by FindDeapexerProviderForModule. } - di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) files := bootImageFilesByArch{} for _, variant := range imageConfig.apexVariants() { arch := variant.target.Arch.ArchType diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 30683daa0..7c8be1e6e 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -30,14 +30,14 @@ type hiddenAPI struct { // that information encoded within it. active bool - // The path to the dex jar that is in the boot class path. If this is nil then the associated + // The path to the dex jar that is in the boot class path. If this is unset then the associated // module is not a boot jar, but could be one of the -hiddenapi modules that provide additional // annotations for the boot dex jar but which do not actually provide a boot dex jar // themselves. // // This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on // this file so using the encoded dex jar here would result in a cycle in the ninja rules. - bootDexJarPath android.Path + bootDexJarPath OptionalDexJarPath // The paths to the classes jars that contain classes and class members annotated with // the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API @@ -49,7 +49,7 @@ type hiddenAPI struct { uncompressDexState *bool } -func (h *hiddenAPI) bootDexJar() android.Path { +func (h *hiddenAPI) bootDexJar() OptionalDexJarPath { return h.bootDexJarPath } @@ -68,7 +68,7 @@ type hiddenAPIModule interface { } type hiddenAPIIntf interface { - bootDexJar() android.Path + bootDexJar() OptionalDexJarPath classesJars() android.Paths uncompressDex() *bool } @@ -79,7 +79,7 @@ var _ hiddenAPIIntf = (*hiddenAPI)(nil) // // uncompressedDexState should be nil when the module is a prebuilt and so does not require hidden // API encoding. -func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar, classesJar android.Path, uncompressedDexState *bool) { +func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar OptionalDexJarPath, classesJar android.Path, uncompressedDexState *bool) { // Save the classes jars even if this is not active as they may be used by modular hidden API // processing. diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 1c6fbac72..b9a1ca74d 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -19,6 +19,7 @@ import ( "strings" "android/soong/android" + "github.com/google/blueprint" ) @@ -277,7 +278,7 @@ func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScop // hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if // available, or reports an error. func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path { - var dexJar android.Path + var dexJar OptionalDexJarPath if sdkLibrary, ok := module.(SdkLibraryDependency); ok { dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind) } else if j, ok := module.(UsesLibraryDependency); ok { @@ -287,10 +288,11 @@ func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android. return nil } - if dexJar == nil { - ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module) + if !dexJar.Valid() { + ctx.ModuleErrorf("dependency %s does not provide a dex jar: %s", module, dexJar.InvalidReason()) + return nil } - return dexJar + return dexJar.Path() } // buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file. @@ -1159,18 +1161,17 @@ func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android // retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule. // -// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that -// create a fake path and either report an error immediately or defer reporting of the error until -// the path is actually used. +// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is unset or +// invalid, then create a fake path and either report an error immediately or defer reporting of the +// error until the path is actually used. func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path { bootDexJar := module.bootDexJar() - if bootDexJar == nil { + if !bootDexJar.Valid() { fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name())) - bootDexJar = fake - - handleMissingDexBootFile(ctx, module, fake) + handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason()) + return fake } - return bootDexJar + return bootDexJar.Path() } // extractClassesJarsFromModules extracts the class jars from the supplied modules. @@ -1264,7 +1265,7 @@ func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.M // handleMissingDexBootFile will either log a warning or create an error rule to create the fake // file depending on the value returned from deferReportingMissingBootDexJar. -func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) { +func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath, reason string) { if deferReportingMissingBootDexJar(ctx, module) { // Create an error rule that pretends to create the output file but will actually fail if it // is run. @@ -1272,11 +1273,11 @@ func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, Rule: android.ErrorRule, Output: fake, Args: map[string]string{ - "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module), + "error": fmt.Sprintf("missing boot dex jar dependency for %s: %s", module, reason), }, }) } else { - ctx.ModuleErrorf("module %s does not provide a dex jar", module) + ctx.ModuleErrorf("module %s does not provide a dex jar: %s", module, reason) } } @@ -1287,14 +1288,13 @@ func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, // However, under certain conditions, e.g. errors, or special build configurations it will return // a path to a fake file. func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path { - bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath() - if bootDexJar == nil { + bootDexJar := module.(interface{ DexJarBuildPath() OptionalDexJarPath }).DexJarBuildPath() + if !bootDexJar.Valid() { fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name())) - bootDexJar = fake - - handleMissingDexBootFile(ctx, module, fake) + handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason()) + return fake } - return bootDexJar + return bootDexJar.Path() } // extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules. diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index dcd363c2c..75b7bb7c8 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -20,6 +20,7 @@ import ( "testing" "android/soong/android" + "github.com/google/blueprint/proptools" ) @@ -306,7 +307,7 @@ func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) { android.AssertStringEquals(t, "encode embedded java_library", unencodedDexJar, actualUnencodedDexJar.String()) // Make sure that the encoded dex jar is the exported one. - exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath() + exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath().Path() android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar) } diff --git a/java/java.go b/java/java.go index 4a4486658..b2c199992 100644 --- a/java/java.go +++ b/java/java.go @@ -219,7 +219,7 @@ type ApexDependency interface { // Provides build path and install path to DEX jars. type UsesLibraryDependency interface { - DexJarBuildPath() android.Path + DexJarBuildPath() OptionalDexJarPath DexJarInstallPath() android.Path ClassLoaderContexts() dexpreopt.ClassLoaderContextMap } @@ -1215,7 +1215,7 @@ type Import struct { properties ImportProperties // output file containing classes.dex and resources - dexJarFile android.Path + dexJarFile OptionalDexJarPath dexJarInstallFile android.Path combinedClasspathFile android.Path @@ -1319,7 +1319,6 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap) var flags javaBuilderFlags - var deapexerModule android.Module ctx.VisitDirectDeps(func(module android.Module) { tag := ctx.OtherModuleDependencyTag(module) @@ -1340,11 +1339,6 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } addCLCFromDep(ctx, module, j.classLoaderContexts) - - // Save away the `deapexer` module on which this depends, if any. - if tag == android.DeapexerTag { - deapexerModule = module - } }) if Bool(j.properties.Installable) { @@ -1359,26 +1353,22 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { // obtained from the associated deapexer module. ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if ai.ForPrebuiltApex { - if deapexerModule == nil { - // This should never happen as a variant for a prebuilt_apex is only created if the - // deapexer module has been configured to export the dex implementation jar for this module. - ctx.ModuleErrorf("internal error: module %q does not depend on a `deapexer` module for prebuilt_apex %q", - j.Name(), ai.ApexVariationName) - return - } - // Get the path of the dex implementation jar from the `deapexer` module. - di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) + di := android.FindDeapexerProviderForModule(ctx) + if di == nil { + return // An error has been reported by FindDeapexerProviderForModule. + } if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(j.BaseModuleName())); dexOutputPath != nil { - j.dexJarFile = dexOutputPath + dexJarFile := makeDexJarPathFromPath(dexOutputPath) + j.dexJarFile = dexJarFile j.dexJarInstallFile = android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName())) // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, dexOutputPath, outputFile, nil) + j.initHiddenAPI(ctx, dexJarFile, outputFile, nil) } else { // This should never happen as a variant for a prebuilt_apex is only created if the // prebuilt_apex has been configured to export the java library dex file. - ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name()) + ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName()) } } else if Bool(j.dexProperties.Compile_dex) { sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) @@ -1407,12 +1397,12 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, dexOutputFile, outputFile, j.dexProperties.Uncompress_dex) + j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), outputFile, j.dexProperties.Uncompress_dex) // Encode hidden API flags in dex file. dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile) - j.dexJarFile = dexOutputFile + j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) j.dexJarInstallFile = android.PathForModuleInstall(ctx, "framework", jarName) } } @@ -1450,7 +1440,7 @@ func (j *Import) ImplementationAndResourcesJars() android.Paths { return android.Paths{j.combinedClasspathFile} } -func (j *Import) DexJarBuildPath() android.Path { +func (j *Import) DexJarBuildPath() OptionalDexJarPath { return j.dexJarFile } @@ -1595,7 +1585,7 @@ type DexImport struct { properties DexImportProperties - dexJarFile android.Path + dexJarFile OptionalDexJarPath dexpreopter @@ -1686,7 +1676,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { }) } - j.dexJarFile = dexOutputFile + j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) j.dexpreopt(ctx, dexOutputFile) @@ -1696,7 +1686,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } -func (j *DexImport) DexJarBuildPath() android.Path { +func (j *DexImport) DexJarBuildPath() OptionalDexJarPath { return j.dexJarFile } @@ -1865,7 +1855,7 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, // from its CLC should be added to the current CLC. if sdkLib != nil { clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, false, true, - dep.DexJarBuildPath(), dep.DexJarInstallPath(), dep.ClassLoaderContexts()) + dep.DexJarBuildPath().PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts()) } else { clcMap.AddContextMap(dep.ClassLoaderContexts(), depName) } diff --git a/java/java_test.go b/java/java_test.go index 8bb017f0b..bc9b40964 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -600,8 +600,8 @@ func TestPrebuilts(t *testing.T) { } barDexJar := barModule.Module().(*Import).DexJarBuildPath() - if barDexJar != nil { - t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar) + if barDexJar.IsSet() { + t.Errorf("bar dex jar build path expected to be set, got %s", barDexJar) } if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) { @@ -612,7 +612,7 @@ func TestPrebuilts(t *testing.T) { t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String()) } - bazDexJar := bazModule.Module().(*Import).DexJarBuildPath() + bazDexJar := bazModule.Module().(*Import).DexJarBuildPath().Path() expectedDexJar := "out/soong/.intermediates/baz/android_common/dex/baz.jar" android.AssertPathRelativeToTopEquals(t, "baz dex jar build path", expectedDexJar, bazDexJar) diff --git a/java/sdk_library.go b/java/sdk_library.go index d46952233..58180f76b 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -540,7 +540,7 @@ type scopePaths struct { // The dex jar for the stubs. // // This is not the implementation jar, it still only contains stubs. - stubsDexJarPath android.Path + stubsDexJarPath OptionalDexJarPath // The API specification file, e.g. system_current.txt. currentApiFilePath android.OptionalPath @@ -915,10 +915,10 @@ func sdkKindToApiScope(kind android.SdkKind) *apiScope { } // to satisfy SdkLibraryDependency interface -func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path { +func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath { paths := c.selectScopePaths(ctx, kind) if paths == nil { - return nil + return makeUnsetDexJarPath() } return paths.stubsDexJarPath @@ -1044,7 +1044,7 @@ type SdkLibraryDependency interface { // SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing // tool which processes dex files. - SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) android.Path + SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath // SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind. SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath @@ -1941,7 +1941,7 @@ type SdkLibraryImport struct { xmlPermissionsFileModule *sdkLibraryXml // Build path to the dex implementation jar obtained from the prebuilt_apex, if any. - dexJarFile android.Path + dexJarFile OptionalDexJarPath // Expected install file path of the source module(sdk_library) // or dex implementation jar obtained from the prebuilt_apex, if any. @@ -2169,8 +2169,6 @@ func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) { func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { module.generateCommonBuildActions(ctx) - var deapexerModule android.Module - // Assume that source module(sdk_library) is installed in //framework module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar") @@ -2199,11 +2197,6 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to) } } - - // Save away the `deapexer` module on which this depends, if any. - if tag == android.DeapexerTag { - deapexerModule = to - } }) // Populate the scope paths with information from the properties. @@ -2223,21 +2216,18 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo // obtained from the associated deapexer module. ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if ai.ForPrebuiltApex { - if deapexerModule == nil { - // This should never happen as a variant for a prebuilt_apex is only created if the - // deapxer module has been configured to export the dex implementation jar for this module. - ctx.ModuleErrorf("internal error: module %q does not depend on a `deapexer` module for prebuilt_apex %q", - module.Name(), ai.ApexVariationName) - } - // Get the path of the dex implementation jar from the `deapexer` module. - di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) + di := android.FindDeapexerProviderForModule(ctx) + if di == nil { + return // An error has been reported by FindDeapexerProviderForModule. + } if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(module.BaseModuleName())); dexOutputPath != nil { - module.dexJarFile = dexOutputPath + dexJarFile := makeDexJarPathFromPath(dexOutputPath) + module.dexJarFile = dexJarFile installPath := android.PathForModuleInPartitionInstall( ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(module.BaseModuleName())) module.installFile = installPath - module.initHiddenAPI(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil) + module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil) // Dexpreopting. module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, installPath) @@ -2247,7 +2237,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo } else { // This should never happen as a variant for a prebuilt_apex is only created if the // prebuilt_apex has been configured to export the java library dex file. - ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name()) + ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName()) } } } @@ -2282,14 +2272,14 @@ func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleCont } // to satisfy UsesLibraryDependency interface -func (module *SdkLibraryImport) DexJarBuildPath() android.Path { +func (module *SdkLibraryImport) DexJarBuildPath() OptionalDexJarPath { // The dex implementation jar extracted from the .apex file should be used in preference to the // source. - if module.dexJarFile != nil { + if module.dexJarFile.IsSet() { return module.dexJarFile } if module.implLibraryModule == nil { - return nil + return makeUnsetDexJarPath() } else { return module.implLibraryModule.DexJarBuildPath() } diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 43542cbdc..2b537398a 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -1307,7 +1307,7 @@ java_sdk_library_import { ctx := android.ModuleInstallPathContextForTesting(result.Config) dexJarBuildPath := func(name string, kind android.SdkKind) string { dep := result.Module(name, "android_common").(java.SdkLibraryDependency) - path := dep.SdkApiStubDexJar(ctx, kind) + path := dep.SdkApiStubDexJar(ctx, kind).Path() return path.RelativeToTop().String() }