Error on suboptimal system server classpath order, unless explicitly allowed.

The order is non-optimal if some jar X precedes its dependency Y. In
that case dexpreopt will be unable to resolve any rerefences from X to
Y. Raise an error unless the product sets variable
PRODUCT_BROKEN_SUBOPTIMAL_ORDER_OF_SYSTEM_SERVER_JARS to true in the
makefile. This is to prevent regressions in existing products that
currently have correct order.

Test: lunch cf_x86_phone-userdebug && m nothing
Test: lunch aosp_car_arm && m nothing

Bug: 140451054

Change-Id: Iafe8fe0e992deb628e38f2321d4601a4804a3c79
Merged-In: Iafe8fe0e992deb628e38f2321d4601a4804a3c79
(cherry picked from commit fb863c87c4240c09be45043d168c165760ecf90a)
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index de696da..b6e6b9a 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -307,6 +307,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.
@@ -606,6 +608,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 {