Add rules to handle asset resources.
AAPT2 ignores assets in overlay resource inputs, so separate rules are
required to extract and merge assets from dependencies.
Test: app_test.go
Test: Added assets to Settings-core for testing
Test: Confirmed Settings.apk contains them with this change.
Fixes: 146655310
Change-Id: Iab8bc61b719541dae64f0e3502bc9cb45a353687
diff --git a/java/aapt2.go b/java/aapt2.go
index cfe0dea..04e4de5 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -147,10 +147,16 @@
RspfileContent: "$in",
})
+var mergeAssetsRule = pctx.AndroidStaticRule("mergeAssets",
+ blueprint.RuleParams{
+ Command: `${config.MergeZipsCmd} ${out} ${in}`,
+ CommandDeps: []string{"${config.MergeZipsCmd}"},
+ })
+
func aapt2Link(ctx android.ModuleContext,
packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath,
flags []string, deps android.Paths,
- compiledRes, compiledOverlay android.Paths, splitPackages android.WritablePaths) {
+ compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) {
genDir := android.PathForModuleGen(ctx, "aapt2", "R")
@@ -186,12 +192,25 @@
}
implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages)
+ linkOutput := packageRes
+
+ // AAPT2 ignores assets in overlays. Merge them after linking.
+ if len(assetPackages) > 0 {
+ linkOutput = android.PathForModuleOut(ctx, "aapt2", "package-res.apk")
+ inputZips := append(android.Paths{linkOutput}, assetPackages...)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: mergeAssetsRule,
+ Inputs: inputZips,
+ Output: packageRes,
+ Description: "merge assets from dependencies",
+ })
+ }
ctx.Build(pctx, android.BuildParams{
Rule: aapt2LinkRule,
Description: "aapt2 link",
Implicits: deps,
- Output: packageRes,
+ Output: linkOutput,
ImplicitOutputs: implicitOutputs,
Args: map[string]string{
"flags": strings.Join(flags, " "),
diff --git a/java/aar.go b/java/aar.go
index ae064e5..c0b39b6 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -15,11 +15,12 @@
package java
import (
- "android/soong/android"
"fmt"
"path/filepath"
"strings"
+ "android/soong/android"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -31,6 +32,7 @@
ExportedRRODirs() []rroDir
ExportedStaticPackages() android.Paths
ExportedManifests() android.Paths
+ ExportedAssets() android.OptionalPath
}
func init() {
@@ -92,6 +94,7 @@
extraAaptPackagesFile android.Path
mergedManifestFile android.Path
noticeFile android.OptionalPath
+ assetPackage android.OptionalPath
isLibrary bool
useEmbeddedNativeLibs bool
useEmbeddedDex bool
@@ -123,6 +126,10 @@
return a.transitiveManifestPaths
}
+func (a *aapt) ExportedAssets() android.OptionalPath {
+ return a.assetPackage
+}
+
func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext,
manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
@@ -215,9 +222,15 @@
}
}
+var extractAssetsRule = pctx.AndroidStaticRule("extractAssets",
+ blueprint.RuleParams{
+ Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} "assets/**/*"`,
+ CommandDeps: []string{"${config.Zip2ZipCmd}"},
+ })
+
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
- transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+ transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries :=
aaptLibs(ctx, sdkContext)
// App manifest file
@@ -317,7 +330,20 @@
}
aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages,
- linkFlags, linkDeps, compiledRes, compiledOverlay, splitPackages)
+ linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages)
+
+ // Extract assets from the resource package output so that they can be used later in aapt2link
+ // for modules that depend on this one.
+ if android.PrefixedStringInList(linkFlags, "-A ") || len(assetPackages) > 0 {
+ assets := android.PathForModuleOut(ctx, "assets.zip")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: extractAssetsRule,
+ Input: packageRes,
+ Output: assets,
+ Description: "extract assets from built resource file",
+ })
+ a.assetPackage = android.OptionalPathForPath(assets)
+ }
a.aaptSrcJar = srcJar
a.exportPackage = packageRes
@@ -331,7 +357,7 @@
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
- staticRRODirs []rroDir, deps android.Paths, flags []string, sdkLibraries []string) {
+ staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) {
var sharedLibs android.Paths
@@ -369,6 +395,9 @@
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...)
+ if aarDep.ExportedAssets().Valid() {
+ assets = append(assets, aarDep.ExportedAssets().Path())
+ }
outer:
for _, d := range aarDep.ExportedRRODirs() {
@@ -398,7 +427,7 @@
transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
sdkLibraries = android.FirstUniqueStrings(sdkLibraries)
- return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags, sdkLibraries
+ return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries
}
type AndroidLibrary struct {
@@ -568,6 +597,11 @@
return android.Paths{a.manifest}
}
+// TODO(jungjw): Decide whether we want to implement this.
+func (a *AARImport) ExportedAssets() android.OptionalPath {
+ return android.OptionalPath{}
+}
+
func (a *AARImport) Prebuilt() *android.Prebuilt {
return &a.prebuilt
}
@@ -656,7 +690,7 @@
linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
linkDeps = append(linkDeps, a.manifest)
- transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+ transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags, sdkLibraries :=
aaptLibs(ctx, sdkContext(a))
_ = staticLibManifests
@@ -669,7 +703,7 @@
overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
- linkFlags, linkDeps, nil, overlayRes, nil)
+ linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
}
var _ Dependency = (*AARImport)(nil)
diff --git a/java/app_test.go b/java/app_test.go
index 9bdef4e..3612112 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -323,6 +323,107 @@
}
}
+func TestLibraryAssets(t *testing.T) {
+ bp := `
+ android_app {
+ name: "foo",
+ sdk_version: "current",
+ static_libs: ["lib1", "lib2", "lib3"],
+ }
+
+ android_library {
+ name: "lib1",
+ sdk_version: "current",
+ asset_dirs: ["assets_a"],
+ }
+
+ android_library {
+ name: "lib2",
+ sdk_version: "current",
+ }
+
+ android_library {
+ name: "lib3",
+ sdk_version: "current",
+ static_libs: ["lib4"],
+ }
+
+ android_library {
+ name: "lib4",
+ sdk_version: "current",
+ asset_dirs: ["assets_b"],
+ }
+ `
+
+ testCases := []struct {
+ name string
+ assetFlag string
+ assetPackages []string
+ }{
+ {
+ name: "foo",
+ // lib1 has its own asset. lib3 doesn't have any, but provides lib4's transitively.
+ assetPackages: []string{
+ buildDir + "/.intermediates/foo/android_common/aapt2/package-res.apk",
+ buildDir + "/.intermediates/lib1/android_common/assets.zip",
+ buildDir + "/.intermediates/lib3/android_common/assets.zip",
+ },
+ },
+ {
+ name: "lib1",
+ assetFlag: "-A assets_a",
+ },
+ {
+ name: "lib2",
+ },
+ {
+ name: "lib3",
+ assetPackages: []string{
+ buildDir + "/.intermediates/lib3/android_common/aapt2/package-res.apk",
+ buildDir + "/.intermediates/lib4/android_common/assets.zip",
+ },
+ },
+ {
+ name: "lib4",
+ assetFlag: "-A assets_b",
+ },
+ }
+ ctx := testApp(t, bp)
+
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ m := ctx.ModuleForTests(test.name, "android_common")
+
+ // Check asset flag in aapt2 link flags
+ var aapt2link android.TestingBuildParams
+ if len(test.assetPackages) > 0 {
+ aapt2link = m.Output("aapt2/package-res.apk")
+ } else {
+ aapt2link = m.Output("package-res.apk")
+ }
+ aapt2Flags := aapt2link.Args["flags"]
+ if test.assetFlag != "" {
+ if !strings.Contains(aapt2Flags, test.assetFlag) {
+ t.Errorf("Can't find asset flag %q in aapt2 link flags %q", test.assetFlag, aapt2Flags)
+ }
+ } else {
+ if strings.Contains(aapt2Flags, " -A ") {
+ t.Errorf("aapt2 link flags %q contain unexpected asset flag", aapt2Flags)
+ }
+ }
+
+ // Check asset merge rule.
+ if len(test.assetPackages) > 0 {
+ mergeAssets := m.Output("package-res.apk")
+ if !reflect.DeepEqual(test.assetPackages, mergeAssets.Inputs.Strings()) {
+ t.Errorf("Unexpected mergeAssets inputs: %v, expected: %v",
+ mergeAssets.Inputs.Strings(), test.assetPackages)
+ }
+ }
+ })
+ }
+}
+
func TestAndroidResources(t *testing.T) {
testCases := []struct {
name string
diff --git a/java/testing.go b/java/testing.go
index 08bae44..3a2fe43 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -48,6 +48,8 @@
"api/test-current.txt": nil,
"api/test-removed.txt": nil,
"framework/aidl/a.aidl": nil,
+ "assets_a/a": nil,
+ "assets_b/b": nil,
"prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so": nil,