From 5c6572e53fa2810e45215850842b81b8fa9a22ec Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Mon, 17 Jun 2019 17:40:56 -0700 Subject: Optionally embed NOTICE files in apks. If embed_notices or ALWAYS_EMBED_NOTICES is set, collect NOTICE files from all dependencies of the android_app, merge them with the app's own one (if exists), transform it to HTML, gzip it, and put it as an asset in the final APK output. Bug: 135460391 Test: app_test.go + Built Mainline modules Change-Id: I52d92e2fd19b3f5f396100424665c5cc344190d8 Merged-In: I52d92e2fd19b3f5f396100424665c5cc344190d8 (cherry picked from commit 5b425e2e20c55216c1ed13fcf047b0df33886736) --- Android.bp | 1 + android/module.go | 16 ++++----- android/notices.go | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ apex/apex.go | 20 +----------- apex/apex_test.go | 8 ++--- java/aar.go | 10 +++++- java/app.go | 79 +++++++++++++++++++++++++++++++++++++++------ java/app_test.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ java/java_test.go | 4 +++ 9 files changed, 278 insertions(+), 42 deletions(-) create mode 100644 android/notices.go diff --git a/Android.bp b/Android.bp index 0121b70e..1d65dff0 100644 --- a/Android.bp +++ b/Android.bp @@ -54,6 +54,7 @@ bootstrap_go_package { "android/mutator.go", "android/namespace.go", "android/neverallow.go", + "android/notices.go", "android/onceper.go", "android/override_module.go", "android/package_ctx.go", diff --git a/android/module.go b/android/module.go index 11e9e917..6a796227 100644 --- a/android/module.go +++ b/android/module.go @@ -849,14 +849,6 @@ func (a *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) } if a.Enabled() { - a.module.GenerateAndroidBuildActions(ctx) - if ctx.Failed() { - return - } - - a.installFiles = append(a.installFiles, ctx.installFiles...) - a.checkbuildFiles = append(a.checkbuildFiles, ctx.checkbuildFiles...) - notice := proptools.StringDefault(a.commonProperties.Notice, "NOTICE") if m := SrcIsModule(notice); m != "" { a.noticeFile = ctx.ExpandOptionalSource(¬ice, "notice") @@ -864,6 +856,14 @@ func (a *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) noticePath := filepath.Join(ctx.ModuleDir(), notice) a.noticeFile = ExistentPathForSource(ctx, noticePath) } + + a.module.GenerateAndroidBuildActions(ctx) + if ctx.Failed() { + return + } + + a.installFiles = append(a.installFiles, ctx.installFiles...) + a.checkbuildFiles = append(a.checkbuildFiles, ctx.checkbuildFiles...) } if a == ctx.FinalModule().(Module).base() { diff --git a/android/notices.go b/android/notices.go new file mode 100644 index 00000000..dbb88fc1 --- /dev/null +++ b/android/notices.go @@ -0,0 +1,87 @@ +// Copyright 2019 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "path/filepath" + + "github.com/google/blueprint" +) + +func init() { + pctx.SourcePathVariable("merge_notices", "build/soong/scripts/mergenotice.py") + pctx.SourcePathVariable("generate_notice", "build/make/tools/generate-notice-files.py") + + pctx.HostBinToolVariable("minigzip", "minigzip") +} + +var ( + mergeNoticesRule = pctx.AndroidStaticRule("mergeNoticesRule", blueprint.RuleParams{ + Command: `${merge_notices} --output $out $in`, + CommandDeps: []string{"${merge_notices}"}, + Description: "merge notice files into $out", + }) + + generateNoticeRule = pctx.AndroidStaticRule("generateNoticeRule", blueprint.RuleParams{ + Command: `rm -rf $tmpDir $$(dirname $out) && ` + + `mkdir -p $tmpDir $$(dirname $out) && ` + + `${generate_notice} --text-output $tmpDir/NOTICE.txt --html-output $tmpDir/NOTICE.html -t "$title" -s $inputDir && ` + + `${minigzip} -c $tmpDir/NOTICE.html > $out`, + CommandDeps: []string{"${generate_notice}", "${minigzip}"}, + Description: "produce notice file $out", + }, "tmpDir", "title", "inputDir") +) + +func MergeNotices(ctx ModuleContext, mergedNotice WritablePath, noticePaths []Path) { + ctx.Build(pctx, BuildParams{ + Rule: mergeNoticesRule, + Description: "merge notices", + Inputs: noticePaths, + Output: mergedNotice, + }) +} + +func BuildNoticeOutput(ctx ModuleContext, installPath OutputPath, installFilename string, + noticePaths []Path) ModuleOutPath { + // Merge all NOTICE files into one. + // TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass. + // + // generate-notice-files.py, which processes the merged NOTICE file, has somewhat strict rules + // about input NOTICE file paths. + // 1. Their relative paths to the src root become their NOTICE index titles. We want to use + // on-device paths as titles, and so output the merged NOTICE file the corresponding location. + // 2. They must end with .txt extension. Otherwise, they're ignored. + noticeRelPath := InstallPathToOnDevicePath(ctx, installPath.Join(ctx, installFilename+".txt")) + mergedNotice := PathForModuleOut(ctx, filepath.Join("NOTICE_FILES/src", noticeRelPath)) + MergeNotices(ctx, mergedNotice, noticePaths) + + // Transform the merged NOTICE file into a gzipped HTML file. + noticeOutput := PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz") + tmpDir := PathForModuleOut(ctx, "NOTICE_tmp") + title := "Notices for " + ctx.ModuleName() + ctx.Build(pctx, BuildParams{ + Rule: generateNoticeRule, + Description: "generate notice output", + Input: mergedNotice, + Output: noticeOutput, + Args: map[string]string{ + "tmpDir": tmpDir.String(), + "title": title, + "inputDir": PathForModuleOut(ctx, "NOTICE_FILES/src").String(), + }, + }) + + return noticeOutput +} diff --git a/apex/apex.go b/apex/apex.go index fa4cb48c..18df4393 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -90,12 +90,6 @@ var ( CommandDeps: []string{"${zip2zip}"}, Description: "app bundle", }, "abi") - - apexMergeNoticeRule = pctx.StaticRule("apexMergeNoticeRule", blueprint.RuleParams{ - Command: `${mergenotice} --output $out $inputs`, - CommandDeps: []string{"${mergenotice}"}, - Description: "merge notice files into $out", - }, "inputs") ) var imageApexSuffix = ".apex" @@ -144,8 +138,6 @@ func init() { pctx.HostBinToolVariable("zip2zip", "zip2zip") pctx.HostBinToolVariable("zipalign", "zipalign") - pctx.SourcePathVariable("mergenotice", "build/soong/scripts/mergenotice.py") - android.RegisterModuleType("apex", apexBundleFactory) android.RegisterModuleType("apex_test", testApexBundleFactory) android.RegisterModuleType("apex_defaults", defaultsFactory) @@ -837,32 +829,22 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (a *apexBundle) buildNoticeFile(ctx android.ModuleContext) { noticeFiles := []android.Path{} - noticeFilesString := []string{} for _, f := range a.filesInfo { if f.module != nil { notice := f.module.NoticeFile() if notice.Valid() { noticeFiles = append(noticeFiles, notice.Path()) - noticeFilesString = append(noticeFilesString, notice.Path().String()) } } } // append the notice file specified in the apex module itself if a.NoticeFile().Valid() { noticeFiles = append(noticeFiles, a.NoticeFile().Path()) - noticeFilesString = append(noticeFilesString, a.NoticeFile().Path().String()) } if len(noticeFiles) > 0 { a.mergedNoticeFile = android.PathForModuleOut(ctx, "NOTICE") - ctx.Build(pctx, android.BuildParams{ - Rule: apexMergeNoticeRule, - Inputs: noticeFiles, - Output: a.mergedNoticeFile, - Args: map[string]string{ - "inputs": strings.Join(noticeFilesString, " "), - }, - }) + android.MergeNotices(ctx, a.mergedNoticeFile, noticeFiles) } } diff --git a/apex/apex_test.go b/apex/apex_test.go index a07a89b8..200a1c29 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -347,10 +347,10 @@ func TestBasicApex(t *testing.T) { t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds) } - apexMergeNoticeRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexMergeNoticeRule") - noticeInputs := strings.Split(apexMergeNoticeRule.Args["inputs"], " ") - if len(noticeInputs) != 3 { - t.Errorf("number of input notice files: expected = 3, actual = %d", len(noticeInputs)) + mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("mergeNoticesRule") + noticeInputs := mergeNoticesRule.Inputs.Strings() + if len(noticeInputs) != 4 { + t.Errorf("number of input notice files: expected = 4, actual = %q", len(noticeInputs)) } ensureListContains(t, noticeInputs, "NOTICE") ensureListContains(t, noticeInputs, "custom_notice") diff --git a/java/aar.go b/java/aar.go index c6212766..6273a9b5 100644 --- a/java/aar.go +++ b/java/aar.go @@ -17,6 +17,7 @@ package java import ( "android/soong/android" "fmt" + "path/filepath" "strings" "github.com/google/blueprint" @@ -78,6 +79,7 @@ type aapt struct { rroDirs []rroDir rTxt android.Path extraAaptPackagesFile android.Path + noticeFile android.OptionalPath isLibrary bool uncompressedJNI bool useEmbeddedDex bool @@ -150,10 +152,16 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, mani assetFiles = append(assetFiles, androidResourceGlob(ctx, dir)...) } + assetDirStrings := assetDirs.Strings() + if a.noticeFile.Valid() { + assetDirStrings = append(assetDirStrings, filepath.Dir(a.noticeFile.Path().String())) + assetFiles = append(assetFiles, a.noticeFile.Path()) + } + linkFlags = append(linkFlags, "--manifest "+manifestPath.String()) linkDeps = append(linkDeps, manifestPath) - linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A ")) + linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A ")) linkDeps = append(linkDeps, assetFiles...) // SDK version flags diff --git a/java/app.go b/java/app.go index da8024fd..8d41b570 100644 --- a/java/app.go +++ b/java/app.go @@ -18,6 +18,7 @@ package java import ( "path/filepath" + "sort" "strings" "github.com/google/blueprint" @@ -79,6 +80,10 @@ type appProperties struct { // Use_embedded_native_libs still selects whether they are stored uncompressed and aligned or compressed. // True for android_test* modules. AlwaysPackageNativeLibs bool `blueprint:"mutated"` + + // If set, find and merge all NOTICE files that this module and its dependencies have and store + // it in the APK as an asset. + Embed_notices *bool } // android_app properties that can be overridden by override_android_app @@ -335,10 +340,74 @@ func (a *AndroidApp) certificateBuildActions(certificateDeps []Certificate, ctx return append([]Certificate{a.certificate}, certificateDeps...) } +func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext, installDir android.OutputPath) android.OptionalPath { + if !Bool(a.appProperties.Embed_notices) && !ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") { + return android.OptionalPath{} + } + + // Collect NOTICE files from all dependencies. + seenModules := make(map[android.Module]bool) + noticePathSet := make(map[android.Path]bool) + + ctx.WalkDepsBlueprint(func(child blueprint.Module, parent blueprint.Module) bool { + if _, ok := child.(android.Module); !ok { + return false + } + module := child.(android.Module) + // Have we already seen this? + if _, ok := seenModules[module]; ok { + return false + } + seenModules[module] = true + + // Skip host modules. + if module.Target().Os.Class == android.Host || module.Target().Os.Class == android.HostCross { + return false + } + + path := module.NoticeFile() + if path.Valid() { + noticePathSet[path.Path()] = true + } + return true + }) + + // If the app has one, add it too. + if a.NoticeFile().Valid() { + noticePathSet[a.NoticeFile().Path()] = true + } + + if len(noticePathSet) == 0 { + return android.OptionalPath{} + } + var noticePaths []android.Path + for path := range noticePathSet { + noticePaths = append(noticePaths, path) + } + sort.Slice(noticePaths, func(i, j int) bool { + return noticePaths[i].String() < noticePaths[j].String() + }) + noticeFile := android.BuildNoticeOutput(ctx, installDir, a.installApkName+".apk", noticePaths) + + return android.OptionalPathForPath(noticeFile) +} + func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Check if the install APK name needs to be overridden. a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name()) + var installDir android.OutputPath + if ctx.ModuleName() == "framework-res" { + // framework-res.apk is installed as system/framework/framework-res.apk + installDir = android.PathForModuleInstall(ctx, "framework") + } else if Bool(a.appProperties.Privileged) { + installDir = android.PathForModuleInstall(ctx, "priv-app", a.installApkName) + } else { + installDir = android.PathForModuleInstall(ctx, "app", a.installApkName) + } + + a.aapt.noticeFile = a.noticeBuildActions(ctx, installDir) + // Process all building blocks, from AAPT to certificates. a.aaptBuildActions(ctx) @@ -374,16 +443,6 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.bundleFile = bundleFile // Install the app package. - var installDir android.OutputPath - if ctx.ModuleName() == "framework-res" { - // framework-res.apk is installed as system/framework/framework-res.apk - installDir = android.PathForModuleInstall(ctx, "framework") - } else if Bool(a.appProperties.Privileged) { - installDir = android.PathForModuleInstall(ctx, "priv-app", a.installApkName) - } else { - installDir = android.PathForModuleInstall(ctx, "app", a.installApkName) - } - ctx.InstallFile(installDir, a.installApkName+".apk", a.outputFile) for _, split := range a.aapt.splits { ctx.InstallFile(installDir, a.installApkName+"_"+split.suffix+".apk", split.path) diff --git a/java/app_test.go b/java/app_test.go index 1f6297c2..d2685107 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -968,3 +968,98 @@ func TestOverrideAndroidApp(t *testing.T) { } } } + +func TestEmbedNotice(t *testing.T) { + ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` + android_app { + name: "foo", + srcs: ["a.java"], + static_libs: ["javalib"], + jni_libs: ["libjni"], + notice: "APP_NOTICE", + embed_notices: true, + } + + // No embed_notice flag + android_app { + name: "bar", + srcs: ["a.java"], + jni_libs: ["libjni"], + notice: "APP_NOTICE", + } + + // No NOTICE files + android_app { + name: "baz", + srcs: ["a.java"], + embed_notices: true, + } + + cc_library { + name: "libjni", + system_shared_libs: [], + stl: "none", + notice: "LIB_NOTICE", + } + + java_library { + name: "javalib", + srcs: [ + ":gen", + ], + } + + genrule { + name: "gen", + tools: ["gentool"], + out: ["gen.java"], + notice: "GENRULE_NOTICE", + } + + java_binary_host { + name: "gentool", + srcs: ["b.java"], + notice: "TOOL_NOTICE", + } + `) + + // foo has NOTICE files to process, and embed_notices is true. + foo := ctx.ModuleForTests("foo", "android_common") + // verify merge notices rule. + mergeNotices := foo.Rule("mergeNoticesRule") + noticeInputs := mergeNotices.Inputs.Strings() + // TOOL_NOTICE should be excluded as it's a host module. + if len(mergeNotices.Inputs) != 3 { + t.Errorf("number of input notice files: expected = 3, actual = %q", noticeInputs) + } + if !inList("APP_NOTICE", noticeInputs) { + t.Errorf("APP_NOTICE is missing from notice files, %q", noticeInputs) + } + if !inList("LIB_NOTICE", noticeInputs) { + t.Errorf("LIB_NOTICE is missing from notice files, %q", noticeInputs) + } + if !inList("GENRULE_NOTICE", noticeInputs) { + t.Errorf("GENRULE_NOTICE is missing from notice files, %q", noticeInputs) + } + // aapt2 flags should include -A so that its contents are put in the APK's /assets. + res := foo.Output("package-res.apk") + aapt2Flags := res.Args["flags"] + e := "-A " + buildDir + "/.intermediates/foo/android_common/NOTICE" + if !strings.Contains(aapt2Flags, e) { + t.Errorf("asset dir flag for NOTICE, %q is missing in aapt2 link flags, %q", e, aapt2Flags) + } + + // bar has NOTICE files to process, but embed_notices is not set. + bar := ctx.ModuleForTests("bar", "android_common") + mergeNotices = bar.MaybeRule("mergeNoticesRule") + if mergeNotices.Rule != nil { + t.Errorf("mergeNotices shouldn't have run for bar") + } + + // baz's embed_notice is true, but it doesn't have any NOTICE files. + baz := ctx.ModuleForTests("baz", "android_common") + mergeNotices = baz.MaybeRule("mergeNoticesRule") + if mergeNotices.Rule != nil { + t.Errorf("mergeNotices shouldn't have run for baz") + } +} diff --git a/java/java_test.go b/java/java_test.go index a5c0aa93..31b23e76 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -119,6 +119,10 @@ func testContext(config android.Config, bp string, "b.kt": nil, "a.jar": nil, "b.jar": nil, + "APP_NOTICE": nil, + "GENRULE_NOTICE": nil, + "LIB_NOTICE": nil, + "TOOL_NOTICE": nil, "java-res/a/a": nil, "java-res/b/b": nil, "java-res2/a": nil, -- cgit v1.2.3 From d6585fe6e34b3181cdaec3892e5214dbf5d25d5e Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Tue, 18 Jun 2019 13:09:13 -0700 Subject: Embed NOTICE output as an APEX asset. Instead of outputting an aggregated NOTICE file as an intermediate build resource to allow Make to include it in the final system-wide NOTICE, process and embed it as an asset in the final APEX. This allows us to update the NOTICE contents automatically when an APEX is updated. Fixes: 135218846 Test: Built mainline modules, apex_test.go Change-Id: Ic851b330fe93be1f602907d44ecc7886c3b0171b Merged-In: Ic851b330fe93be1f602907d44ecc7886c3b0171b (cherry picked from commit 14f5ff62c952350a9e2b07d9d07429b9535655de) --- apex/apex.go | 24 +++++++++++++----------- apex/apex_test.go | 11 ++++++++--- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/apex/apex.go b/apex/apex.go index 18df4393..a546b904 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -394,8 +394,6 @@ type apexBundle struct { container_certificate_file android.Path container_private_key_file android.Path - mergedNoticeFile android.WritablePath - // list of files to be included in this apex filesInfo []apexFile @@ -812,8 +810,6 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") a.filesInfo = filesInfo - a.buildNoticeFile(ctx) - if a.apexTypes.zip() { a.buildUnflattenedApex(ctx, zipApex) } @@ -827,7 +823,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } -func (a *apexBundle) buildNoticeFile(ctx android.ModuleContext) { +func (a *apexBundle) buildNoticeFile(ctx android.ModuleContext, apexFileName string) android.OptionalPath { noticeFiles := []android.Path{} for _, f := range a.filesInfo { if f.module != nil { @@ -842,10 +838,12 @@ func (a *apexBundle) buildNoticeFile(ctx android.ModuleContext) { noticeFiles = append(noticeFiles, a.NoticeFile().Path()) } - if len(noticeFiles) > 0 { - a.mergedNoticeFile = android.PathForModuleOut(ctx, "NOTICE") - android.MergeNotices(ctx, a.mergedNoticeFile, noticeFiles) + if len(noticeFiles) == 0 { + return android.OptionalPath{} } + + return android.OptionalPathForPath( + android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles))) } func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType apexPackaging) { @@ -970,6 +968,13 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType ap } optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion) + noticeFile := a.buildNoticeFile(ctx, ctx.ModuleName()+suffix) + if noticeFile.Valid() { + // If there's a NOTICE file, embed it as an asset file in the APEX. + implicitInputs = append(implicitInputs, noticeFile.Path()) + optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeFile.String())) + } + ctx.Build(pctx, android.BuildParams{ Rule: apexRule, Implicits: implicitInputs, @@ -1209,9 +1214,6 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString())) fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix()) fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable()) - if a.installable() && a.mergedNoticeFile != nil { - fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNoticeFile.String()) - } if len(moduleNames) > 0 { fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " ")) } diff --git a/apex/apex_test.go b/apex/apex_test.go index 200a1c29..c671e7c3 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -27,8 +27,11 @@ import ( "android/soong/java" ) +var buildDir string + func testApex(t *testing.T, bp string) *android.TestContext { - config, buildDir := setup(t) + var config android.Config + config, buildDir = setup(t) defer teardown(buildDir) ctx := android.NewTestArchContext() @@ -310,6 +313,8 @@ func TestBasicApex(t *testing.T) { optFlags := apexRule.Args["opt_flags"] ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey") + // Ensure that the NOTICE output is being packaged as an asset. + ensureContains(t, optFlags, "--assets_dir "+buildDir+"/.intermediates/myapex/android_common_myapex/NOTICE") copyCmds := apexRule.Args["copy_commands"] @@ -349,8 +354,8 @@ func TestBasicApex(t *testing.T) { mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("mergeNoticesRule") noticeInputs := mergeNoticesRule.Inputs.Strings() - if len(noticeInputs) != 4 { - t.Errorf("number of input notice files: expected = 4, actual = %q", len(noticeInputs)) + if len(noticeInputs) != 2 { + t.Errorf("number of input notice files: expected = 2, actual = %q", len(noticeInputs)) } ensureListContains(t, noticeInputs, "NOTICE") ensureListContains(t, noticeInputs, "custom_notice") -- cgit v1.2.3 From 43377eeb3890dcdbc8d5a391c54c5b6062f9d807 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 25 Jun 2019 13:35:30 -0700 Subject: Uncompress dex in unbundled privileged apps Mainline builds privileged apps unbundled and then uses them as prebuilts, so they need to respect the privileged flag when deciding whether or not to uncompress the dex. Bug: 135772877 Test: TestUncompressDex Change-Id: I91da7116b779ae35c0617ef77dbcb9788902370c Merged-In: I91da7116b779ae35c0617ef77dbcb9788902370c (cherry picked from commit 53a87f523b75f86008c3e0971489a06a6450a670) --- android/config.go | 1 + java/app.go | 11 +++---- java/app_test.go | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/android/config.go b/android/config.go index 43eeb975..d1db87b2 100644 --- a/android/config.go +++ b/android/config.go @@ -208,6 +208,7 @@ func TestConfig(buildDir string, env map[string]string) Config { AAPTPreferredConfig: stringPtr("xhdpi"), AAPTCharacteristics: stringPtr("nosdcard"), AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"}, + UncompressPrivAppDex: boolPtr(true), }, buildDir: buildDir, diff --git a/java/app.go b/java/app.go index 8d41b570..ad672ead 100644 --- a/java/app.go +++ b/java/app.go @@ -188,17 +188,18 @@ func (a *AndroidApp) shouldUncompressDex(ctx android.ModuleContext) bool { return true } - if ctx.Config().UnbundledBuild() { - return false - } - - // Uncompress dex in APKs of privileged apps, and modules used by privileged apps. + // Uncompress dex in APKs of privileged apps, and modules used by privileged apps + // (even for unbundled builds, they may be preinstalled as prebuilts). if ctx.Config().UncompressPrivAppDex() && (Bool(a.appProperties.Privileged) || inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules())) { return true } + if ctx.Config().UnbundledBuild() { + return false + } + // Uncompress if the dex files is preopted on /system. if !a.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, a.dexpreopter.installPath)) { return true diff --git a/java/app_test.go b/java/app_test.go index d2685107..2bd44ad4 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -24,6 +24,8 @@ import ( "sort" "strings" "testing" + + "github.com/google/blueprint/proptools" ) var ( @@ -1063,3 +1065,86 @@ func TestEmbedNotice(t *testing.T) { t.Errorf("mergeNotices shouldn't have run for baz") } } + +func TestUncompressDex(t *testing.T) { + testCases := []struct { + name string + bp string + + uncompressedPlatform bool + uncompressedUnbundled bool + }{ + { + name: "normal", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + } + `, + uncompressedPlatform: true, + uncompressedUnbundled: false, + }, + { + name: "use_embedded_dex", + bp: ` + android_app { + name: "foo", + use_embedded_dex: true, + srcs: ["a.java"], + } + `, + uncompressedPlatform: true, + uncompressedUnbundled: true, + }, + { + name: "privileged", + bp: ` + android_app { + name: "foo", + privileged: true, + srcs: ["a.java"], + } + `, + uncompressedPlatform: true, + uncompressedUnbundled: true, + }, + } + + test := func(t *testing.T, bp string, want bool, unbundled bool) { + t.Helper() + + config := testConfig(nil) + if unbundled { + config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) + } + + ctx := testAppContext(config, bp, nil) + + run(t, ctx, config) + + foo := ctx.ModuleForTests("foo", "android_common") + dex := foo.Rule("r8") + uncompressedInDexJar := strings.Contains(dex.Args["zipFlags"], "-L 0") + aligned := foo.MaybeRule("zipalign").Rule != nil + + if uncompressedInDexJar != want { + t.Errorf("want uncompressed in dex %v, got %v", want, uncompressedInDexJar) + } + + if aligned != want { + t.Errorf("want aligned %v, got %v", want, aligned) + } + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + t.Run("platform", func(t *testing.T) { + test(t, tt.bp, tt.uncompressedPlatform, false) + }) + t.Run("unbundled", func(t *testing.T) { + test(t, tt.bp, tt.uncompressedUnbundled, true) + }) + }) + } +} -- cgit v1.2.3