Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c779cd40 authored by Jaewoong Jung's avatar Jaewoong Jung
Browse files

Apply PRODUCT_ENFORCE_RRO_TARGETS to dependencies.

With this change, users don't need to figure out which libraries
actually hold the resources to be overlaid when targetting apps with a
core lib dependency (e.g. Settings, SystemUI).

Fixes: 169898727
Test: app_test.go
Change-Id: I3c3b9dc0a377b1828db1199858a73d080a173205
parent 3c72ce86
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -916,6 +916,10 @@ func (c *config) EnforceRROForModule(name string) bool {
	return false
}

func (c *config) EnforceRROExemptedForModule(name string) bool {
	return InList(name, c.productVariables.EnforceRROExemptedTargets)
}

func (c *config) EnforceRROExcludedOverlay(path string) bool {
	excluded := c.productVariables.EnforceRROExcludedOverlays
	if len(excluded) > 0 {
+52 −7
Original line number Diff line number Diff line
@@ -34,10 +34,16 @@ type AndroidLibraryDependency interface {
	ExportedStaticPackages() android.Paths
	ExportedManifests() android.Paths
	ExportedAssets() android.OptionalPath
	SetRROEnforcedForDependent(enforce bool)
	IsRROEnforced(ctx android.BaseModuleContext) bool
}

func init() {
	RegisterAARBuildComponents(android.InitRegistrationContext)

	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
		ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator).Parallel()
	})
}

func RegisterAARBuildComponents(ctx android.RegistrationContext) {
@@ -82,6 +88,9 @@ type aaptProperties struct {

	// do not include AndroidManifest from dependent libraries
	Dont_merge_manifests *bool

	// true if RRO is enforced for any of the dependent modules
	RROEnforcedForDependent bool `blueprint:"mutated"`
}

type aapt struct {
@@ -117,6 +126,18 @@ type split struct {
	path   android.Path
}

// Propagate RRO enforcement flag to static lib dependencies transitively.
func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) {
	m := ctx.Module()
	if d, ok := m.(AndroidLibraryDependency); ok && d.IsRROEnforced(ctx) {
		ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
			if a, ok := d.(AndroidLibraryDependency); ok {
				a.SetRROEnforcedForDependent(true)
			}
		})
	}
}

func (a *aapt) ExportPackage() android.Path {
	return a.exportPackage
}
@@ -133,6 +154,17 @@ func (a *aapt) ExportedAssets() android.OptionalPath {
	return a.assetPackage
}

func (a *aapt) SetRROEnforcedForDependent(enforce bool) {
	a.aaptProperties.RROEnforcedForDependent = enforce
}

func (a *aapt) IsRROEnforced(ctx android.BaseModuleContext) bool {
	// True if RRO is enforced for this module or...
	return ctx.Config().EnforceRROForModule(ctx.ModuleName()) ||
		// if RRO is enforced for any of its dependents, and this module is not exempted.
		(a.aaptProperties.RROEnforcedForDependent && !ctx.Config().EnforceRROExemptedForModule(ctx.ModuleName()))
}

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) {
@@ -156,7 +188,7 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext,
			dir:   dir,
			files: androidResourceGlob(ctx, dir),
		})
		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, a, dir)
		overlayDirs = append(overlayDirs, resOverlayDirs...)
		rroDirs = append(rroDirs, resRRODirs...)
	}
@@ -412,6 +444,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
					assets = append(assets, aarDep.ExportedAssets().Path())
				}

				if !ctx.Config().EnforceRROExemptedForModule(ctx.ModuleName()) {
				outer:
					for _, d := range aarDep.ExportedRRODirs() {
						for _, e := range staticRRODirs {
@@ -423,6 +456,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati
					}
				}
			}
		}
	})

	deps = append(deps, sharedLibs...)
@@ -621,6 +655,17 @@ func (a *AARImport) ExportedAssets() android.OptionalPath {
	return android.OptionalPath{}
}

// RRO enforcement is not available on aar_import since its RRO dirs are not
// exported.
func (a *AARImport) SetRROEnforcedForDependent(enforce bool) {
}

// RRO enforcement is not available on aar_import since its RRO dirs are not
// exported.
func (a *AARImport) IsRROEnforced(ctx android.BaseModuleContext) bool {
	return false
}

func (a *AARImport) Prebuilt() *android.Prebuilt {
	return &a.prebuilt
}
+2 −2
Original line number Diff line number Diff line
@@ -66,13 +66,13 @@ type globbedResourceDir struct {
	files android.Paths
}

func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
func overlayResourceGlob(ctx android.ModuleContext, a *aapt, dir android.Path) (res []globbedResourceDir,
	rroDirs []rroDir) {

	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)

	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
	rroEnabled := ctx.Config().EnforceRROForModule(ctx.ModuleName())
	rroEnabled := a.IsRROEnforced(ctx)

	for _, data := range overlayData {
		files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
+113 −4
Original line number Diff line number Diff line
@@ -848,19 +848,17 @@ func TestAndroidResources(t *testing.T) {
				"lib": {
					buildDir + "/.intermediates/lib2/android_common/package-res.apk",
					"lib/res/res/values/strings.xml",
					"device/vendor/blah/overlay/lib/res/values/strings.xml",
				},
			},

			rroDirs: map[string][]string{
				"foo": {
					"device:device/vendor/blah/overlay/foo/res",
					// Enforce RRO on "foo" could imply RRO on static dependencies, but for now it doesn't.
					// "device/vendor/blah/overlay/lib/res",
					"product:product/vendor/blah/overlay/foo/res",
					"device:device/vendor/blah/overlay/lib/res",
				},
				"bar": nil,
				"lib": nil,
				"lib": {"device:device/vendor/blah/overlay/lib/res"},
			},
		},
		{
@@ -3401,3 +3399,114 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) {
		checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag)
	}
}

func TestEnforceRRO_propagatesToDependencies(t *testing.T) {
	testCases := []struct {
		name                    string
		enforceRROTargets       []string
		enforceRROExemptTargets []string
		rroDirs                 map[string][]string
	}{
		{
			name:                    "no RRO",
			enforceRROTargets:       nil,
			enforceRROExemptTargets: nil,
			rroDirs: map[string][]string{
				"foo": nil,
				"bar": nil,
			},
		},
		{
			name:                    "enforce RRO on all",
			enforceRROTargets:       []string{"*"},
			enforceRROExemptTargets: nil,
			rroDirs: map[string][]string{
				"foo": {"product/vendor/blah/overlay/lib2/res"},
				"bar": {"product/vendor/blah/overlay/lib2/res"},
			},
		},
		{
			name:                    "enforce RRO on foo",
			enforceRROTargets:       []string{"foo"},
			enforceRROExemptTargets: nil,
			rroDirs: map[string][]string{
				"foo": {"product/vendor/blah/overlay/lib2/res"},
				"bar": {"product/vendor/blah/overlay/lib2/res"},
			},
		},
		{
			name:                    "enforce RRO on foo, bar exempted",
			enforceRROTargets:       []string{"foo"},
			enforceRROExemptTargets: []string{"bar"},
			rroDirs: map[string][]string{
				"foo": {"product/vendor/blah/overlay/lib2/res"},
				"bar": nil,
			},
		},
	}

	productResourceOverlays := []string{
		"product/vendor/blah/overlay",
	}

	fs := map[string][]byte{
		"lib2/res/values/strings.xml":                             nil,
		"product/vendor/blah/overlay/lib2/res/values/strings.xml": nil,
	}

	bp := `
			android_app {
				name: "foo",
				sdk_version: "current",
				resource_dirs: [],
				static_libs: ["lib"],
			}

			android_app {
				name: "bar",
				sdk_version: "current",
				resource_dirs: [],
				static_libs: ["lib"],
			}

			android_library {
				name: "lib",
				sdk_version: "current",
				resource_dirs: [],
				static_libs: ["lib2"],
			}

			android_library {
				name: "lib2",
				sdk_version: "current",
				resource_dirs: ["lib2/res"],
			}
		`

	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			config := testAppConfig(nil, bp, fs)
			config.TestProductVariables.ProductResourceOverlays = productResourceOverlays
			if testCase.enforceRROTargets != nil {
				config.TestProductVariables.EnforceRROTargets = testCase.enforceRROTargets
			}
			if testCase.enforceRROExemptTargets != nil {
				config.TestProductVariables.EnforceRROExemptedTargets = testCase.enforceRROExemptTargets
			}

			ctx := testContext()
			run(t, ctx, config)

			modules := []string{"foo", "bar"}
			for _, moduleName := range modules {
				module := ctx.ModuleForTests(moduleName, "android_common")
				mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0]
				actualRRODirs := mkEntries.EntryMap["LOCAL_SOONG_PRODUCT_RRO_DIRS"]
				if !reflect.DeepEqual(actualRRODirs, testCase.rroDirs[moduleName]) {
					t.Errorf("exected %s LOCAL_SOONG_PRODUCT_RRO_DIRS entry: %v\ngot:%q",
						moduleName, testCase.rroDirs[moduleName], actualRRODirs)
				}
			}
		})
	}
}
+4 −0
Original line number Diff line number Diff line
@@ -102,6 +102,10 @@ func testContext() *android.TestContext {

	dexpreopt.RegisterToolModulesForTest(ctx)

	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
		ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator).Parallel()
	})

	return ctx
}