Add enforced RRO support to Soong

Ignore overlay directories that have been selected for enforced RRO
by the product, and pass them to Make instead to be converted to
an auto generated RRO package.

Bug: 69917341
Test: m checkbuild
Change-Id: I8e2677f4c600acdd8dee0869bf4fbc3d5dbc8b44
This commit is contained in:
Colin Cross
2017-11-30 20:13:19 -08:00
parent 527012af07
commit 890ff551f7
4 changed files with 205 additions and 13 deletions

View File

@@ -131,7 +131,7 @@ func (m TestingModule) Output(file string) BuildParams {
outputs = append(outputs, p.Output)
}
for _, f := range outputs {
if f.Rel() == file {
if f.String() == file || f.Rel() == file {
return p
}
}

View File

@@ -143,6 +143,13 @@ func (app *AndroidApp) AndroidMk() android.AndroidMkData {
// framework_res.
fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true")
}
if len(app.rroDirs) > 0 {
fmt.Fprintln(w, "LOCAL_SOONG_RRO_DIRS :=", strings.Join(app.rroDirs.Strings(), " "))
}
fmt.Fprintln(w, "LOCAL_EXPORT_PACKAGE_RESOURCES :=",
Bool(app.appProperties.Export_package_resources))
fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", app.manifestPath.String())
}
},
},

View File

@@ -70,6 +70,8 @@ type AndroidApp struct {
aaptSrcJar android.Path
exportPackage android.Path
rroDirs android.Paths
manifestPath android.Path
}
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -86,7 +88,7 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
linkFlags, linkDeps, resDirs, overlayDirs := a.aapt2Flags(ctx)
linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath := a.aapt2Flags(ctx)
packageRes := android.PathForModuleOut(ctx, "package-res.apk")
srcJar := android.PathForModuleGen(ctx, "R.jar")
@@ -144,6 +146,8 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
a.outputFile = packageFile
a.rroDirs = rroDirs
a.manifestPath = manifestPath
if ctx.ModuleName() == "framework-res" {
// framework-res.apk is installed as system/framework/framework-res.apk
@@ -171,7 +175,7 @@ type globbedResourceDir struct {
}
func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
resDirs, overlayDirs []globbedResourceDir) {
resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths, manifestPath android.Path) {
hasVersionCode := false
hasVersionName := false
@@ -205,7 +209,9 @@ func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps
dir: dir,
files: resourceGlob(ctx, dir),
})
overlayDirs = append(overlayDirs, overlayResourceGlob(ctx, dir)...)
resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
overlayDirs = append(overlayDirs, resOverlayDirs...)
rroDirs = append(rroDirs, resRRODirs...)
}
var assetFiles android.Paths
@@ -221,7 +227,7 @@ func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps
manifestFile = *a.properties.Manifest
}
manifestPath := android.PathForModuleSrc(ctx, manifestFile)
manifestPath = android.PathForModuleSrc(ctx, manifestFile)
linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
linkDeps = append(linkDeps, manifestPath)
@@ -288,7 +294,7 @@ func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps
// TODO: LOCAL_PACKAGE_OVERRIDES
// $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
return linkFlags, linkDeps, resDirs, overlayDirs
return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath
}
func AndroidAppFactory() android.Module {
@@ -320,26 +326,49 @@ func resourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
type overlayGlobResult struct {
dir string
paths android.DirectorySortedPaths
// Set to true of the product has selected that values in this overlay should not be moved to
// Runtime Resource Overlay (RRO) packages.
excludeFromRRO bool
}
const overlayDataKey = "overlayDataKey"
func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) []globbedResourceDir {
func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
rroDirs android.Paths) {
overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
var ret []globbedResourceDir
// Runtime resource overlays (RRO) may be turned on by the product config for some modules
rroEnabled := false
enforceRROTargets := ctx.Config().ProductVariables.EnforceRROTargets
if enforceRROTargets != nil {
if len(*enforceRROTargets) == 1 && (*enforceRROTargets)[0] == "*" {
rroEnabled = true
} else if inList(ctx.ModuleName(), *enforceRROTargets) {
rroEnabled = true
}
}
for _, data := range overlayData {
files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
if len(files) > 0 {
ret = append(ret, globbedResourceDir{
dir: android.PathForSource(ctx, data.dir, dir.String()),
files: files,
})
overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
// If enforce RRO is enabled for this module and this overlay is not in the
// exclusion list, ignore the overlay. The list of ignored overlays will be
// passed to Make to be turned into an RRO package.
if rroEnabled && !data.excludeFromRRO {
rroDirs = append(rroDirs, overlayModuleDir)
} else {
res = append(res, globbedResourceDir{
dir: overlayModuleDir,
files: files,
})
}
}
}
return ret
return res, rroDirs
}
func OverlaySingletonFactory() android.Singleton {
@@ -349,10 +378,25 @@ func OverlaySingletonFactory() android.Singleton {
type overlaySingleton struct{}
func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
// Specific overlays may be excluded from Runtime Resource Overlays by the product config
var rroExcludedOverlays []string
if ctx.Config().ProductVariables.EnforceRROExcludedOverlays != nil {
rroExcludedOverlays = *ctx.Config().ProductVariables.EnforceRROExcludedOverlays
}
var overlayData []overlayGlobResult
for _, overlay := range ctx.Config().ResourceOverlays() {
var result overlayGlobResult
result.dir = overlay
// Mark overlays that will not have Runtime Resource Overlays enforced on them
for _, exclude := range rroExcludedOverlays {
if strings.HasPrefix(overlay, exclude) {
result.excludeFromRRO = true
}
}
files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
if err != nil {
ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())

View File

@@ -91,3 +91,144 @@ func TestApp(t *testing.T) {
expectedLinkImplicits, res.Implicits.Strings())
}
}
var testEnforceRROTests = []struct {
name string
enforceRROTargets []string
enforceRROExcludedOverlays []string
fooOverlayFiles []string
fooRRODirs []string
barOverlayFiles []string
barRRODirs []string
}{
{
name: "no RRO",
enforceRROTargets: nil,
enforceRROExcludedOverlays: nil,
fooOverlayFiles: []string{
"device/vendor/blah/overlay/foo/res/values/strings.xml",
"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
},
fooRRODirs: nil,
barOverlayFiles: []string{
"device/vendor/blah/overlay/bar/res/values/strings.xml",
"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
},
barRRODirs: nil,
},
{
name: "enforce RRO on foo",
enforceRROTargets: []string{"foo"},
enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
fooOverlayFiles: []string{
"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
},
fooRRODirs: []string{
"device/vendor/blah/overlay/foo/res",
},
barOverlayFiles: []string{
"device/vendor/blah/overlay/bar/res/values/strings.xml",
"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
},
barRRODirs: nil,
},
{
name: "enforce RRO on all",
enforceRROTargets: []string{"*"},
enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
fooOverlayFiles: []string{
"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
},
fooRRODirs: []string{
"device/vendor/blah/overlay/foo/res",
},
barOverlayFiles: []string{
"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
},
barRRODirs: []string{
"device/vendor/blah/overlay/bar/res",
},
},
}
func TestEnforceRRO(t *testing.T) {
resourceOverlays := []string{
"device/vendor/blah/overlay",
"device/vendor/blah/overlay2",
"device/vendor/blah/static_overlay",
}
fs := map[string][]byte{
"foo/res/res/values/strings.xml": nil,
"bar/res/res/values/strings.xml": nil,
"device/vendor/blah/overlay/foo/res/values/strings.xml": nil,
"device/vendor/blah/overlay/bar/res/values/strings.xml": nil,
"device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil,
"device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil,
"device/vendor/blah/overlay2/res/values/strings.xml": nil,
}
bp := `
android_app {
name: "foo",
resource_dirs: ["foo/res"],
}
android_app {
name: "bar",
resource_dirs: ["bar/res"],
}
`
for _, testCase := range testEnforceRROTests {
t.Run(testCase.name, func(t *testing.T) {
config := testConfig(nil)
config.ProductVariables.ResourceOverlays = &resourceOverlays
if testCase.enforceRROTargets != nil {
config.ProductVariables.EnforceRROTargets = &testCase.enforceRROTargets
}
if testCase.enforceRROExcludedOverlays != nil {
config.ProductVariables.EnforceRROExcludedOverlays = &testCase.enforceRROExcludedOverlays
}
ctx := testAppContext(config, bp, fs)
run(t, ctx, config)
getOverlays := func(moduleName string) ([]string, []string) {
module := ctx.ModuleForTests(moduleName, "android_common")
overlayCompiledPaths := module.Output("aapt2/overlay.list").Inputs.Strings()
var overlayFiles []string
for _, o := range overlayCompiledPaths {
overlayFiles = append(overlayFiles, module.Output(o).Inputs.Strings()...)
}
rroDirs := module.Module().(*AndroidApp).rroDirs.Strings()
return overlayFiles, rroDirs
}
fooOverlayFiles, fooRRODirs := getOverlays("foo")
barOverlayFiles, barRRODirs := getOverlays("bar")
if !reflect.DeepEqual(fooOverlayFiles, testCase.fooOverlayFiles) {
t.Errorf("expected foo overlay files:\n %#v\n got:\n %#v",
testCase.fooOverlayFiles, fooOverlayFiles)
}
if !reflect.DeepEqual(fooRRODirs, testCase.fooRRODirs) {
t.Errorf("expected foo rroDirs: %#v\n got:\n %#v",
testCase.fooRRODirs, fooRRODirs)
}
if !reflect.DeepEqual(barOverlayFiles, testCase.barOverlayFiles) {
t.Errorf("expected bar overlay files:\n %#v\n got:\n %#v",
testCase.barOverlayFiles, barOverlayFiles)
}
if !reflect.DeepEqual(barRRODirs, testCase.barRRODirs) {
t.Errorf("expected bar rroDirs: %#v\n got:\n %#v",
testCase.barRRODirs, barRRODirs)
}
})
}
}