Merge "Use module name as the suffix for apex variant"
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 3e55958..f54e774 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -54,7 +54,7 @@
 // For example, an Android.bp file could have:
 //
 //     soong_config_module_type_import {
-//         from: "device/acme/Android.bp.bp",
+//         from: "device/acme/Android.bp",
 //         module_types: ["acme_cc_defaults"],
 //     }
 //
@@ -139,9 +139,9 @@
 }
 
 // soong_config_module_type defines module types with conditionals on Soong config
-// variables from another Android.bp file.  The new module type will exist for all
-// modules after the definition in an Android.bp file, and can be imported into other
-// Android.bp files using soong_config_module_type_import.
+// variables.  The new module type will exist for all modules after the definition
+// in an Android.bp file, and can be imported into other Android.bp files using
+// soong_config_module_type_import.
 //
 // For example, an Android.bp file could have:
 //
@@ -186,8 +186,6 @@
 //         srcs: ["*.cpp"],
 //     }
 //
-// And device/acme/Android.bp could have:
-//
 // If an acme BoardConfig.mk file contained:
 //
 //     SOONG_CONFIG_NAMESPACES += acme
diff --git a/android/util.go b/android/util.go
index 81f481d..e985fc1 100644
--- a/android/util.go
+++ b/android/util.go
@@ -121,8 +121,19 @@
 	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
 		}
diff --git a/apex/apex.go b/apex/apex.go
index 48cdedf..53bdc12 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1194,6 +1194,12 @@
 	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
 }
 
+func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.PlatformCompatConfigIntf, depName string) apexFile {
+	dirInApex := filepath.Join("etc", config.SubDir())
+	fileToCopy := config.CompatConfig()
+	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, config)
+}
+
 func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp interface {
 	android.Module
 	Privileged() bool
@@ -1361,8 +1367,10 @@
 			case prebuiltTag:
 				if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
 					filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+				} else if prebuilt, ok := child.(java.PlatformCompatConfigIntf); ok {
+					filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, prebuilt, depName))
 				} else {
-					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
+					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc and not a platform_compat_config module", depName)
 				}
 			case testTag:
 				if ccTest, ok := child.(*cc.Module); ok {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 515cb45..faf7ae5 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -299,6 +299,7 @@
 	ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
 	ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory)
 	ctx.RegisterModuleType("prebuilt_etc", android.PrebuiltEtcFactory)
+	ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
 	ctx.RegisterModuleType("sh_binary", android.ShBinaryFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	java.RegisterJavaBuildComponents(ctx)
@@ -3473,6 +3474,41 @@
 	ensureContains(t, xml.Args["content"], `<library name="foo" file="/apex/myapex/javalib/foo.jar"`)
 }
 
+func TestCompatConfig(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			prebuilts: ["myjar-platform-compat-config"],
+			java_libs: ["myjar"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		platform_compat_config {
+		    name: "myjar-platform-compat-config",
+		    src: ":myjar",
+		}
+
+		java_library {
+			name: "myjar",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			compile_dex: true,
+			apex_available: [ "myapex" ],
+		}
+	`)
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+		"etc/compatconfig/myjar-platform-compat-config.xml",
+		"javalib/myjar.jar",
+	})
+}
+
 func TestRejectNonInstallableJavaLibrary(t *testing.T) {
 	testApexError(t, `"myjar" is not configured to be compiled into dex`, `
 		apex {
diff --git a/java/aapt2.go b/java/aapt2.go
index cfe0dea..04e4de5 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -147,10 +147,16 @@
 		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 @@
 	}
 
 	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, " "),
diff --git a/java/aar.go b/java/aar.go
index d707e36..24c5e7d 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -32,6 +32,7 @@
 	ExportedRRODirs() []rroDir
 	ExportedStaticPackages() android.Paths
 	ExportedManifests() android.Paths
+	ExportedAssets() android.OptionalPath
 }
 
 func init() {
@@ -93,6 +94,7 @@
 	extraAaptPackagesFile   android.Path
 	mergedManifestFile      android.Path
 	noticeFile              android.OptionalPath
+	assetPackage            android.OptionalPath
 	isLibrary               bool
 	useEmbeddedNativeLibs   bool
 	useEmbeddedDex          bool
@@ -124,6 +126,10 @@
 	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) {
@@ -219,9 +225,15 @@
 	}
 }
 
+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
@@ -321,7 +333,20 @@
 	}
 
 	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
@@ -335,7 +360,7 @@
 
 // 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
 
@@ -373,6 +398,9 @@
 				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() {
@@ -402,7 +430,7 @@
 	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 {
@@ -572,6 +600,11 @@
 	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
 }
@@ -660,7 +693,7 @@
 	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
@@ -673,7 +706,7 @@
 	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)
diff --git a/java/app_test.go b/java/app_test.go
index c20a8e7..c86b038 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -323,6 +323,107 @@
 	}
 }
 
+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
diff --git a/java/java.go b/java/java.go
index ed3dca9..a4e91ab 100644
--- a/java/java.go
+++ b/java/java.go
@@ -757,9 +757,12 @@
 type linkType int
 
 const (
+	// TODO(jiyong) rename these for better readability. Make the allowed
+	// and disallowed link types explicit
 	javaCore linkType = iota
 	javaSdk
 	javaSystem
+	javaModule
 	javaPlatform
 )
 
@@ -789,6 +792,10 @@
 		return javaSdk, true
 	case ver.kind == sdkPublic:
 		return javaSdk, false
+	case name == "android_module_lib_stubs_current":
+		return javaModule, true
+	case ver.kind == sdkModule:
+		return javaModule, false
 	case ver.kind == sdkPrivate || ver.kind == sdkNone || ver.kind == sdkCorePlatform:
 		return javaPlatform, false
 	case !ver.valid():
@@ -824,11 +831,17 @@
 		}
 		break
 	case javaSystem:
-		if otherLinkType == javaPlatform {
+		if otherLinkType == javaPlatform || otherLinkType == javaModule {
 			ctx.ModuleErrorf("compiles against system API, but dependency %q is compiling against private API."+commonMessage,
 				ctx.OtherModuleName(to))
 		}
 		break
+	case javaModule:
+		if otherLinkType == javaPlatform {
+			ctx.ModuleErrorf("compiles against module API, but dependency %q is compiling against private API."+commonMessage,
+				ctx.OtherModuleName(to))
+		}
+		break
 	case javaPlatform:
 		// no restriction on link-type
 		break
diff --git a/java/java_test.go b/java/java_test.go
index 0e987a6..8815c09 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1099,6 +1099,12 @@
 			libs: ["foo"],
 			sdk_version: "test_current",
 		}
+		java_library {
+			name: "baz-29",
+			srcs: ["c.java"],
+			libs: ["foo"],
+			sdk_version: "system_29",
+		}
 		`)
 
 	// check the existence of the internal modules
@@ -1138,6 +1144,13 @@
 			"foo.stubs.test.jar")
 	}
 
+	baz29Javac := ctx.ModuleForTests("baz-29", "android_common").Rule("javac")
+	// tests if baz-29 is actually linked to the system 29 stubs lib
+	if !strings.Contains(baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") {
+		t.Errorf("baz-29 javac classpath %v does not contain %q", baz29Javac.Args["classpath"],
+			"prebuilts/sdk/29/system/foo.jar")
+	}
+
 	// test if baz has exported SDK lib names foo and bar to qux
 	qux := ctx.ModuleForTests("qux", "android_common")
 	if quxLib, ok := qux.Module().(*Library); ok {
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 95c0574..cb8e684 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -21,7 +21,7 @@
 
 func init() {
 	android.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
-	android.RegisterModuleType("platform_compat_config", platformCompatConfigFactory)
+	android.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory)
 	android.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
 }
 
@@ -50,11 +50,24 @@
 	return p.metadataFile
 }
 
-type platformCompatConfigIntf interface {
-	compatConfigMetadata() android.OutputPath
+func (p *platformCompatConfig) CompatConfig() android.OutputPath {
+	return p.configFile
 }
 
-var _ platformCompatConfigIntf = (*platformCompatConfig)(nil)
+func (p *platformCompatConfig) SubDir() string {
+	return "compatconfig"
+}
+
+type PlatformCompatConfigIntf interface {
+	android.Module
+
+	compatConfigMetadata() android.OutputPath
+	CompatConfig() android.OutputPath
+	// Sub dir under etc dir.
+	SubDir() string
+}
+
+var _ PlatformCompatConfigIntf = (*platformCompatConfig)(nil)
 
 // compat singleton rules
 func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -62,7 +75,7 @@
 	var compatConfigMetadata android.Paths
 
 	ctx.VisitAllModules(func(module android.Module) {
-		if c, ok := module.(platformCompatConfigIntf); ok {
+		if c, ok := module.(PlatformCompatConfigIntf); ok {
 			metadata := c.compatConfigMetadata()
 			compatConfigMetadata = append(compatConfigMetadata, metadata)
 		}
@@ -130,7 +143,7 @@
 	return &platformCompatConfigSingleton{}
 }
 
-func platformCompatConfigFactory() android.Module {
+func PlatformCompatConfigFactory() android.Module {
 	module := &platformCompatConfig{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
diff --git a/java/sdk.go b/java/sdk.go
index f388358..1c047a3 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -71,6 +71,7 @@
 	sdkPublic
 	sdkSystem
 	sdkTest
+	sdkModule
 	sdkPrivate
 )
 
@@ -91,6 +92,8 @@
 		return "core"
 	case sdkCorePlatform:
 		return "core_platform"
+	case sdkModule:
+		return "module"
 	default:
 		return "invalid"
 	}
@@ -256,6 +259,8 @@
 			kind = sdkSystem
 		case "test":
 			kind = sdkTest
+		case "module":
+			kind = sdkModule
 		default:
 			return sdkSpec{sdkInvalid, sdkVersionNone, str}
 		}
@@ -382,6 +387,9 @@
 		return toModule("android_test_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
 	case sdkCore:
 		return toModule("core.current.stubs", "", nil)
+	case sdkModule:
+		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
+		return toModule("android_module_lib_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
 	default:
 		panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw))
 	}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index cd22e6e..fb8ae95 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -683,8 +683,9 @@
 	sdkVersion sdkSpec,
 	headerJars bool) android.Paths {
 
-	// This module is just a wrapper for the stubs.
-	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+	// If a specific numeric version has been requested or the build is explicitly configured
+	// for it then use prebuilt versions of the sdk.
+	if sdkVersion.version.isNumbered() || ctx.Config().UnbundledBuildUsePrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
 	} else {
 		if !sdkVersion.specified() {
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 9cabd77..c815fe3 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -211,6 +211,15 @@
 			java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
 			aidl:           "-pprebuilts/sdk/29/public/framework.aidl",
 		},
+		{
+
+			name:           "module_current",
+			properties:     `sdk_version: "module_current",`,
+			bootclasspath:  []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
+			system:         "core-current-stubs-system-modules",
+			java9classpath: []string{"android_module_lib_stubs_current"},
+			aidl:           "-p" + buildDir + "/framework.aidl",
+		},
 	}
 
 	for _, testcase := range classpathTestcases {
diff --git a/java/testing.go b/java/testing.go
index e746e2d..8f979c7 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -49,6 +49,8 @@
 		"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,
 
@@ -61,6 +63,7 @@
 		"prebuilts/sdk/29/public/android.jar":         nil,
 		"prebuilts/sdk/29/public/framework.aidl":      nil,
 		"prebuilts/sdk/29/system/android.jar":         nil,
+		"prebuilts/sdk/29/system/foo.jar":             nil,
 		"prebuilts/sdk/current/core/android.jar":      nil,
 		"prebuilts/sdk/current/public/android.jar":    nil,
 		"prebuilts/sdk/current/public/framework.aidl": nil,
@@ -143,6 +146,7 @@
 		"android_stubs_current",
 		"android_system_stubs_current",
 		"android_test_stubs_current",
+		"android_module_lib_stubs_current",
 		"core.current.stubs",
 		"core.platform.api.stubs",
 		"kotlin-stdlib",