Share vdex files in the ART apex between architectures (via symlinks).

Test: aosp_walleye-userdebug boots.

Test: Check symlinks to *.vdex files in the ART apex:
$ adb shell 'find /apex/com.android.art -name '*.vdex' | xargs ls -l'
  lrw-r--r-- 1 system system   23 1970-01-01 01:00 /apex/com.android.art/javalib/arm/boot-apache-xml.vdex -> ../boot-apache-xml.vdex
  lrw-r--r-- 1 system system   25 1970-01-01 01:00 /apex/com.android.art/javalib/arm/boot-bouncycastle.vdex -> ../boot-bouncycastle.vdex
  lrw-r--r-- 1 system system   23 1970-01-01 01:00 /apex/com.android.art/javalib/arm/boot-core-icu4j.vdex -> ../boot-core-icu4j.vdex
  lrw-r--r-- 1 system system   24 1970-01-01 01:00 /apex/com.android.art/javalib/arm/boot-core-libart.vdex -> ../boot-core-libart.vdex
  lrw-r--r-- 1 system system   19 1970-01-01 01:00 /apex/com.android.art/javalib/arm/boot-okhttp.vdex -> ../boot-okhttp.vdex
  lrw-r--r-- 1 system system   12 1970-01-01 01:00 /apex/com.android.art/javalib/arm/boot.vdex -> ../boot.vdex
  lrw-r--r-- 1 system system   23 1970-01-01 01:00 /apex/com.android.art/javalib/arm64/boot-apache-xml.vdex -> ../boot-apache-xml.vdex
  lrw-r--r-- 1 system system   25 1970-01-01 01:00 /apex/com.android.art/javalib/arm64/boot-bouncycastle.vdex -> ../boot-bouncycastle.vdex
  lrw-r--r-- 1 system system   23 1970-01-01 01:00 /apex/com.android.art/javalib/arm64/boot-core-icu4j.vdex -> ../boot-core-icu4j.vdex
  lrw-r--r-- 1 system system   24 1970-01-01 01:00 /apex/com.android.art/javalib/arm64/boot-core-libart.vdex -> ../boot-core-libart.vdex
  lrw-r--r-- 1 system system   19 1970-01-01 01:00 /apex/com.android.art/javalib/arm64/boot-okhttp.vdex -> ../boot-okhttp.vdex
  lrw-r--r-- 1 system system   12 1970-01-01 01:00 /apex/com.android.art/javalib/arm64/boot.vdex -> ../boot.vdex
  -rw-r--r-- 1 system system 1229 1970-01-01 01:00 /apex/com.android.art/javalib/boot-apache-xml.vdex
  -rw-r--r-- 1 system system 2043 1970-01-01 01:00 /apex/com.android.art/javalib/boot-bouncycastle.vdex
  -rw-r--r-- 1 system system 2883 1970-01-01 01:00 /apex/com.android.art/javalib/boot-core-icu4j.vdex
  -rw-r--r-- 1 system system  865 1970-01-01 01:00 /apex/com.android.art/javalib/boot-core-libart.vdex
  -rw-r--r-- 1 system system  395 1970-01-01 01:00 /apex/com.android.art/javalib/boot-okhttp.vdex
  -rw-r--r-- 1 system system 7125 1970-01-01 01:00 /apex/com.android.art/javalib/boot.vdex

Bug: 150934453

Change-Id: Ifbceb845749f4c218693f4118e8b35b59ff26de1
diff --git a/apex/apex.go b/apex/apex.go
index cddd72b..ab6ceff 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2315,7 +2315,10 @@
 	// Build rules are generated by the dexpreopt singleton, and here we access build artifacts
 	// via the global boot image config.
 	if a.artApex {
-		for arch, files := range java.DexpreoptedArtApexJars(ctx) {
+		artAndOatFiles, vdexFiles := java.DexpreoptedArtApexJars(ctx)
+
+		// Copy *.art and *.oat files to arch-specific subdirectories.
+		for arch, files := range artAndOatFiles {
 			dirInApex := filepath.Join("javalib", arch.String())
 			for _, f := range files {
 				localModule := "javalib_" + arch.String() + "_" + filepath.Base(f.String())
@@ -2323,6 +2326,18 @@
 				filesInfo = append(filesInfo, af)
 			}
 		}
+
+		// Copy *.vdex files to a common subdirectory.
+		for _, file := range vdexFiles {
+			dirInApex := "javalib"
+			localModule := "javalib_" + filepath.Base(file.String())
+			af := newApexFile(ctx, file, localModule, dirInApex, etc, nil)
+			// Add a symlink to the *.vdex file for each arch-specific subdirectory.
+			for arch := range artAndOatFiles {
+				af.symlinks = append(af.symlinks, filepath.Join(arch.String(), filepath.Base(file.String())))
+			}
+			filesInfo = append(filesInfo, af)
+		}
 	}
 
 	if a.private_key_file == nil {
diff --git a/apex/builder.go b/apex/builder.go
index 464d843..97be852 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -335,6 +335,7 @@
 	for _, fi := range a.filesInfo {
 		destPath := android.PathForModuleOut(ctx, "image"+suffix, fi.Path()).String()
 		copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(destPath))
+
 		if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() {
 			// TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
 			pathOnDevice := filepath.Join("/system", fi.Path())
@@ -343,10 +344,16 @@
 			copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
 			implicitInputs = append(implicitInputs, fi.builtFile)
 		}
+
 		// create additional symlinks pointing the file inside the APEX
 		for _, symlinkPath := range fi.SymlinkPaths() {
 			symlinkDest := android.PathForModuleOut(ctx, "image"+suffix, symlinkPath).String()
-			copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
+			symlinkTarget, err := filepath.Rel(filepath.Dir(symlinkDest), destPath)
+			if err != nil {
+				panic("Cannot compute relative path from " + destPath + " to " + filepath.Dir(symlinkDest))
+			}
+			copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(symlinkDest))
+			copyCommands = append(copyCommands, "ln -sfn "+symlinkTarget+" "+symlinkDest)
 		}
 	}
 
@@ -409,6 +416,7 @@
 				}
 			} else {
 				readOnlyPaths = append(readOnlyPaths, pathInApex)
+				readOnlyPaths = append(readOnlyPaths, f.SymlinkPaths()...)
 			}
 			dir := f.installDir
 			for !android.InList(dir, executablePaths) && dir != "" {