Simplify the construction of class loader contexts for system server jars.

This reworks CL https://r.android.com/1180134 as follows:

1) Do not reorder the list of system server jars passed from Make to
  Soong via the product variable PRODUCT_SYSTEM_SERVER_JARS. This means
  that for some products the order of jars on the system server
  classpath may be non-optimal: a jar X that depends on Y may be
  dexpreopted before Y, so that all references to the classes and
  methods from Y wil be unresolved.

  Unfortunately for such products, fixing the order is not a simple
  matter of rearranging their PRODUCT_SYSTEM_SERVER_JARS, because the
  conflicts may arise when the product-specific variable gets merged
  with the common variable.

2) As a consequence of 1), do not add artificial dependencies between
  system server jars: this is now impossible, as it would create
  circular dependencies for those products that have non-optimal order
  of jars.

3) Copy dex files for system server jars to a predefined build location.
  This is necessary because at the time when Soong generates class
  loader context for k-th jar, it needs to know the paths to jars 1 ..
  (k-1), and it might have not processed those jars yet (so Soong can't
  query the paths from the modules).

  This approach is similar to the way Soong handles bootclasspath jars.

4) Do not exclude from dexpreopting system server jars that are not
  Soong modules (those that are Make modules). The previous CL excluded
  them because Make modules do not have ModuleContext. But it turns out
  that ModuleContext is not necessary, as all the information is passed
  via the dexpreopt config.

Test: aosp_walleye-userdebug boots and there are no messages in the
  logcat regarding class loader context mismatch:

  $ adb logcat | grep 'mismatch'
  # empty

Test: Class loader contexts in the oat files for system server jars
  match expectations:

  $ oatdump --oat-file=out/target/product/walleye/system/framework/oat/arm64/com.android.location.provider.odex 2>/dev/null | grep '^classpath'
  classpath = PCL[]
  $ oatdump --oat-file=out/target/product/walleye/system/framework/oat/arm64/services.odex 2>/dev/null | grep '^classpath'
  classpath = PCL[/system/framework/com.android.location.provider.jar*1989208671]
  $ oatdump --oat-file=out/target/product/walleye/system/framework/oat/arm64/ethernet-service.odex 2>/dev/null | grep '^classpath'
  classpath = PCL[/system/framework/com.android.location.provider.jar*1989208671:/system/framework/services.jar*4040443083:/system/framework/services.jar!classes2.dex*2210087472]

Test: The phone boots and logcat has no scary messages related to
  class loader contexts:

  $ lunch aosp_walleye-userdebug && m
  $ adb reboot bootloader && fastboot flashall -w && adb wait-for-device
  $ adb root
  $ adb shell stop
  $ adb logcat -c
  $ adb shell setprop dalvik.vm.extra-opts -verbose:oat
  $ adb shell start
  $ adb logcat | egrep -io 'system_server: .*load.*/system/framework.*'
  system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 0
  system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 0
  system_server: Loading /system/framework/oat/arm64/services.odex with executable: 0
  system_server: Successfully loaded /system/framework/oat/arm64/services.odex with executable: 0
  system_server: Loading /system/framework/oat/arm64/ethernet-service.odex with executable: 0
  system_server: Successfully loaded /system/framework/oat/arm64/ethernet-service.odex with executable: 0
  system_server: Loading /system/framework/oat/arm64/wifi-service.odex with executable: 0
  system_server: Successfully loaded /system/framework/oat/arm64/wifi-service.odex with executable: 0
  system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1
  system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1
  system_server: Loading /system/framework/oat/arm64/services.odex with executable: 1
  system_server: Successfully loaded /system/framework/oat/arm64/services.odex with executable: 1
  system_server: Loading /system/framework/oat/arm64/ethernet-service.odex with executable: 1
  system_server: Successfully loaded /system/framework/oat/arm64/ethernet-service.odex with executable: 1
  system_server: Loading /system/framework/oat/arm64/wifi-service.odex with executable: 1
  system_server: Successfully loaded /system/framework/oat/arm64/wifi-service.odex with executable: 1
  system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1
  system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1

Bug: 141785760
Bug: 140451054
Bug: 148944771
Bug: 147017252

Change-Id: I33c4087f8bfacd0ecb89877aa150b75360d06710
Merged-In: I33c4087f8bfacd0ecb89877aa150b75360d06710
(cherry picked from commit a4a83b0ef9b9769681ad285290fdbbf043eff3d5)

Exempt-From-Owner-Approval: cherry-pick.
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 6cb9873..7dd01e2 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -41,21 +41,12 @@
 
 	"android/soong/android"
 
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 )
 
 const SystemPartition = "/system/"
 const SystemOtherPartition = "/system_other/"
 
-type dependencyTag struct {
-	blueprint.BaseDependencyTag
-	name string
-}
-
-var SystemServerDepTag = dependencyTag{name: "system-server-dep"}
-var SystemServerForcedDepTag = dependencyTag{name: "system-server-forced-dep"}
-
 // GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
 // ModuleConfig.  The produced files and their install locations will be available through rule.Installs().
 func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConfig,
@@ -116,13 +107,6 @@
 		}
 	}
 
-	// Don't preopt system server jars that are not Soong modules.
-	if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) {
-		if _, ok := ctx.(android.ModuleContext); !ok {
-			return true
-		}
-	}
-
 	// If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip
 	// Also preopt system server jars since selinux prevents system server from loading anything from
 	// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
@@ -239,6 +223,8 @@
 
 	invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
 
+	systemServerJars := NonUpdatableSystemServerJars(ctx, global)
+
 	// The class loader context using paths in the build
 	var classLoaderContextHost android.Paths
 
@@ -253,8 +239,8 @@
 	var conditionalClassLoaderContextHost29 android.Paths
 	var conditionalClassLoaderContextTarget29 []string
 
-	var classLoaderContextHostString, classLoaderContextDeviceString string
-	var classLoaderDeps android.Paths
+	// A flag indicating if the '&' class loader context is used.
+	unknownClassLoaderContext := false
 
 	if module.EnforceUsesLibraries {
 		usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
@@ -298,49 +284,38 @@
 			pathForLibrary(module, hidlBase))
 		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
 			filepath.Join("/system/framework", hidlBase+".jar"))
-
-		classLoaderContextHostString = strings.Join(classLoaderContextHost.Strings(), ":")
-	} else if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) {
-		// We expect that all dexpreopted system server jars are Soong modules.
-		mctx, isModule := ctx.(android.ModuleContext)
-		if !isModule {
-			panic("Cannot dexpreopt system server jar that is not a soong module.")
+	} else if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
+		// System server jars should be dexpreopted together: class loader context of each jar
+		// should include all preceding jars on the system server classpath.
+		for _, otherJar := range systemServerJars[:jarIndex] {
+			classLoaderContextHost = append(classLoaderContextHost, SystemServerDexJarHostPath(ctx, otherJar))
+			classLoaderContextTarget = append(classLoaderContextTarget, "/system/framework/"+otherJar+".jar")
 		}
 
-		// System server jars should be dexpreopted together: class loader context of each jar
-		// should include preceding jars (which can be found as dependencies of the current jar
-		// with a special tag).
-		var jarsOnHost android.Paths
-		var jarsOnDevice []string
-		mctx.VisitDirectDepsWithTag(SystemServerDepTag, func(dep android.Module) {
-			depName := mctx.OtherModuleName(dep)
-			if jar, ok := dep.(interface{ DexJar() android.Path }); ok {
-				jarsOnHost = append(jarsOnHost, jar.DexJar())
-				jarsOnDevice = append(jarsOnDevice, "/system/framework/"+depName+".jar")
-			} else {
-				mctx.ModuleErrorf("module \"%s\" is not a jar", depName)
-			}
-		})
-		classLoaderContextHostString = strings.Join(jarsOnHost.Strings(), ":")
-		classLoaderContextDeviceString = strings.Join(jarsOnDevice, ":")
-		classLoaderDeps = jarsOnHost
+		// Copy the system server jar to a predefined location where dex2oat will find it.
+		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)
 	} else {
 		// Pass special class loader context to skip the classpath and collision check.
 		// This will get removed once LOCAL_USES_LIBRARIES is enforced.
 		// Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
 		// to the &.
-		classLoaderContextHostString = `\&`
+		unknownClassLoaderContext = true
 	}
 
 	rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
 	rule.Command().FlagWithOutput("rm -f ", odexPath)
 	// Set values in the environment of the rule.  These may be modified by construct_context.sh.
-	if classLoaderContextHostString == `\&` {
-		rule.Command().Text(`class_loader_context_arg=--class-loader-context=\&`)
-		rule.Command().Text(`stored_class_loader_context_arg=""`)
+	if unknownClassLoaderContext {
+		rule.Command().
+			Text(`class_loader_context_arg=--class-loader-context=\&`).
+			Text(`stored_class_loader_context_arg=""`)
 	} else {
-		rule.Command().Text("class_loader_context_arg=--class-loader-context=PCL[" + classLoaderContextHostString + "]")
-		rule.Command().Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + classLoaderContextDeviceString + "]")
+		rule.Command().
+			Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(classLoaderContextHost.Strings(), ":") + "]").
+			Implicits(classLoaderContextHost).
+			Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(classLoaderContextTarget, ":") + "]")
 	}
 
 	if module.EnforceUsesLibraries {
@@ -395,7 +370,7 @@
 		Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", module.PreoptBootClassPathDexFiles, ":").
 		Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":").
 		Flag("${class_loader_context_arg}").
-		Flag("${stored_class_loader_context_arg}").Implicits(classLoaderDeps).
+		Flag("${stored_class_loader_context_arg}").
 		FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()).
 		FlagWithInput("--dex-file=", module.DexPath).
 		FlagWithArg("--dex-location=", dexLocationArg).
@@ -609,6 +584,14 @@
 	}).([]string)
 }
 
+// A predefined location for the system server dex jars. This is needed in order to generate
+// class loader context for dex2oat, as the path to the jar in the Soong module may be unknown
+// at that time (Soong processes the jars in dependency order, which may be different from the
+// the system server classpath order).
+func SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.OutputPath {
+	return android.PathForOutput(ctx, ctx.Config().DeviceName(), "system_server_dexjars", jar+".jar")
+}
+
 func contains(l []string, s string) bool {
 	for _, e := range l {
 		if e == s {
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index d77d3e1..ffce2a9 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -30,9 +30,9 @@
 	return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
 		global := dexpreopt.GetGlobalConfig(ctx)
 		var systemServerClasspathLocations []string
-		var dexpreoptJars = *DexpreoptedSystemServerJars(ctx.Config())
-		// 1) The jars that are dexpreopted.
-		for _, m := range dexpreoptJars {
+		nonUpdatable := dexpreopt.NonUpdatableSystemServerJars(ctx, global)
+		// 1) Non-updatable jars.
+		for _, m := range nonUpdatable {
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				filepath.Join("/system/framework", m+".jar"))
 		}
@@ -41,13 +41,6 @@
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				dexpreopt.GetJarLocationFromApexJarPair(m))
 		}
-		// 3) The jars from make (which are not updatable, not preopted).
-		for _, m := range dexpreopt.NonUpdatableSystemServerJars(ctx, global) {
-			if !android.InList(m, dexpreoptJars) {
-				systemServerClasspathLocations = append(systemServerClasspathLocations,
-					filepath.Join("/system/framework", m+".jar"))
-			}
-		}
 		if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
 			panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
 				len(systemServerClasspathLocations),
diff --git a/java/java.go b/java/java.go
index 8c779f5..3793821 100644
--- a/java/java.go
+++ b/java/java.go
@@ -23,14 +23,12 @@
 	"path/filepath"
 	"strconv"
 	"strings"
-	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/dexpreopt"
 	"android/soong/java/config"
 	"android/soong/tradefed"
 )
@@ -60,8 +58,6 @@
 			PropertyName: "java_tests",
 		},
 	})
-
-	android.PostDepsMutators(RegisterPostDepsMutators)
 }
 
 func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
@@ -90,44 +86,6 @@
 	ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
-func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
-	ctx.BottomUp("ordered_system_server_jars", systemServerJarsDepsMutator)
-}
-
-var (
-	dexpreoptedSystemServerJarsKey  = android.NewOnceKey("dexpreoptedSystemServerJars")
-	dexpreoptedSystemServerJarsLock sync.Mutex
-)
-
-func DexpreoptedSystemServerJars(config android.Config) *[]string {
-	return config.Once(dexpreoptedSystemServerJarsKey, func() interface{} {
-		return &[]string{}
-	}).(*[]string)
-}
-
-// A PostDepsMutator pass that enforces total order on non-updatable system server jars. A total
-// order is neededed because such jars must be dexpreopted together (each jar on the list must have
-// all preceding jars in its class loader context). The total order must be compatible with the
-// partial order imposed by genuine dependencies between system server jars (which is not always
-// respected by the PRODUCT_SYSTEM_SERVER_JARS variable).
-//
-// An earlier mutator pass creates genuine dependencies, and this pass traverses the jars in that
-// order (which is partial and non-deterministic). This pass adds additional dependencies between
-// jars, making the order total and deterministic. It also constructs a global ordered list.
-func systemServerJarsDepsMutator(ctx android.BottomUpMutatorContext) {
-	jars := dexpreopt.NonUpdatableSystemServerJars(ctx, dexpreopt.GetGlobalConfig(ctx))
-	name := ctx.ModuleName()
-	if android.InList(name, jars) {
-		dexpreoptedSystemServerJarsLock.Lock()
-		defer dexpreoptedSystemServerJarsLock.Unlock()
-		jars := DexpreoptedSystemServerJars(ctx.Config())
-		for _, dep := range *jars {
-			ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerDepTag, dep)
-		}
-		*jars = append(*jars, name)
-	}
-}
-
 func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
 	if j.SocSpecific() || j.DeviceSpecific() ||
 		(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
@@ -711,11 +669,6 @@
 	} else if j.shouldInstrumentStatic(ctx) {
 		ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
 	}
-
-	// services depend on com.android.location.provider, but dependency in not registered in a Blueprint file
-	if ctx.ModuleName() == "services" {
-		ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerForcedDepTag, "com.android.location.provider")
-	}
 }
 
 func hasSrcExt(srcs []string, ext string) bool {