Merge "Revert "Rename DexJar interface method to DexJarBuildPath.""
diff --git a/apex/apex.go b/apex/apex.go
index d3c5df0..8fd80fc 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1650,7 +1650,8 @@
 }
 
 type javaDependency interface {
-	java.Dependency
+	DexJar() android.Path
+	JacocoReportClassesFile() android.Path
 	Stem() string
 }
 
@@ -1977,23 +1978,16 @@
 					ctx.PropertyErrorf("binaries", "%q is neither cc_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName)
 				}
 			case javaLibTag:
-				if javaLib, ok := child.(*java.Library); ok {
-					af := apexFileForJavaLibrary(ctx, javaLib, javaLib)
-					if !af.Ok() {
-						ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
-					} else {
-						filesInfo = append(filesInfo, af)
-						return true // track transitive dependencies
-					}
-				} else if sdkLib, ok := child.(*java.SdkLibrary); ok {
-					af := apexFileForJavaLibrary(ctx, sdkLib, sdkLib)
+				switch child.(type) {
+				case *java.Library, *java.SdkLibrary, *java.DexImport:
+					af := apexFileForJavaLibrary(ctx, child.(javaDependency), child.(android.Module))
 					if !af.Ok() {
 						ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
 						return false
 					}
 					filesInfo = append(filesInfo, af)
 					return true // track transitive dependencies
-				} else {
+				default:
 					ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
 				}
 			case androidAppTag:
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 779119c..e45cd00 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -329,7 +329,10 @@
 					binaries: ["foo",],
 				}
 			},
-			java_libs: ["myjar"],
+			java_libs: [
+				"myjar",
+				"myjar_dex",
+			],
 		}
 
 		apex {
@@ -438,6 +441,15 @@
 			],
 		}
 
+		dex_import {
+			name: "myjar_dex",
+			jars: ["prebuilt.jar"],
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
+
 		java_library {
 			name: "myotherjar",
 			srcs: ["foo/bar/MyClass.java"],
@@ -473,6 +485,7 @@
 	// Ensure that apex variant is created for the direct dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
 	ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex")
+	ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_myapex")
 
 	// Ensure that apex variant is created for the indirect dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
@@ -482,6 +495,7 @@
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib2.so")
 	ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar")
+	ensureContains(t, copyCmds, "image.apex/javalib/myjar_dex.jar")
 	// .. but not for java libs
 	ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
 	ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 98850e5..0148161 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -50,6 +50,8 @@
 	UpdatableSystemServerJars []string // jars within apex that are loaded into system server
 	SpeedApps                 []string // apps that should be speed optimized
 
+	BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error
+
 	PreoptFlags []string // global dex2oat flags that should be used if no module-specific dex2oat flags are specified
 
 	DefaultCompilerFilter      string // default compiler filter to pass to dex2oat, overridden by --compiler-filter= in module-specific dex2oat flags
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 5275e8f..8e65ca6 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -314,6 +314,8 @@
 		dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
 		rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
 		rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost)
+
+		checkSystemServerOrder(ctx, jarIndex)
 	} else {
 		// Pass special class loader context to skip the classpath and collision check.
 		// This will get removed once LOCAL_USES_LIBRARIES is enforced.
@@ -607,6 +609,29 @@
 	}
 }
 
+// Check the order of jars on the system server classpath and give a warning/error if a jar precedes
+// one of its dependencies. This is not an error, but a missed optimization, as dexpreopt won't
+// have the dependency jar in the class loader context, and it won't be able to resolve any
+// references to its classes and methods.
+func checkSystemServerOrder(ctx android.PathContext, jarIndex int) {
+	mctx, isModule := ctx.(android.ModuleContext)
+	if isModule {
+		config := GetGlobalConfig(ctx)
+		jars := NonUpdatableSystemServerJars(ctx, config)
+		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+			depIndex := android.IndexList(dep.Name(), jars)
+			if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {
+				jar := jars[jarIndex]
+				dep := jars[depIndex]
+				mctx.ModuleErrorf("non-optimal order of jars on the system server classpath:"+
+					" '%s' precedes its dependency '%s', so dexpreopt is unable to resolve any"+
+					" references from '%s' to '%s'.\n", jar, dep, jar, dep)
+			}
+			return true
+		})
+	}
+}
+
 func contains(l []string, s string) bool {
 	for _, e := range l {
 		if e == s {
diff --git a/java/androidmk.go b/java/androidmk.go
index 6eb22fd..62cf169 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -69,7 +69,26 @@
 	if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
 		hideFromMake = true
 	}
-	if !hideFromMake {
+	if hideFromMake {
+		// May still need to add some additional dependencies. This will be called
+		// once for the platform variant (even if it is not being used) and once each
+		// for the APEX specific variants. In order to avoid adding the dependency
+		// multiple times only add it for the platform variant.
+		checkedModulePaths := library.additionalCheckedModules
+		if library.IsForPlatform() && len(checkedModulePaths) != 0 {
+			mainEntries = android.AndroidMkEntries{
+				Class: "FAKE",
+				// Need at least one output file in order for this to take effect.
+				OutputFile: android.OptionalPathForPath(checkedModulePaths[0]),
+				Include:    "$(BUILD_PHONY_PACKAGE)",
+				ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+					func(entries *android.AndroidMkEntries) {
+						entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", checkedModulePaths.Strings()...)
+					},
+				},
+			}
+		}
+	} else {
 		mainEntries = android.AndroidMkEntries{
 			Class:      "JAVA_LIBRARIES",
 			DistFile:   android.OptionalPathForPath(library.distFile),
@@ -104,6 +123,10 @@
 
 					entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...)
 
+					if len(library.additionalCheckedModules) != 0 {
+						entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
+					}
+
 					if library.proguardDictionary != nil {
 						entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary)
 					}
diff --git a/java/builder.go b/java/builder.go
index 640dba9..a27e5c3 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -206,7 +206,7 @@
 		blueprint.RuleParams{
 			Command: "rm -f $out && " +
 				"${config.PackageCheckCmd} $in $packages && " +
-				"cp $in $out",
+				"touch $out",
 			CommandDeps: []string{"${config.PackageCheckCmd}"},
 		},
 		"packages")
@@ -547,9 +547,8 @@
 	})
 }
 
-func CheckJarPackages(ctx android.ModuleContext, classesJar android.Path, permittedPackages []string) android.ModuleOutPath {
-	outputFile := android.PathForModuleOut(ctx, "package-check", classesJar.Base())
-
+func CheckJarPackages(ctx android.ModuleContext, outputFile android.WritablePath,
+	classesJar android.Path, permittedPackages []string) {
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        packageCheck,
 		Description: "packageCheck",
@@ -559,8 +558,6 @@
 			"packages": strings.Join(permittedPackages, " "),
 		},
 	})
-
-	return outputFile
 }
 
 func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePath,
diff --git a/java/java.go b/java/java.go
index 09df2ad..eaf0fe9 100644
--- a/java/java.go
+++ b/java/java.go
@@ -463,6 +463,9 @@
 	// expanded Jarjar_rules
 	expandJarjarRules android.Path
 
+	// list of additional targets for checkbuild
+	additionalCheckedModules android.Paths
+
 	// Extra files generated by the module type to be added as java resources.
 	extraResources android.Paths
 
@@ -1518,10 +1521,10 @@
 
 	// Check package restrictions if necessary.
 	if len(j.properties.Permitted_packages) > 0 {
-		// Check packages and copy input to package-checked file.
-		// Use the file copied after a successful package check as the output file for this
-		// module so that any dependencies on this module will trigger the package check.
-		outputFile = CheckJarPackages(ctx, outputFile, j.properties.Permitted_packages)
+		// Check packages and copy to package-checked file.
+		pkgckFile := android.PathForModuleOut(ctx, "package-check.stamp")
+		CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages)
+		j.additionalCheckedModules = append(j.additionalCheckedModules, pkgckFile)
 
 		if ctx.Failed() {
 			return
@@ -2688,6 +2691,10 @@
 	return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
 }
 
+func (a *DexImport) JacocoReportClassesFile() android.Path {
+	return nil
+}
+
 func (j *DexImport) IsInstallable() bool {
 	return true
 }