Enforce updatable=true on apps of updatable apexes

- Update apex_info (a topdown mutator) so that it sets updatable=true on
  apps of updatable apexes
- Write a unit test that tests different combinations of
  updatable/non-updatable apks-in-apexes
- Update an existing unit test that asserts a different error

Test: go test ./java
Test: m nothing (in internal)
Bug: 209409604

Change-Id: Ie8881b857afcec44addf27fc360c5b8abf726bd2
diff --git a/apex/apex.go b/apex/apex.go
index a7b0a4f..4bcba7e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -994,6 +994,7 @@
 
 // apexInfoMutator delegates the work of identifying which modules need an ApexInfo and apex
 // specific variant to modules that support the ApexInfoMutator.
+// It also propagates updatable=true to apps of updatable apexes
 func apexInfoMutator(mctx android.TopDownMutatorContext) {
 	if !mctx.Module().Enabled() {
 		return
@@ -1001,8 +1002,8 @@
 
 	if a, ok := mctx.Module().(ApexInfoMutator); ok {
 		a.ApexInfoMutator(mctx)
-		return
 	}
+	enforceAppUpdatability(mctx)
 }
 
 // apexStrictUpdatibilityLintMutator propagates strict_updatability_linting to transitive deps of a mainline module
@@ -1033,6 +1034,22 @@
 	}
 }
 
+// enforceAppUpdatability propagates updatable=true to apps of updatable apexes
+func enforceAppUpdatability(mctx android.TopDownMutatorContext) {
+	if !mctx.Module().Enabled() {
+		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
 // Transitive deps of certain mainline modules baseline NewApi errors
 // Skip these mainline modules for now