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
This commit is contained in:
parent
814bebb8ea
commit
6431ca7a3a
|
@ -121,8 +121,19 @@ func InList(s string, list []string) bool {
|
|||
return IndexList(s, list) != -1
|
||||
}
|
||||
|
||||
func PrefixInList(s string, list []string) bool {
|
||||
for _, prefix := range list {
|
||||
// Returns true if the given string s is prefixed with any string in the given prefix list.
|
||||
func PrefixInList(s string, prefixList []string) bool {
|
||||
for _, prefix := range prefixList {
|
||||
if strings.HasPrefix(s, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns true if any string in the given list has the given prefix.
|
||||
func PrefixedStringInList(list []string, prefix string) bool {
|
||||
for _, s := range list {
|
||||
if strings.HasPrefix(s, prefix) {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -147,10 +147,16 @@ var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile",
|
|||
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 @@ func aapt2Link(ctx android.ModuleContext,
|
|||
}
|
||||
|
||||
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, " "),
|
||||
|
|
48
java/aar.go
48
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 @@ type AndroidLibraryDependency interface {
|
|||
ExportedRRODirs() []rroDir
|
||||
ExportedStaticPackages() android.Paths
|
||||
ExportedManifests() android.Paths
|
||||
ExportedAssets() android.OptionalPath
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -92,6 +94,7 @@ type aapt struct {
|
|||
extraAaptPackagesFile android.Path
|
||||
mergedManifestFile android.Path
|
||||
noticeFile android.OptionalPath
|
||||
assetPackage android.OptionalPath
|
||||
isLibrary bool
|
||||
useEmbeddedNativeLibs bool
|
||||
useEmbeddedDex bool
|
||||
|
@ -123,6 +126,10 @@ func (a *aapt) ExportedManifests() android.Paths {
|
|||
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 @@ func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkDep sdkDep) {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex
|
|||
}
|
||||
|
||||
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 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex
|
|||
|
||||
// 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 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
|
|||
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 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
|
|||
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 @@ func (a *AARImport) ExportedManifests() android.Paths {
|
|||
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 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
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 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
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)
|
||||
|
|
101
java/app_test.go
101
java/app_test.go
|
@ -323,6 +323,107 @@ func TestResourceDirs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -48,6 +48,8 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string
|
|||
"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,
|
||||
|
||||
|
|
Loading…
Reference in New Issue