diff options
Diffstat (limited to 'java/hiddenapi.go')
-rw-r--r-- | java/hiddenapi.go | 170 |
1 files changed, 130 insertions, 40 deletions
diff --git a/java/hiddenapi.go b/java/hiddenapi.go index eafbf5df0..1651c1c6d 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -28,10 +28,39 @@ 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), without any "-hiddenapi" suffix if it just provides + // annotations 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 + + // True if the module only contains additional annotations and so does not require hiddenapi + // information to be encoded in its dex file and should not be used to generate the + // hiddenAPISingletonPathsStruct.stubFlags file. + annotationsOnly 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 // 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 // The path to the CSV file that contains mappings from Java signature to various flags derived @@ -89,52 +118,109 @@ type hiddenAPIIntf interface { var _ hiddenAPIIntf = (*hiddenAPI)(nil) -func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bool, dexJar android.OutputPath, - implementationJar android.Path, uncompressDex bool) android.OutputPath { - if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { - - // Modules whose names are of the format <x>-hiddenapi provide hiddenapi information - // for the boot jar module <x>. Otherwise, the module provides information for itself. - // Either way extract the name of the boot jar module. - bootJarName := strings.TrimSuffix(name, "-hiddenapi") - - // If this module is on the boot jars list (or providing information for a module - // on the list) then extract the hiddenapi information from it, and if necessary - // encode that information in the generated dex file. - // - // It is important that hiddenapi information is only gathered for/from modules on - // that are actually 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 CtsHiddenApiBlacklist... - // tests. - if inList(bootJarName, ctx.Config().BootJars()) { - // 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 - // the gathered information in the generated dex file. - if name == bootJarName { - hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", name+".jar").OutputPath - - // More than one library with the same classes can be encoded but only one can - // be added to the global set of flags, otherwise it will result in duplicate - // classes which is an error. Therefore, only add the dex jar of one of them - // to the global set of flags. - if primary { - h.bootDexJarPath = dexJar - } - hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex) - dexJar = hiddenAPIJar - } +// Initialize the hiddenapi structure +func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, name string) { + // If hiddenapi processing is disabled treat this as inactive. + if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + return + } + + // Modules whose names are of the format <x>-hiddenapi provide hiddenapi information for the boot + // jar module <x>. Otherwise, the module provides information for itself. Either way extract the + // configurationName of the boot jar module. + configurationName := strings.TrimSuffix(name, "-hiddenapi") + h.configurationName = configurationName + + // It is important that hiddenapi information is only gathered for/from modules that are actually + // 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. + h.active = inList(configurationName, ctx.Config().BootJars()) + if !h.active { + // The rest of the properties will be ignored if active is false. + return + } + + // If this module has a suffix of -hiddenapi then it only provides additional annotation + // information for a module on the boot jars list. + h.annotationsOnly = strings.HasSuffix(name, "-hiddenapi") + + // 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. + module := ctx.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 name 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 = name == ctx.ModuleName() + + // A source module that has been replaced by a prebuilt can never be the primary module. + primary = primary && !module.IsReplacedByPrebuilt() + } + h.primary = primary +} + +// hiddenAPIExtractAndEncode is called by any module that could contribute to the hiddenapi +// processing. +// +// It ignores any module that has not had initHiddenApi() called on it and which is not in the boot +// jar list. +// +// Otherwise, it generates ninja rules to do the following: +// 1. Extract information needed for hiddenapi processing from the module and output it into CSV +// files. +// 2. Conditionally adds the supplied dex file to the list of files used to generate the +// hiddenAPISingletonPathsStruct.stubsFlag file. +// 3. Conditionally 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, otherwise simply returns the supplied +// dex jar. +func (h *hiddenAPI) hiddenAPIExtractAndEncode(ctx android.ModuleContext, dexJar android.OutputPath, + implementationJar android.Path, uncompressDex bool) android.OutputPath { + + if !h.active { + return dexJar + } + + h.hiddenAPIExtractInformation(ctx, dexJar, implementationJar) + + if !h.annotationsOnly { + hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", h.configurationName+".jar").OutputPath + + // Create a copy of the dex jar which has been encoded with hiddenapi flags. + hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex) + + // Use the encoded dex jar from here onwards. + dexJar = hiddenAPIJar } return dexJar } -func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar android.Path) { +// hiddenAPIExtractInformation 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) hiddenAPIExtractInformation(ctx android.ModuleContext, dexJar, classesJar android.Path) { + if !h.active { + return + } + + // More than one library with the same classes may need to be encoded but only one should be + // used as a source of information for hidden API processing otherwise it will result in + // duplicate entries in the files. + if !h.primary { + return + } + stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv") @@ -173,6 +259,10 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar a FlagWithOutput("--output=", indexCSV) rule.Build("merged-hiddenapi-index", "Merged Hidden API index") h.indexCSVPath = indexCSV + + // Save the unencoded dex jar so it can be used when generating the + // hiddenAPISingletonPathsStruct.stubFlags file. + h.bootDexJarPath = dexJar } var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{ |