From e2ed70c61abb92d355906a51b6df65c5d4e9da4f Mon Sep 17 00:00:00 2001 From: Dennis Shen Date: Wed, 11 Jan 2023 14:15:43 +0000 Subject: [PATCH] Support trimmed variant build in soong variable.go: add a new product variable TrimmedApex which is controlled by environment variable PRODUCT_TRIMMED_APEX config.go: all config to check if trimmed build is turned on or not apex.go: add overridable apex module property: use_DCLA: "use_DCLA" allows user to just use the lib list in DCLA to determine which native shared libraries to trim. This property is no-op if TrimApexEnabled is set to false. builder.go 1, if it is to produce a trimmed variant, fix the default version code by making the last variant digit to 2. this is only useful in local build. in production build, there is apex manifest injection by coastguard that determines the actual version code. 2, create a new apex rule called: "TrimmedApexRule", this rule invokes an apexer wrapper called apexer_with_trim_preprocessing which will properly trim the target libs. BUG: b/259381334 TEST: adbd banchan build for both static and trimmed variant Change-Id: I38a91cdef86a3c9185d00610ab3dd7acd07fd90a --- android/config.go | 4 ++++ android/variable.go | 2 ++ apex/apex.go | 52 ++++++++++++++++++++++++++++++++++++++++++++- apex/builder.go | 48 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/android/config.go b/android/config.go index d5ed883fa..32131fc74 100644 --- a/android/config.go +++ b/android/config.go @@ -1498,6 +1498,10 @@ func (c *config) ApexCompressionEnabled() bool { return Bool(c.productVariables.CompressedApex) && !c.UnbundledBuildApps() } +func (c *config) ApexTrimEnabled() bool { + return Bool(c.productVariables.TrimmedApex) +} + func (c *config) EnforceSystemCertificate() bool { return Bool(c.productVariables.EnforceSystemCertificate) } diff --git a/android/variable.go b/android/variable.go index 97258955a..27c5ef110 100644 --- a/android/variable.go +++ b/android/variable.go @@ -380,6 +380,7 @@ type productVariables struct { Ndk_abis *bool `json:",omitempty"` + TrimmedApex *bool `json:",omitempty"` Flatten_apex *bool `json:",omitempty"` ForceApexSymlinkOptimization *bool `json:",omitempty"` CompressedApex *bool `json:",omitempty"` @@ -502,6 +503,7 @@ func (v *productVariables) SetDefaultConfig() { Malloc_zero_contents: boolPtr(true), Malloc_pattern_fill_contents: boolPtr(false), Safestack: boolPtr(false), + TrimmedApex: boolPtr(false), BootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}}, ApexBootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}}, diff --git a/apex/apex.go b/apex/apex.go index b9a3c8f4f..2e2c2cbf8 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -80,6 +80,7 @@ func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { ctx.BottomUp("apex", apexMutator).Parallel() ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel() ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel() + ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel() // Register after apex_info mutator so that it can use ApexVariationName ctx.TopDown("apex_strict_updatability_lint", apexStrictUpdatibilityLintMutator).Parallel() } @@ -389,6 +390,9 @@ type overridableProperties struct { // conditions, e.g., target device needs to support APEX compression, are also fulfilled. // Default: false. Compressible *bool + + // Trim against a specific Dynamic Common Lib APEX + Trim_against *string } type apexBundle struct { @@ -675,6 +679,7 @@ var ( androidAppTag = &dependencyTag{name: "androidApp", payload: true} bpfTag = &dependencyTag{name: "bpf", payload: true} certificateTag = &dependencyTag{name: "certificate"} + dclaTag = &dependencyTag{name: "dcla"} executableTag = &dependencyTag{name: "executable", payload: true} fsTag = &dependencyTag{name: "filesystem", payload: true} bcpfTag = &dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true, memberType: java.BootclasspathFragmentSdkMemberType} @@ -908,6 +913,33 @@ func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutato } } +func apexDCLADepsMutator(mctx android.BottomUpMutatorContext) { + if !mctx.Config().ApexTrimEnabled() { + return + } + if a, ok := mctx.Module().(*apexBundle); ok && a.overridableProperties.Trim_against != nil { + commonVariation := mctx.Config().AndroidCommonTarget.Variations() + mctx.AddFarVariationDependencies(commonVariation, dclaTag, String(a.overridableProperties.Trim_against)) + } else if o, ok := mctx.Module().(*OverrideApex); ok { + for _, p := range o.GetProperties() { + properties, ok := p.(*overridableProperties) + if !ok { + continue + } + if properties.Trim_against != nil { + commonVariation := mctx.Config().AndroidCommonTarget.Variations() + mctx.AddFarVariationDependencies(commonVariation, dclaTag, String(properties.Trim_against)) + } + } + } +} + +type DCLAInfo struct { + ProvidedLibs []string +} + +var DCLAInfoProvider = blueprint.NewMutatorProvider(DCLAInfo{}, "apex_info") + type ApexBundleInfo struct { Contents *android.ApexContents } @@ -1035,6 +1067,12 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { child.(android.ApexModule).BuildForApex(apexInfo) // leave a mark! return true }) + + if a.dynamic_common_lib_apex() { + mctx.SetProvider(DCLAInfoProvider, DCLAInfo{ + ProvidedLibs: a.properties.Native_shared_libs, + }) + } } type ApexInfoMutator interface { @@ -1531,6 +1569,19 @@ func (a *apexBundle) dynamic_common_lib_apex() bool { return proptools.BoolDefault(a.properties.Dynamic_common_lib_apex, false) } +// See the list of libs to trim +func (a *apexBundle) libs_to_trim(ctx android.ModuleContext) []string { + dclaModules := ctx.GetDirectDepsWithTag(dclaTag) + if len(dclaModules) > 1 { + panic(fmt.Errorf("expected exactly at most one dcla dependency, got %d", len(dclaModules))) + } + if len(dclaModules) > 0 { + DCLAInfo := ctx.OtherModuleProvider(dclaModules[0], DCLAInfoProvider).(DCLAInfo) + return DCLAInfo.ProvidedLibs + } + return []string{} +} + // These functions are interfacing with cc/sanitizer.go. The entire APEX (along with all of its // members) can be sanitized, either forcibly, or by the global configuration. For some of the // sanitizers, extra dependencies can be forcibly added as well. @@ -2473,7 +2524,6 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } //////////////////////////////////////////////////////////////////////////////////////////// // 2) traverse the dependency tree to collect apexFile structs from them. - // Collect the module directory for IDE info in java/jdeps.go. a.modulePaths = append(a.modulePaths, ctx.ModuleDir()) diff --git a/apex/builder.go b/apex/builder.go index 3b9cac069..984e7f052 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -40,6 +40,8 @@ func init() { pctx.Import("android/soong/java") pctx.HostBinToolVariable("apexer", "apexer") pctx.HostBinToolVariable("apexer_with_DCLA_preprocessing", "apexer_with_DCLA_preprocessing") + pctx.HostBinToolVariable("apexer_with_trim_preprocessing", "apexer_with_trim_preprocessing") + // ART minimal builds (using the master-art manifest) do not have the "frameworks/base" // projects, and hence cannot build 'aapt2'. Use the SDK prebuilt instead. hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) { @@ -146,6 +148,34 @@ var ( }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "is_DCLA") + TrimmedApexRule = pctx.StaticRule("TrimmedApexRule", blueprint.RuleParams{ + Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` + + `(. ${out}.copy_commands) && ` + + `APEXER_TOOL_PATH=${tool_path} ` + + `${apexer_with_trim_preprocessing} ` + + `--apexer ${apexer} ` + + `--canned_fs_config ${canned_fs_config} ` + + `--manifest ${manifest} ` + + `--libs_to_trim ${libs_to_trim} ` + + `${image_dir} ` + + `${out} ` + + `-- ` + + `--include_build_info ` + + `--force ` + + `--payload_type image ` + + `--key ${key} ` + + `--file_contexts ${file_contexts} ` + + `${opt_flags} `, + CommandDeps: []string{"${apexer_with_trim_preprocessing}", "${apexer}", "${avbtool}", "${e2fsdroid}", + "${merge_zips}", "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", + "${sload_f2fs}", "${make_erofs}", "${soong_zip}", "${zipalign}", "${aapt2}", + "prebuilts/sdk/current/public/android.jar"}, + Rspfile: "${out}.copy_commands", + RspfileContent: "${copy_commands}", + Description: "APEX ${image_dir} => ${out}", + }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", + "opt_flags", "manifest", "libs_to_trim") + zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{ Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` + `(. ${out}.copy_commands) && ` + @@ -706,6 +736,24 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { "opt_flags": strings.Join(optFlags, " "), }, }) + } else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 { + ctx.Build(pctx, android.BuildParams{ + Rule: TrimmedApexRule, + Implicits: implicitInputs, + Output: unsignedOutputFile, + Description: "apex (" + apexType.name() + ")", + Args: map[string]string{ + "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir, + "image_dir": imageDir.String(), + "copy_commands": strings.Join(copyCommands, " && "), + "manifest": a.manifestPbOut.String(), + "file_contexts": fileContexts.String(), + "canned_fs_config": cannedFsConfig.String(), + "key": a.privateKeyFile.String(), + "opt_flags": strings.Join(optFlags, " "), + "libs_to_trim": strings.Join(a.libs_to_trim(ctx), ","), + }, + }) } else { ctx.Build(pctx, android.BuildParams{ Rule: apexRule,