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

Commit 99939e9c authored by Colin Cross's avatar Colin Cross
Browse files

Enforce app updatability in GenerateAndroidBuildActions

Remove part of the apex top down mutator by moving enforceAppUpdatability
to a check in GenerateAndroidBuildActions instead of mutating
dependencies.  This requires annotating app dependencies of updatable
apexes with `updatable: true` in the Android.bp files.

Bug: 367784740
Test: builds
Flag: EXEMPT refactor
Change-Id: I234a457bba48c0f48410d53740aaa9b89661ca7c
parent 12c41d83
Loading
Loading
Loading
Loading
+19 −17
Original line number Diff line number Diff line
@@ -1110,23 +1110,6 @@ func apexInfoMutator(mctx android.TopDownMutatorContext) {
	if am, ok := mctx.Module().(android.ApexModule); ok {
		android.ApexInfoMutator(mctx, am)
	}
	enforceAppUpdatability(mctx)
}

// enforceAppUpdatability propagates updatable=true to apps of updatable apexes
func enforceAppUpdatability(mctx android.TopDownMutatorContext) {
	if !mctx.Module().Enabled(mctx) {
		return
	}
	if apex, ok := mctx.Module().(*apexBundle); ok && apex.Updatable() {
		// checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults
		mctx.VisitDirectDeps(func(module android.Module) {
			// ignore android_test_app
			if app, ok := module.(*java.AndroidApp); ok {
				app.SetUpdatable(true)
			}
		})
	}
}

// TODO: b/215736885 Whittle the denylist
@@ -1872,6 +1855,7 @@ func (a *apexBundle) commonBuildActions(ctx android.ModuleContext) bool {
	a.CheckMinSdkVersion(ctx)
	a.checkStaticLinkingToStubLibraries(ctx)
	a.checkStaticExecutables(ctx)
	a.enforceAppUpdatability(ctx)
	if len(a.properties.Tests) > 0 && !a.testApex {
		ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
		return false
@@ -2397,6 +2381,24 @@ func (a *apexBundle) setOutputFiles(ctx android.ModuleContext) {
	}
}

// enforceAppUpdatability propagates updatable=true to apps of updatable apexes
func (a *apexBundle) enforceAppUpdatability(mctx android.ModuleContext) {
	if !a.Enabled(mctx) {
		return
	}
	if a.Updatable() {
		// checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults
		mctx.VisitDirectDeps(func(module android.Module) {
			if appInfo, ok := android.OtherModuleProvider(mctx, module, java.AppInfoProvider); ok {
				// ignore android_test_app
				if !appInfo.TestHelperApp && !appInfo.Updatable {
					mctx.ModuleErrorf("app dependency %s must have updatable: true", mctx.OtherModuleName(module))
				}
			}
		})
	}
}

// apexBootclasspathFragmentFiles returns the list of apexFile structures defining the files that
// the bootclasspath_fragment contributes to the apex.
func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint.Module) []apexFile {
+7 −39
Original line number Diff line number Diff line
@@ -9876,7 +9876,7 @@ func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) {
		apex {
			name: "myapex",
			key: "myapex.key",
			updatable: %v,
			updatable: true,
			apps: [
				"myapp",
			],
@@ -9887,7 +9887,6 @@ func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) {
		}
		android_app {
			name: "myapp",
			updatable: %v,
			apex_available: [
				"myapex",
			],
@@ -9895,42 +9894,10 @@ func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) {
			min_sdk_version: "30",
		}
		`
	testCases := []struct {
		name                      string
		apex_is_updatable_bp      bool
		app_is_updatable_bp       bool
		app_is_updatable_expected bool
	}{
		{
			name:                      "Non-updatable apex respects updatable property of non-updatable app",
			apex_is_updatable_bp:      false,
			app_is_updatable_bp:       false,
			app_is_updatable_expected: false,
		},
		{
			name:                      "Non-updatable apex respects updatable property of updatable app",
			apex_is_updatable_bp:      false,
			app_is_updatable_bp:       true,
			app_is_updatable_expected: true,
		},
		{
			name:                      "Updatable apex respects updatable property of updatable app",
			apex_is_updatable_bp:      true,
			app_is_updatable_bp:       true,
			app_is_updatable_expected: true,
		},
		{
			name:                      "Updatable apex sets updatable=true on non-updatable app",
			apex_is_updatable_bp:      true,
			app_is_updatable_bp:       false,
			app_is_updatable_expected: true,
		},
	}
	for _, testCase := range testCases {
		result := testApex(t, fmt.Sprintf(bp, testCase.apex_is_updatable_bp, testCase.app_is_updatable_bp))
		myapp := result.ModuleForTests("myapp", "android_common").Module().(*java.AndroidApp)
		android.AssertBoolEquals(t, testCase.name, testCase.app_is_updatable_expected, myapp.Updatable())
	}
	_ = android.GroupFixturePreparers(
		prepareForApexTest,
	).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("app dependency myapp must have updatable: true")).
		RunTestWithBp(t, bp)
}

func TestTrimmedApex(t *testing.T) {
@@ -11699,6 +11666,7 @@ func TestSdkLibraryTransitiveClassLoaderContext(t *testing.T) {
			sdk_version: "core_current",
			min_sdk_version: "30",
			manifest: "AndroidManifest.xml",
			updatable: true,
		}
       `)
}
+18 −5
Original line number Diff line number Diff line
@@ -63,6 +63,16 @@ func RegisterAppBuildComponents(ctx android.RegistrationContext) {
	ctx.RegisterModuleType("override_android_test", OverrideAndroidTestModuleFactory)
}

type AppInfo struct {
	// Updatable is set to the value of the updatable property
	Updatable bool

	// TestHelperApp is true if the module is a android_test_helper_app
	TestHelperApp bool
}

var AppInfoProvider = blueprint.NewProvider[*AppInfo]()

// AndroidManifest.xml merging
// package splits

@@ -385,7 +395,10 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon
	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
		TestOnly: true,
	})

	android.SetProvider(ctx, AppInfoProvider, &AppInfo{
		Updatable:     Bool(a.appProperties.Updatable),
		TestHelperApp: true,
	})
}

func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -393,6 +406,10 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
	a.checkEmbedJnis(ctx)
	a.generateAndroidBuildActions(ctx)
	a.generateJavaUsedByApex(ctx)
	android.SetProvider(ctx, AppInfoProvider, &AppInfo{
		Updatable:     Bool(a.appProperties.Updatable),
		TestHelperApp: false,
	})
}

func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
@@ -1206,10 +1223,6 @@ func (a *AndroidApp) Updatable() bool {
	return Bool(a.appProperties.Updatable)
}

func (a *AndroidApp) SetUpdatable(val bool) {
	a.appProperties.Updatable = &val
}

func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string {
	certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
	if overridden {