diff --git a/dexpreopt/config.go b/dexpreopt/config.go index db5e97ae9..064d9d9c5 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -17,6 +17,7 @@ package dexpreopt import ( "encoding/json" "fmt" + "sort" "strings" "github.com/google/blueprint" @@ -100,6 +101,8 @@ type GlobalSoongConfig struct { ConstructContext android.Path } +const UnknownInstallLibraryPath = "error" + // LibraryPath contains paths to the library DEX jar on host and on device. type LibraryPath struct { Host android.Path @@ -109,6 +112,46 @@ type LibraryPath struct { // LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar. type LibraryPaths map[string]*LibraryPath +// Add a new path to the map of library paths, unless a path for this library already exists. +func (libPaths LibraryPaths) AddLibraryPath(ctx android.PathContext, lib *string, hostPath, installPath android.Path) { + if lib == nil { + return + } + if _, present := libPaths[*lib]; !present { + var devicePath string + if installPath != nil { + devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath)) + } else { + // For some stub libraries the only known thing is the name of their implementation + // library, but the library itself is unavailable (missing or part of a prebuilt). In + // such cases we still need to add the library to tags in the manifest, + // but we cannot use if for dexpreopt. + devicePath = UnknownInstallLibraryPath + } + libPaths[*lib] = &LibraryPath{hostPath, devicePath} + } + return +} + +// Add library paths from the second map to the first map (do not override existing entries). +func (libPaths LibraryPaths) AddLibraryPaths(otherPaths LibraryPaths) { + for lib, path := range otherPaths { + if _, present := libPaths[lib]; !present { + libPaths[lib] = path + } + } +} + +// Return sorted names of the libraries in the map. +func (libPaths LibraryPaths) Names() []string { + keys := make([]string, 0, len(libPaths)) + for k := range libPaths { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + type ModuleConfig struct { Name string DexLocation string // dex location on device diff --git a/java/aar.go b/java/aar.go index 778e1cd7a..6e9153cf7 100644 --- a/java/aar.go +++ b/java/aar.go @@ -20,6 +20,7 @@ import ( "strings" "android/soong/android" + "android/soong/dexpreopt" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -99,7 +100,7 @@ type aapt struct { useEmbeddedNativeLibs bool useEmbeddedDex bool usesNonSdkApis bool - sdkLibraries []string + sdkLibraries dexpreopt.LibraryPaths hasNoCode bool LoggingParent string resourceFiles android.Paths @@ -231,6 +232,8 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries := aaptLibs(ctx, sdkContext) + a.sdkLibraries = sdkLibraries + // App manifest file manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) @@ -357,7 +360,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths, - staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) { + staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.LibraryPaths) { var sharedLibs android.Paths @@ -366,6 +369,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, sdkDep.jars...) } + sdkLibraries = make(dexpreopt.LibraryPaths) + ctx.VisitDirectDeps(func(module android.Module) { var exportPackage android.Path aarDep, _ := module.(AndroidLibraryDependency) @@ -385,7 +390,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati // (including the java_sdk_library) itself then append any implicit sdk library // names to the list of sdk libraries to be added to the manifest. if component, ok := module.(SdkLibraryComponentDependency); ok { - sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...) + sdkLibraries.AddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(), + component.DexJarBuildPath(), component.DexJarInstallPath()) } case frameworkResTag: @@ -397,7 +403,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...) transitiveStaticLibs = append(transitiveStaticLibs, exportPackage) transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...) - sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...) + sdkLibraries.AddLibraryPaths(aarDep.ExportedSdkLibs()) if aarDep.ExportedAssets().Valid() { assets = append(assets, aarDep.ExportedAssets().Path()) } @@ -428,7 +434,6 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs) transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests) - sdkLibraries = android.FirstUniqueStrings(sdkLibraries) return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries } @@ -465,8 +470,8 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true - a.aapt.sdkLibraries = a.exportedSdkLibs a.aapt.buildActions(ctx, sdkContext(a)) + a.exportedSdkLibs = a.aapt.sdkLibraries ctx.CheckbuildFile(a.proguardOptionsFile) ctx.CheckbuildFile(a.exportPackage) @@ -749,7 +754,7 @@ func (a *AARImport) AidlIncludeDirs() android.Paths { return nil } -func (a *AARImport) ExportedSdkLibs() []string { +func (a *AARImport) ExportedSdkLibs() dexpreopt.LibraryPaths { return nil } diff --git a/java/android_manifest.go b/java/android_manifest.go index 84dee16c5..f45ebe8d5 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -21,6 +21,7 @@ import ( "github.com/google/blueprint" "android/soong/android" + "android/soong/dexpreopt" ) var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer", @@ -52,7 +53,7 @@ var optionalUsesLibs = []string{ } // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml -func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string, +func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path { var args []string @@ -79,7 +80,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext args = append(args, "--use-embedded-dex") } - for _, usesLib := range sdkLibraries { + for usesLib, _ := range sdkLibraries { if inList(usesLib, optionalUsesLibs) { args = append(args, "--optional-uses-library", usesLib) } else { diff --git a/java/androidmk.go b/java/androidmk.go index bc327cf68..144268f62 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -121,7 +121,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile) } - entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...) + entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs.Names()...) if len(library.additionalCheckedModules) != 0 { entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...) diff --git a/java/app.go b/java/app.go index fd842237b..bfec83fad 100755 --- a/java/app.go +++ b/java/app.go @@ -598,6 +598,7 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx) a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx) a.dexpreopter.manifestFile = a.mergedManifestFile + a.exportedSdkLibs = make(dexpreopt.LibraryPaths) if ctx.ModuleName() != "framework-res" { a.Module.compile(ctx, a.aaptSrcJar) diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 9191a8321..40a2280d9 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -19,6 +19,7 @@ import ( "io" "android/soong/android" + "android/soong/dexpreopt" ) type DeviceHostConverter struct { @@ -162,7 +163,7 @@ func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths { return nil } -func (d *DeviceHostConverter) ExportedSdkLibs() []string { +func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.LibraryPaths { return nil } diff --git a/java/java.go b/java/java.go index 288e2ebf1..25fba13e2 100644 --- a/java/java.go +++ b/java/java.go @@ -29,6 +29,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/dexpreopt" "android/soong/java/config" "android/soong/tradefed" ) @@ -411,8 +412,8 @@ type Module struct { // manifest file to use instead of properties.Manifest overrideManifest android.OptionalPath - // list of SDK lib names that this java module is exporting - exportedSdkLibs []string + // map of SDK libs exported by this java module to their build and install paths + exportedSdkLibs dexpreopt.LibraryPaths // list of plugins that this java module is exporting exportedPluginJars android.Paths @@ -488,14 +489,19 @@ type ApexDependency interface { ImplementationAndResourcesJars() android.Paths } -type Dependency interface { - ApexDependency - ImplementationJars() android.Paths - ResourceJars() android.Paths +// Provides build path and install path to DEX jars. +type UsesLibraryDependency interface { DexJarBuildPath() android.Path DexJarInstallPath() android.Path +} + +type Dependency interface { + ApexDependency + UsesLibraryDependency + ImplementationJars() android.Paths + ResourceJars() android.Paths AidlIncludeDirs() android.Paths - ExportedSdkLibs() []string + ExportedSdkLibs() dexpreopt.LibraryPaths ExportedPlugins() (android.Paths, []string) SrcJarArgs() ([]string, android.Paths) BaseModuleName() string @@ -966,12 +972,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } - // If this is a component library (stubs, etc.) for a java_sdk_library then - // add the name of that java_sdk_library to the exported sdk libs to make sure - // that, if necessary, a element for that java_sdk_library is - // added to the Android manifest. - j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) - ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -991,7 +991,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag: deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...) + j.exportedSdkLibs.AddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath()) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -1002,7 +1002,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag, instrumentationForTag: deps.classpath = append(deps.classpath, dep.HeaderJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) pluginJars, pluginClasses := dep.ExportedPlugins() addPlugins(&deps, pluginJars, pluginClasses...) @@ -1014,7 +1014,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...) deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) pluginJars, pluginClasses := dep.ExportedPlugins() addPlugins(&deps, pluginJars, pluginClasses...) @@ -1077,8 +1077,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } }) - j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs) - return deps } @@ -1819,8 +1817,7 @@ func (j *Module) AidlIncludeDirs() android.Paths { return j.exportAidlIncludeDirs } -func (j *Module) ExportedSdkLibs() []string { - // exportedSdkLibs is type []string +func (j *Module) ExportedSdkLibs() dexpreopt.LibraryPaths { return j.exportedSdkLibs } @@ -1953,6 +1950,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) } j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex + j.exportedSdkLibs = make(dexpreopt.LibraryPaths) j.compile(ctx, nil) // Collect the module directory for IDE info in java/jdeps.go. @@ -1968,6 +1966,12 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Stem()+".jar", j.outputFile, extraInstallDeps...) } + // If this is a component library (stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs.AddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath()) + j.distFiles = j.GenerateTaggedDistFiles(ctx) } @@ -2518,7 +2522,7 @@ type Import struct { properties ImportProperties combinedClasspathFile android.Path - exportedSdkLibs []string + exportedSdkLibs dexpreopt.LibraryPaths exportAidlIncludeDirs android.Paths } @@ -2571,12 +2575,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { TransformJetifier(ctx, outputFile, inputFile) } j.combinedClasspathFile = outputFile - - // If this is a component library (impl, stubs, etc.) for a java_sdk_library then - // add the name of that java_sdk_library to the exported sdk libs to make sure - // that, if necessary, a element for that java_sdk_library is - // added to the Android manifest. - j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) + j.exportedSdkLibs = make(dexpreopt.LibraryPaths) ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) @@ -2587,23 +2586,29 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { switch tag { case libTag, staticLibTag: // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) } case SdkLibraryDependency: switch tag { case libTag: // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, otherName) + j.exportedSdkLibs.AddLibraryPath(ctx, &otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath()) } } }) - j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs) + var installFile android.Path if Bool(j.properties.Installable) { - ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), + installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), jarName, outputFile) } + // If this is a component library (impl, stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs.AddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile) + j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs) } @@ -2646,7 +2651,7 @@ func (j *Import) AidlIncludeDirs() android.Paths { return j.exportAidlIncludeDirs } -func (j *Import) ExportedSdkLibs() []string { +func (j *Import) ExportedSdkLibs() dexpreopt.LibraryPaths { return j.exportedSdkLibs } diff --git a/java/java_test.go b/java/java_test.go index 50c40c38c..0089545ca 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -20,7 +20,6 @@ import ( "path/filepath" "reflect" "regexp" - "sort" "strconv" "strings" "testing" @@ -1496,8 +1495,7 @@ func TestJavaSdkLibrary(t *testing.T) { // test if baz has exported SDK lib names foo and bar to qux qux := ctx.ModuleForTests("qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { - sdkLibs := quxLib.ExportedSdkLibs() - sort.Strings(sdkLibs) + sdkLibs := quxLib.ExportedSdkLibs().Names() if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) { t.Errorf("qux should export %q but exports %q", w, sdkLibs) } diff --git a/java/sdk_library.go b/java/sdk_library.go index 2aae42fc9..6f939a92d 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -849,22 +849,20 @@ func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *andr } // to satisfy SdkLibraryComponentDependency -func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string { - if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil { - return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack} - } - return nil +func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string { + return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack } // Implemented by modules that are (or possibly could be) a component of a java_sdk_library // (including the java_sdk_library) itself. type SdkLibraryComponentDependency interface { + UsesLibraryDependency + // The optional name of the sdk library that should be implicitly added to the // AndroidManifest of an app that contains code which references the sdk library. // - // Returns an array containing 0 or 1 items rather than a *string to make it easier - // to append this to the list of exported sdk libraries. - OptionalImplicitSdkLibrary() []string + // Returns the name of the optional implicit SDK library or nil, if there isn't one. + OptionalImplicitSdkLibrary() *string } // Make sure that all the module types that are components of java_sdk_library/_import @@ -878,6 +876,7 @@ var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil) // Provides access to sdk_version related header and implentation jars. type SdkLibraryDependency interface { SdkLibraryComponentDependency + UsesLibraryDependency // Get the header jars appropriate for the supplied sdk_version. // @@ -1972,7 +1971,7 @@ func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleCont return module.sdkJars(ctx, sdkVersion, false) } -// to satisfy apex.javaDependency interface +// to satisfy SdkLibraryDependency interface func (module *SdkLibraryImport) DexJarBuildPath() android.Path { if module.implLibraryModule == nil { return nil @@ -1981,6 +1980,15 @@ func (module *SdkLibraryImport) DexJarBuildPath() android.Path { } } +// to satisfy SdkLibraryDependency interface +func (module *SdkLibraryImport) DexJarInstallPath() android.Path { + if module.implLibraryModule == nil { + return nil + } else { + return module.implLibraryModule.DexJarInstallPath() + } +} + // to satisfy apex.javaDependency interface func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { if module.implLibraryModule == nil {