diff options
author | Jaewoong Jung <jungjw@google.com> | 2019-06-17 17:40:56 -0700 |
---|---|---|
committer | Jaewoong Jung <jungjw@google.com> | 2019-06-25 20:56:17 +0000 |
commit | 5c6572e53fa2810e45215850842b81b8fa9a22ec (patch) | |
tree | 0db20545dd2f0cda070b05d11069bb8f813cd09d /java | |
parent | 3ad00bf196544f686eaf8b9caf8ef44d3e991744 (diff) | |
download | build_soong-5c6572e53fa2810e45215850842b81b8fa9a22ec.tar.gz build_soong-5c6572e53fa2810e45215850842b81b8fa9a22ec.tar.bz2 build_soong-5c6572e53fa2810e45215850842b81b8fa9a22ec.zip |
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)
Diffstat (limited to 'java')
-rw-r--r-- | java/aar.go | 10 | ||||
-rw-r--r-- | java/app.go | 79 | ||||
-rw-r--r-- | java/app_test.go | 95 | ||||
-rw-r--r-- | java/java_test.go | 4 |
4 files changed, 177 insertions, 11 deletions
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 <NOTICE dir> 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, |