diff options
Diffstat (limited to 'java')
-rw-r--r-- | java/androidmk.go | 4 | ||||
-rwxr-xr-x | java/app.go | 1 | ||||
-rw-r--r-- | java/app_import.go | 1 | ||||
-rw-r--r-- | java/boot_image.go | 53 | ||||
-rw-r--r-- | java/dexpreopt.go | 47 | ||||
-rw-r--r-- | java/dexpreopt_bootjars.go | 16 | ||||
-rw-r--r-- | java/dexpreopt_test.go | 2 | ||||
-rw-r--r-- | java/hiddenapi.go | 49 | ||||
-rw-r--r-- | java/hiddenapi_singleton.go | 61 | ||||
-rw-r--r-- | java/testing.go | 10 |
10 files changed, 200 insertions, 44 deletions
diff --git a/java/androidmk.go b/java/androidmk.go index cc454b03d..21f3012a4 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -125,6 +125,10 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_MODULE_STEM", library.Stem()) entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports) + + if library.dexpreopter.configPath != nil { + entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath) + } }, }, }) diff --git a/java/app.go b/java/app.go index e6c9a2d98..ce89e9bb6 100755 --- a/java/app.go +++ b/java/app.go @@ -455,6 +455,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.dexpreopter.installPath = a.installPath(ctx) + a.dexpreopter.isApp = true if a.dexProperties.Uncompress_dex == nil { // If the value was not force-set by the user, use reasonable default based on the module. a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx)) diff --git a/java/app_import.go b/java/app_import.go index df940f1ff..6f21bfbbf 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -255,6 +255,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext installDir = android.PathForModuleInstall(ctx, "app", a.BaseModuleName()) } + a.dexpreopter.isApp = true a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk") a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned) a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx) diff --git a/java/boot_image.go b/java/boot_image.go index 07ef0d841..0a525b752 100644 --- a/java/boot_image.go +++ b/java/boot_image.go @@ -15,9 +15,11 @@ package java import ( + "fmt" "strings" "android/soong/android" + "android/soong/dexpreopt" "github.com/google/blueprint" ) @@ -38,6 +40,7 @@ type bootImageProperties struct { type BootImageModule struct { android.ModuleBase + android.ApexModuleBase properties bootImageProperties } @@ -45,7 +48,8 @@ type BootImageModule struct { func bootImageFactory() android.Module { m := &BootImageModule{} m.AddProperties(&m.properties) - android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibCommon) + android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon) + android.InitApexModule(m) return m } @@ -53,6 +57,9 @@ var BootImageInfoProvider = blueprint.NewProvider(BootImageInfo{}) type BootImageInfo struct { // The image config, internal to this module (and the dex_bootjars singleton). + // + // Will be nil if the BootImageInfo has not been provided for a specific module. That can occur + // when SkipDexpreoptBootJars(ctx) returns true. imageConfig *bootImageConfig } @@ -60,12 +67,56 @@ func (i BootImageInfo) Modules() android.ConfiguredJarList { return i.imageConfig.modules } +// Get a map from ArchType to the associated boot image's contents for Android. +// +// Extension boot images only return their own files, not the files of the boot images they extend. +func (i BootImageInfo) AndroidBootImageFilesByArchType() map[android.ArchType]android.OutputPaths { + files := map[android.ArchType]android.OutputPaths{} + if i.imageConfig != nil { + for _, variant := range i.imageConfig.variants { + // We also generate boot images for host (for testing), but we don't need those in the apex. + // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device + if variant.target.Os == android.Android { + files[variant.target.Arch.ArchType] = variant.imagesDeps + } + } + } + return files +} + +func (b *BootImageModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { + tag := ctx.OtherModuleDependencyTag(dep) + if tag == dexpreopt.Dex2oatDepTag { + // The dex2oat tool is only needed for building and is not required in the apex. + return false + } + panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag))) +} + +func (b *BootImageModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { + return nil +} + +func (b *BootImageModule) DepsMutator(ctx android.BottomUpMutatorContext) { + if SkipDexpreoptBootJars(ctx) { + return + } + + // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The + // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). + dexpreopt.RegisterToolDeps(ctx) +} + func (b *BootImageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Nothing to do if skipping the dexpreopt of boot image jars. if SkipDexpreoptBootJars(ctx) { return } + // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars + // GenerateSingletonBuildActions method as it cannot create it for itself. + dexpreopt.GetGlobalSoongConfig(ctx) + // Get a map of the image configs that are supported. imageConfigs := genBootImageConfigs(ctx) diff --git a/java/dexpreopt.go b/java/dexpreopt.go index b5830c744..ac00592a7 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -30,6 +30,7 @@ type dexpreopter struct { installPath android.InstallPath uncompressedDex bool isSDKLibrary bool + isApp bool isTest bool isPresignedPrebuilt bool @@ -38,6 +39,11 @@ type dexpreopter struct { classLoaderContexts dexpreopt.ClassLoaderContextMap builtInstalled string + + // A path to a dexpreopt.config file generated by Soong for libraries that may be used as a + // <uses-library> by Make modules. The path is passed to Make via LOCAL_SOONG_DEXPREOPT_CONFIG + // variable. If the path is nil, no config is generated (which is the case for apps and tests). + configPath android.WritablePath } type DexpreoptProperties struct { @@ -117,7 +123,40 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo // the dexpreopter struct hasn't been fully initialized before we're called, // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively // disabled, even if installable is true. - if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." { + if d.installPath.Base() == "." { + return + } + + dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) + + buildPath := android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath + + providesUsesLib := ctx.ModuleName() + if ulib, ok := ctx.Module().(ProvidesUsesLib); ok { + name := ulib.ProvidesUsesLib() + if name != nil { + providesUsesLib = *name + } + } + + if !d.isApp && !d.isTest { + // Slim dexpreopt config is serialized to dexpreopt.config files and used by + // dex_preopt_config_merger.py to get information about <uses-library> dependencies. + // Note that it might be needed even if dexpreopt is disabled for this module. + slimDexpreoptConfig := &dexpreopt.ModuleConfig{ + Name: ctx.ModuleName(), + DexLocation: dexLocation, + BuildPath: buildPath, + EnforceUsesLibraries: d.enforceUsesLibs, + ProvidesUsesLibrary: providesUsesLib, + ClassLoaderContexts: d.classLoaderContexts, + // The rest of the fields are not needed. + } + d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config") + dexpreopt.WriteSlimModuleConfigForMake(ctx, slimDexpreoptConfig, d.configPath) + } + + if d.dexpreoptDisabled(ctx) { return } @@ -157,8 +196,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo // The image locations for all Android variants are identical. imageLocations := bootImage.getAnyAndroidVariant().imageLocations() - dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) - var profileClassListing android.OptionalPath var profileBootListing android.OptionalPath profileIsTextListing := false @@ -177,10 +214,11 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo } } + // Full dexpreopt config, used to create dexpreopt build rules. dexpreoptConfig := &dexpreopt.ModuleConfig{ Name: ctx.ModuleName(), DexLocation: dexLocation, - BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath, + BuildPath: buildPath, DexPath: dexJarFile, ManifestPath: d.manifestFile, UncompressedDex: d.uncompressedDex, @@ -192,6 +230,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo ProfileBootListing: profileBootListing, EnforceUsesLibraries: d.enforceUsesLibs, + ProvidesUsesLibrary: providesUsesLib, ClassLoaderContexts: d.classLoaderContexts, Archs: archs, diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 36d0d3017..2a7eb42dc 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -392,22 +392,6 @@ type dexpreoptBootJars struct { dexpreoptConfigForMake android.WritablePath } -// Accessor function for the apex package. Returns nil if dexpreopt is disabled. -func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]android.OutputPaths { - if SkipDexpreoptBootJars(ctx) { - return nil - } - // Include dexpreopt files for the primary boot image. - files := map[android.ArchType]android.OutputPaths{} - for _, variant := range artBootImageConfig(ctx).variants { - // We also generate boot images for host (for testing), but we don't need those in the apex. - if variant.target.Os == android.Android { - files[variant.target.Arch.ArchType] = variant.imagesDeps - } - } - return files -} - // Provide paths to boot images for use by modules that depend upon them. // // The build rules are created in GenerateSingletonBuildActions(). diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go index 5550a4c17..a9e0773b7 100644 --- a/java/dexpreopt_test.go +++ b/java/dexpreopt_test.go @@ -148,7 +148,7 @@ func TestDexpreoptEnabled(t *testing.T) { t.Run(test.name, func(t *testing.T) { ctx, _ := testJava(t, test.bp) - dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeDescription("dexpreopt") + dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt") enabled := dexpreopt.Rule != nil if enabled != test.enabled { diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 71f1e576d..2cd025e43 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -28,10 +28,40 @@ var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", bl }, "outFlag", "stubAPIFlags") type hiddenAPI struct { - bootDexJarPath android.Path - flagsCSVPath android.Path - indexCSVPath android.Path + // The path to the dex jar that is in the boot class path. If this is nil then the associated + // module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional + // annotations for the <x> boot dex jar but which do not actually provide a boot dex jar + // themselves. + bootDexJarPath android.Path + + // The path to the CSV file that contains mappings from Java signature to various flags derived + // from annotations in the source, e.g. whether it is public or the sdk version above which it + // can no longer be used. + // + // It is created by the Class2NonSdkList tool which processes the .class files in the class + // implementation jar looking for UnsupportedAppUsage and CovariantReturnType annotations. The + // tool also consumes the hiddenAPISingletonPathsStruct.stubFlags file in order to perform + // consistency checks on the information in the annotations and to filter out bridge methods + // that are already part of the public API. + flagsCSVPath android.Path + + // The path to the CSV file that contains mappings from Java signature to the value of properties + // specified on UnsupportedAppUsage annotations in the source. + // + // Like the flagsCSVPath file this is also created by the Class2NonSdkList in the same way. + // Although the two files could potentially be created in a single invocation of the + // Class2NonSdkList at the moment they are created using their own invocation, with the behavior + // being determined by the property that is used. metadataCSVPath android.Path + + // The path to the CSV file that contains mappings from Java signature to source location + // information. + // + // It is created by the merge_csv tool which processes the class implementation jar, extracting + // all the files ending in .uau (which are CSV files) and merges them together. The .uau files are + // created by the unsupported app usage annotation processor during compilation of the class + // implementation jar. + indexCSVPath android.Path } func (h *hiddenAPI) flagsCSV() android.Path { @@ -78,11 +108,9 @@ func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bo // not on the list then that will cause failures in the CtsHiddenApiBlacklist... // tests. if inList(bootJarName, ctx.Config().BootJars()) { - // Derive the greylist from classes jar. - flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv") - metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv") - indexCSV := android.PathForModuleOut(ctx, "hiddenapi", "index.csv") - h.hiddenAPIGenerateCSV(ctx, flagsCSV, metadataCSV, indexCSV, implementationJar) + // Create ninja rules to generate various CSV files needed by hiddenapi and store the paths + // in the hiddenAPI structure. + h.hiddenAPIGenerateCSV(ctx, implementationJar) // If this module is actually on the boot jars list and not providing // hiddenapi information for a module on the boot jars list then encode @@ -106,9 +134,10 @@ func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bo return dexJar } -func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, metadataCSV, indexCSV android.WritablePath, classesJar android.Path) { +func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar android.Path) { stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags + flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv") ctx.Build(pctx, android.BuildParams{ Rule: hiddenAPIGenerateCSVRule, Description: "hiddenapi flags", @@ -122,6 +151,7 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, me }) h.flagsCSVPath = flagsCSV + metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv") ctx.Build(pctx, android.BuildParams{ Rule: hiddenAPIGenerateCSVRule, Description: "hiddenapi metadata", @@ -135,6 +165,7 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, me }) h.metadataCSVPath = metadataCSV + indexCSV := android.PathForModuleOut(ctx, "hiddenapi", "index.csv") rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). BuiltTool("merge_csv"). diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 4bd255cbf..ccb874506 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -28,9 +28,64 @@ func init() { } type hiddenAPISingletonPathsStruct struct { - flags android.OutputPath - index android.OutputPath - metadata android.OutputPath + // The path to the CSV file that contains the flags that will be encoded into the dex boot jars. + // + // It is created by the generate_hiddenapi_lists.py tool that is passed the stubFlags along with + // a number of additional files that are used to augment the information in the stubFlags with + // manually curated data. + flags android.OutputPath + + // The path to the CSV index file that contains mappings from Java signature to source location + // information for all Java elements annotated with the UnsupportedAppUsage annotation in the + // source of all the boot jars. + // + // It is created by the merge_csv tool which merges all the hiddenAPI.indexCSVPath files that have + // been created by the rest of the build. That includes the index files generated for + // <x>-hiddenapi modules. + index android.OutputPath + + // The path to the CSV metadata file that contains mappings from Java signature to the value of + // properties specified on UnsupportedAppUsage annotations in the source of all the boot jars. + // + // It is created by the merge_csv tool which merges all the hiddenAPI.metadataCSVPath files that + // have been created by the rest of the build. That includes the metadata files generated for + // <x>-hiddenapi modules. + metadata android.OutputPath + + // The path to the CSV metadata file that contains mappings from Java signature to flags obtained + // from the public, system and test API stubs. + // + // This is created by the hiddenapi tool which is given dex files for the public, system and test + // API stubs (including product specific stubs) along with dex boot jars, so does not include + // <x>-hiddenapi modules. For each API surface (i.e. public, system, test) it records which + // members in the dex boot jars match a member in the dex stub jars for that API surface and then + // outputs a file containing the signatures of all members in the dex boot jars along with the + // flags that indicate which API surface it belongs, if any. + // + // e.g. a dex member that matches a member in the public dex stubs would have flags + // "public-api,system-api,test-api" set (as system and test are both supersets of public). A dex + // member that didn't match a member in any of the dex stubs is still output it just has an empty + // set of flags. + // + // The notion of matching is quite complex, it is not restricted to just exact matching but also + // follows the Java inheritance rules. e.g. if a method is public then all overriding/implementing + // methods are also public. If an interface method is public and a class inherits an + // implementation of that method from a super class then that super class method is also public. + // That ensures that any method that can be called directly by an App through a public method is + // visible to that App. + // + // Propagating the visibility of members across the inheritance hierarchy at build time will cause + // problems when modularizing and unbundling as it that propagation can cross module boundaries. + // e.g. Say that a private framework class implements a public interface and inherits an + // implementation of one of its methods from a core platform ART class. In that case the ART + // implementation method needs to be marked as public which requires the build to have access to + // the framework implementation classes at build time. The work to rectify this is being tracked + // at http://b/178693149. + // + // This file (or at least those items marked as being in the public-api) is used by hiddenapi when + // creating the metadata and flags for the individual modules in order to perform consistency + // checks and filter out bridge methods that are part of the public API. The latter relies on the + // propagation of visibility across the inheritance hierarchy. stubFlags android.OutputPath } diff --git a/java/testing.go b/java/testing.go index 31ff47ff4..5fcf84c6b 100644 --- a/java/testing.go +++ b/java/testing.go @@ -219,16 +219,6 @@ func GatherRequiredDepsForTest() string { dex_bootjars { name: "dex_bootjars", } - - boot_image { - name: "art-boot-image", - image_name: "art", - } - - boot_image { - name: "framework-boot-image", - image_name: "boot", - } ` return bp |