diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/base.go | 21 | ||||
| -rw-r--r-- | java/bootclasspath_fragment.go | 56 | ||||
| -rw-r--r-- | java/hiddenapi.go | 126 | ||||
| -rw-r--r-- | java/hiddenapi_singleton_test.go | 53 | ||||
| -rw-r--r-- | java/java.go | 18 | ||||
| -rw-r--r-- | java/sdk_library.go | 17 |
6 files changed, 153 insertions, 138 deletions
diff --git a/java/base.go b/java/base.go index 03652be05..c828503d4 100644 --- a/java/base.go +++ b/java/base.go @@ -229,12 +229,6 @@ type DeviceProperties struct { // otherwise provides defaults libraries to add to the bootclasspath. System_modules *string - // The name of the module as used in build configuration. - // - // Allows a library to separate its actual name from the name used in - // build configuration, e.g.ctx.Config().BootJars(). - ConfigurationName *string `blueprint:"mutated"` - // set the name of the output Stem *string @@ -1223,11 +1217,11 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { return } - // Update hidden API paths. - j.hiddenAPIUpdatePaths(ctx, dexOutputFile, j.implementationJarFile) + // Initialize the hiddenapi structure. + j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex) // Encode hidden API flags in dex file. - dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile, proptools.Bool(j.dexProperties.Uncompress_dex)) + dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile) // merge dex jar with resources if necessary if j.resourceJar != nil { @@ -1501,15 +1495,6 @@ func (j *Module) Stem() string { return proptools.StringDefault(j.deviceProperties.Stem, j.Name()) } -// ConfigurationName returns the name of the module as used in build configuration. -// -// This is usually the same as BaseModuleName() except for the <x>.impl libraries created by -// java_sdk_library in which case this is the BaseModuleName() without the ".impl" suffix, -// i.e. just <x>. -func (j *Module) ConfigurationName() string { - return proptools.StringDefault(j.deviceProperties.ConfigurationName, j.BaseModuleName()) -} - func (j *Module) JacocoReportClassesFile() android.Path { return j.jacocoReportClassesFile } diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index 16aa5e2ea..b6b877b6f 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -112,6 +112,11 @@ type bootclasspathFragmentProperties struct { Coverage BootclasspathFragmentCoverageAffectedProperties Hidden_api HiddenAPIFlagFileProperties + + // Properties that allow a fragment to depend on other fragments. This is needed for hidden API + // processing as it needs access to all the classes used by a fragment including those provided + // by other fragments. + BootclasspathFragmentsDepsProperties } type BootclasspathFragmentModule struct { @@ -448,12 +453,54 @@ func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleCont return imageConfig } +// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed. +// +// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the +// appropriate information needed for hidden API processing breaking the build. +// TODO(b/179354495): Remove this workaround. +func (b *BootclasspathFragmentModule) canPerformHiddenAPIProcessing(ctx android.ModuleContext) bool { + // Hidden API processing is always enabled in tests. + if ctx.Config().TestProductVariables != nil { + return true + } + // A module that has fragments should have access to the information it needs in order to perform + // hidden API processing. + if len(b.properties.Fragments) != 0 { + return true + } + + // The art bootclasspath fragment does not depend on any other fragments but already supports + // hidden API processing. + imageName := proptools.String(b.properties.Image_name) + if imageName == "art" { + return true + } + + // Disable it for everything else. + return false +} + // generateHiddenAPIBuildActions generates all the hidden API related build rules. func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module) { + // A temporary workaround to avoid existing bootclasspath_fragments that do not provide the + // appropriate information needed for hidden API processing breaking the build. + if !b.canPerformHiddenAPIProcessing(ctx) { + // Nothing to do. + return + } + // Convert the kind specific lists of modules into kind specific lists of jars. stubJarsByKind := hiddenAPIGatherStubLibDexJarPaths(ctx, contents) + // Performing hidden API processing without stubs is not supported and it is unlikely to ever be + // required as the whole point of adding something to the bootclasspath fragment is to add it to + // the bootclasspath in order to be used by something else in the system. Without any stubs it + // cannot do that. + if len(stubJarsByKind) == 0 { + return + } + // Store the information for use by other modules. bootclasspathApiInfo := bootclasspathApiInfo{stubJarsByKind: stubJarsByKind} ctx.SetProvider(bootclasspathApiInfoProvider, bootclasspathApiInfo) @@ -474,15 +521,6 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. // produceHiddenAPIAllFlagsFile produces the hidden API all-flags.csv file (and supporting files) // for the fragment. func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.ModuleContext, contents []hiddenAPIModule, stubJarsByKind map[android.SdkKind]android.Paths, flagFileInfo *hiddenAPIFlagFileInfo) { - // If no stubs have been provided then don't perform hidden API processing. This is a temporary - // workaround to avoid existing bootclasspath_fragments that do not provide stubs breaking the - // build. - // TODO(b/179354495): Remove this workaround. - if len(stubJarsByKind) == 0 { - // Nothing to do. - return - } - // Generate the rules to create the hidden API flags and update the supplied flagFileInfo with the // paths to the created files. hiddenAPIGenerateAllFlagsForBootclasspathFragment(ctx, contents, stubJarsByKind, flagFileInfo) diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 829c47383..1e838247b 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -26,27 +26,10 @@ var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", bl }, "outFlag", "stubAPIFlags") type hiddenAPI struct { - // The name of the module as it would be used in the boot jars configuration, e.g. without any - // prebuilt_ prefix (if it is a prebuilt) and without any ".impl" suffix if it is a - // java_sdk_library implementation library. - configurationName string - // True if the module containing this structure contributes to the hiddenapi information or has // that information encoded within it. active bool - // Identifies the active module variant which will be used as the source of hiddenapi information. - // - // A class may be compiled into a number of different module variants each of which will need the - // hiddenapi information encoded into it and so will be marked as active. However, only one of - // them must be used as a source of information by hiddenapi otherwise it will end up with - // duplicate entries. That module will have primary=true. - // - // Note, that modules <x>-hiddenapi that provide additional annotation information for module <x> - // that is on the bootclasspath are marked as primary=true as they are the primary source of that - // annotation information. - primary bool - // 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 @@ -60,6 +43,10 @@ type hiddenAPI struct { // the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API // processing. classesJarPaths android.Paths + + // The compressed state of the dex file being encoded. This is used to ensure that the encoded + // dex file has the same state. + uncompressDexState *bool } func (h *hiddenAPI) bootDexJar() android.Path { @@ -70,6 +57,10 @@ func (h *hiddenAPI) classesJars() android.Paths { return h.classesJarPaths } +func (h *hiddenAPI) uncompressDex() *bool { + return h.uncompressDexState +} + // hiddenAPIModule is the interface a module that embeds the hiddenAPI structure must implement. type hiddenAPIModule interface { android.Module @@ -79,18 +70,39 @@ type hiddenAPIModule interface { type hiddenAPIIntf interface { bootDexJar() android.Path classesJars() android.Paths + uncompressDex() *bool } var _ hiddenAPIIntf = (*hiddenAPI)(nil) // Initialize the hiddenapi structure -func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, configurationName string) { +// +// 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) { + + // Save the classes jars even if this is not active as they may be used by modular hidden API + // processing. + classesJars := android.Paths{classesJar} + ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) { + javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) + classesJars = append(classesJars, javaInfo.ImplementationJars...) + }) + h.classesJarPaths = classesJars + + // Save the unencoded dex jar so it can be used when generating the + // hiddenAPISingletonPathsStruct.stubFlags file. + h.bootDexJarPath = dexJar + + h.uncompressDexState = uncompressedDexState + // If hiddenapi processing is disabled treat this as inactive. if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { return } - h.configurationName = configurationName + // The context module must implement hiddenAPIModule. + module := ctx.Module().(hiddenAPIModule) // If the frameworks/base directories does not exist and no prebuilt hidden API flag files have // been configured then it is not possible to do hidden API encoding. @@ -102,52 +114,7 @@ func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, configurationNa // on the boot jars list because the runtime only enforces access to the hidden API for the // bootclassloader. If information is gathered for modules not on the list then that will cause // failures in the CtsHiddenApiBlocklist... tests. - module := ctx.Module() h.active = isModuleInBootClassPath(ctx, module) - if !h.active { - // The rest of the properties will be ignored if active is false. - return - } - - // Determine whether this module is the primary module or not. - primary := true - - // A prebuilt module is only primary if it is preferred and conversely a source module is only - // primary if it has not been replaced by a prebuilt module. - if pi, ok := module.(android.PrebuiltInterface); ok { - if p := pi.Prebuilt(); p != nil { - primary = p.UsePrebuilt() - } - } else { - // The only module that will pass a different configurationName to its module name to this - // method is the implementation library of a java_sdk_library. It has a configuration name of - // <x> the same as its parent java_sdk_library but a module name of <x>.impl. It is not the - // primary module, the java_sdk_library with the name of <x> is. - primary = configurationName == ctx.ModuleName() - - // A source module that has been replaced by a prebuilt can never be the primary module. - if module.IsReplacedByPrebuilt() { - if ctx.HasProvider(android.ApexInfoProvider) { - // The source module is in an APEX but the prebuilt module on which it depends is not in an - // APEX and so is not the one that will actually be used for hidden API processing. That - // means it is not possible to check to see if it is a suitable replacement so just assume - // that it is. - primary = false - } else { - ctx.VisitDirectDepsWithTag(android.PrebuiltDepTag, func(prebuilt android.Module) { - if h, ok := prebuilt.(hiddenAPIIntf); ok && h.bootDexJar() != nil { - primary = false - } else { - ctx.ModuleErrorf( - "hiddenapi has determined that the source module %q should be ignored as it has been"+ - " replaced by the prebuilt module %q but unfortunately it does not provide a"+ - " suitable boot dex jar", ctx.ModuleName(), ctx.OtherModuleName(prebuilt)) - } - }) - } - } - } - h.primary = primary } func isModuleInBootClassPath(ctx android.BaseModuleContext, module android.Module) bool { @@ -166,13 +133,19 @@ func isModuleInBootClassPath(ctx android.BaseModuleContext, module android.Modul // // Otherwise, it creates a copy of the supplied dex file into which it has encoded the hiddenapi // flags and returns this instead of the supplied dex jar. -func (h *hiddenAPI) hiddenAPIEncodeDex(ctx android.ModuleContext, dexJar android.OutputPath, uncompressDex bool) android.OutputPath { +func (h *hiddenAPI) hiddenAPIEncodeDex(ctx android.ModuleContext, dexJar android.OutputPath) android.OutputPath { if !h.active { return dexJar } - hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", h.configurationName+".jar").OutputPath + // A nil uncompressDexState prevents the dex file from being encoded. + if h.uncompressDexState == nil { + ctx.ModuleErrorf("cannot encode dex file %s when uncompressDexState is nil", dexJar) + } + uncompressDex := *h.uncompressDexState + + hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", dexJar.Base()).OutputPath // Create a copy of the dex jar which has been encoded with hiddenapi flags. hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex) @@ -183,27 +156,6 @@ func (h *hiddenAPI) hiddenAPIEncodeDex(ctx android.ModuleContext, dexJar android return dexJar } -// hiddenAPIUpdatePaths generates ninja rules to extract the information from the classes -// jar, and outputs it to the appropriate module specific CSV file. -// -// It also makes the dex jar available for use when generating the -// hiddenAPISingletonPathsStruct.stubFlags. -func (h *hiddenAPI) hiddenAPIUpdatePaths(ctx android.ModuleContext, dexJar, classesJar android.Path) { - - // Save the classes jars even if this is not active as they may be used by modular hidden API - // processing. - classesJars := android.Paths{classesJar} - ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) { - javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) - classesJars = append(classesJars, javaInfo.ImplementationJars...) - }) - h.classesJarPaths = classesJars - - // Save the unencoded dex jar so it can be used when generating the - // hiddenAPISingletonPathsStruct.stubFlags file. - h.bootDexJarPath = dexJar -} - // buildRuleToGenerateAnnotationFlags builds a ninja rule to generate the annotation-flags.csv file // from the classes jars and stub-flags.csv files. // diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index e6b45ac20..dcd363c2c 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -274,3 +274,56 @@ func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { android.AssertStringEquals(t, "hiddenapi encode dex rule flags csv", expectedFlagsCsv, actualFlagsCsv) } + +func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) { + + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, + FixtureConfigureBootJars("platform:foo"), + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo"), + + // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding + // is disabled. + android.FixtureAddTextFile("frameworks/base/Android.bp", ""), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + shared_library: false, + compile_dex: true, + public: {enabled: true}, + } + `) + + checkDexEncoded := func(t *testing.T, name, unencodedDexJar, encodedDexJar string) { + moduleForTests := result.ModuleForTests(name, "android_common") + + encodeDexRule := moduleForTests.Rule("hiddenAPIEncodeDex") + actualUnencodedDexJar := encodeDexRule.Input + + // Make sure that the module has its dex jar encoded. + 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() + android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar) + } + + // The java_library embedded with the java_sdk_library must be dex encoded. + t.Run("foo", func(t *testing.T) { + expectedUnencodedDexJar := "out/soong/.intermediates/foo/android_common/aligned/foo.jar" + expectedEncodedDexJar := "out/soong/.intermediates/foo/android_common/hiddenapi/foo.jar" + checkDexEncoded(t, "foo", expectedUnencodedDexJar, expectedEncodedDexJar) + }) + + // The dex jar of the child implementation java_library of the java_sdk_library is not currently + // dex encoded. + t.Run("foo.impl", func(t *testing.T) { + fooImpl := result.ModuleForTests("foo.impl", "android_common") + encodeDexRule := fooImpl.MaybeRule("hiddenAPIEncodeDex") + if encodeDexRule.Rule != nil { + t.Errorf("foo.impl is not expected to be encoded") + } + }) +} diff --git a/java/java.go b/java/java.go index f85de3d77..45eb69339 100644 --- a/java/java.go +++ b/java/java.go @@ -481,11 +481,6 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo } func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { - // Initialize the hiddenapi structure. Pass in the configuration name rather than the module name - // so the hidden api will encode the <x>.impl java_ library created by java_sdk_library just as it - // would the <x> library if <x> was configured as a boot jar. - j.initHiddenAPI(ctx, j.ConfigurationName()) - j.sdkVersion = j.SdkVersion(ctx) j.minSdkVersion = j.MinSdkVersion(ctx) @@ -1241,9 +1236,6 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.sdkVersion = j.SdkVersion(ctx) j.minSdkVersion = j.MinSdkVersion(ctx) - // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, j.BaseModuleName()) - if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() { j.hideApexVariantFromMake = true } @@ -1315,7 +1307,9 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) if dexOutputPath := di.PrebuiltExportPath(j.BaseModuleName(), ".dexjar"); dexOutputPath != nil { j.dexJarFile = dexOutputPath - j.hiddenAPIUpdatePaths(ctx, dexOutputPath, outputFile) + + // Initialize the hiddenapi structure. + j.initHiddenAPI(ctx, dexOutputPath, 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. @@ -1346,11 +1340,11 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } - // Update hidden API paths. - j.hiddenAPIUpdatePaths(ctx, dexOutputFile, outputFile) + // Initialize the hiddenapi structure. + j.initHiddenAPI(ctx, dexOutputFile, outputFile, j.dexProperties.Uncompress_dex) // Encode hidden API flags in dex file. - dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile, proptools.Bool(j.dexProperties.Uncompress_dex)) + dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile) j.dexJarFile = dexOutputFile } diff --git a/java/sdk_library.go b/java/sdk_library.go index f04f837cc..99eacf4e7 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1235,16 +1235,13 @@ func childModuleVisibility(childVisibility []string) []string { // Creates the implementation java library func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) { - moduleNamePtr := proptools.StringPtr(module.BaseModuleName()) - visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility) props := struct { - Name *string - Visibility []string - Instrument bool - Libs []string - ConfigurationName *string + Name *string + Visibility []string + Instrument bool + Libs []string }{ Name: proptools.StringPtr(module.implLibraryModuleName()), Visibility: visibility, @@ -1253,9 +1250,6 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) // Set the impl_only libs. Note that the module's "Libs" get appended as well, via the // addition of &module.properties below. Libs: module.sdkLibraryProperties.Impl_only_libs, - - // Make the created library behave as if it had the same name as this module. - ConfigurationName: moduleNamePtr, } properties := []interface{}{ @@ -2127,8 +2121,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) if dexOutputPath := di.PrebuiltExportPath(module.BaseModuleName(), ".dexjar"); dexOutputPath != nil { module.dexJarFile = dexOutputPath - module.initHiddenAPI(ctx, module.configurationName) - module.hiddenAPIUpdatePaths(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0]) + module.initHiddenAPI(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0], 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. |