Merge "Add a flag to allow unbundled builds to build SDKs from source"
diff --git a/OWNERS b/OWNERS
index 780a35b..30546f6 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,4 @@
-per-file * = ccross@android.com,dwillemsen@google.com,nanzhang@google.com
+per-file * = ccross@android.com,dwillemsen@google.com,nanzhang@google.com,jungjw@google.com
 per-file ndk_*.go, *gen_stub_libs.py = danalbert@google.com
 per-file clang.go,global.go,tidy.go = srhines@google.com, chh@google.com
 per-file apex.go = jiyong@google.com
diff --git a/apex/apex.go b/apex/apex.go
index c14cd9e..67b1f27 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -328,6 +328,7 @@
 	archType   android.ArchType
 	installDir string
 	class      apexFileClass
+	module     android.Module
 }
 
 type apexBundle struct {
@@ -517,7 +518,7 @@
 			case sharedLibTag:
 				if cc, ok := child.(*cc.Module); ok {
 					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc})
 					return true
 				} else {
 					ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
@@ -525,7 +526,7 @@
 			case executableTag:
 				if cc, ok := child.(*cc.Module); ok {
 					fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable, cc})
 					return true
 				} else {
 					ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName)
@@ -536,7 +537,7 @@
 					if fileToCopy == nil {
 						ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
 					} else {
-						filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib})
+						filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib, java})
 					}
 					return true
 				} else {
@@ -545,7 +546,7 @@
 			case prebuiltTag:
 				if prebuilt, ok := child.(*android.PrebuiltEtc); ok {
 					fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc, prebuilt})
 					return true
 				} else {
 					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
@@ -574,7 +575,7 @@
 					}
 					depName := ctx.OtherModuleName(child)
 					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
-					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib, cc})
 					return true
 				}
 			}
@@ -793,7 +794,7 @@
 		// For flattened APEX, do nothing but make sure that apex_manifest.json file is also copied along
 		// with other ordinary files.
 		manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-		a.filesInfo = append(a.filesInfo, apexFile{manifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc})
+		a.filesInfo = append(a.filesInfo, apexFile{manifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc, nil})
 
 		for _, fi := range a.filesInfo {
 			dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
@@ -849,6 +850,9 @@
 						fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
 					}
 					if fi.class == javaSharedLib {
+						javaModule := fi.module.(*java.Library)
+						fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
+						fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
 						fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
 						fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
 						fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 88c57bc..acc895f 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -321,6 +321,9 @@
 	// Ensure that stubs libs are built without -include flags
 	mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylib2Cflags, "-include ")
+
+	// Ensure that genstub is invoked with --apex
+	ensureContains(t, "--apex", ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_3_myapex").Rule("genStubSrc").Args["flags"])
 }
 
 func TestApexWithExplicitStubsDependency(t *testing.T) {
diff --git a/cc/binary.go b/cc/binary.go
index 6923f2b..bc9abfe 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -299,9 +299,6 @@
 
 	var linkerDeps android.Paths
 
-	sharedLibs := deps.SharedLibs
-	sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
-
 	if deps.LinkerFlagsFile.Valid() {
 		flags.LdFlags = append(flags.LdFlags, "$$(cat "+deps.LinkerFlagsFile.String()+")")
 		linkerDeps = append(linkerDeps, deps.LinkerFlagsFile.Path())
@@ -363,8 +360,15 @@
 		binary.injectHostBionicLinkerSymbols(ctx, outputFile, deps.DynamicLinker.Path(), injectedOutputFile)
 	}
 
-	linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
-	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
+	var sharedLibs android.Paths
+	// Ignore shared libs for static executables.
+	if !binary.static() {
+		sharedLibs = deps.SharedLibs
+		sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
+		linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
+		linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
+	}
+
 	linkerDeps = append(linkerDeps, objs.tidyFiles...)
 	linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)
 
diff --git a/cc/cc_test.go b/cc/cc_test.go
index e368fb3..33a90f2 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -53,6 +53,7 @@
 
 func createTestContext(t *testing.T, config android.Config, bp string) *android.TestContext {
 	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(binaryFactory))
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
 	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
@@ -194,11 +195,23 @@
 		}
 
 		cc_object {
+			name: "crtbegin_static",
+			recovery_available: true,
+			vendor_available: true,
+		}
+
+		cc_object {
 			name: "crtend_so",
 			recovery_available: true,
 			vendor_available: true,
 		}
 
+		cc_object {
+			name: "crtend_android",
+			recovery_available: true,
+			vendor_available: true,
+		}
+
 		cc_library {
 			name: "libprotobuf-cpp-lite",
 		}
@@ -1845,3 +1858,28 @@
 		t.Errorf("%q is not found in %q", libFoo1VersioningMacro, cFlags)
 	}
 }
+
+func TestStaticExecutable(t *testing.T) {
+	ctx := testCc(t, `
+		cc_binary {
+			name: "static_test",
+			srcs: ["foo.c"],
+			static_executable: true,
+		}`)
+
+	variant := "android_arm64_armv8-a_core"
+	binModuleRule := ctx.ModuleForTests("static_test", variant).Rule("ld")
+	libFlags := binModuleRule.Args["libFlags"]
+	systemStaticLibs := []string{"libc.a", "libm.a", "libdl.a"}
+	for _, lib := range systemStaticLibs {
+		if !strings.Contains(libFlags, lib) {
+			t.Errorf("Static lib %q was not found in %q", lib, libFlags)
+		}
+	}
+	systemSharedLibs := []string{"libc.so", "libm.so", "libdl.so"}
+	for _, lib := range systemSharedLibs {
+		if strings.Contains(libFlags, lib) {
+			t.Errorf("Shared lib %q was found in %q", lib, libFlags)
+		}
+	}
+}
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index c49d197..4906ea2 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -108,7 +108,7 @@
     return version.endswith('_PRIVATE') or version.endswith('_PLATFORM')
 
 
-def should_omit_version(version, arch, api, vndk):
+def should_omit_version(version, arch, api, vndk, apex):
     """Returns True if the version section should be ommitted.
 
     We want to omit any sections that do not have any symbols we'll have in the
@@ -121,6 +121,8 @@
         return True
     if 'vndk' in version.tags and not vndk:
         return True
+    if 'apex' in version.tags and not apex:
+        return True
     if not symbol_in_arch(version.tags, arch):
         return True
     if not symbol_in_api(version.tags, arch, api):
@@ -128,10 +130,12 @@
     return False
 
 
-def should_omit_symbol(symbol, arch, api, vndk):
+def should_omit_symbol(symbol, arch, api, vndk, apex):
     """Returns True if the symbol should be omitted."""
     if not vndk and 'vndk' in symbol.tags:
         return True
+    if not apex and 'apex' in symbol.tags:
+        return True
     if not symbol_in_arch(symbol.tags, arch):
         return True
     if not symbol_in_api(symbol.tags, arch, api):
@@ -239,15 +243,15 @@
     def __eq__(self, other):
         return self.name == other.name and set(self.tags) == set(other.tags)
 
-
 class SymbolFileParser(object):
     """Parses NDK symbol files."""
-    def __init__(self, input_file, api_map, arch, api, vndk):
+    def __init__(self, input_file, api_map, arch, api, vndk, apex):
         self.input_file = input_file
         self.api_map = api_map
         self.arch = arch
         self.api = api
         self.vndk = vndk
+        self.apex = apex
         self.current_line = None
 
     def parse(self):
@@ -275,11 +279,11 @@
         symbol_names = set()
         multiply_defined_symbols = set()
         for version in versions:
-            if should_omit_version(version, self.arch, self.api, self.vndk):
+            if should_omit_version(version, self.arch, self.api, self.vndk, self.apex):
                 continue
 
             for symbol in version.symbols:
-                if should_omit_symbol(symbol, self.arch, self.api, self.vndk):
+                if should_omit_symbol(symbol, self.arch, self.api, self.vndk, self.apex):
                     continue
 
                 if symbol.name in symbol_names:
@@ -363,12 +367,13 @@
 
 class Generator(object):
     """Output generator that writes stub source files and version scripts."""
-    def __init__(self, src_file, version_script, arch, api, vndk):
+    def __init__(self, src_file, version_script, arch, api, vndk, apex):
         self.src_file = src_file
         self.version_script = version_script
         self.arch = arch
         self.api = api
         self.vndk = vndk
+        self.apex = apex
 
     def write(self, versions):
         """Writes all symbol data to the output files."""
@@ -377,14 +382,14 @@
 
     def write_version(self, version):
         """Writes a single version block's data to the output files."""
-        if should_omit_version(version, self.arch, self.api, self.vndk):
+        if should_omit_version(version, self.arch, self.api, self.vndk, self.apex):
             return
 
         section_versioned = symbol_versioned_in_api(version.tags, self.api)
         version_empty = True
         pruned_symbols = []
         for symbol in version.symbols:
-            if should_omit_symbol(symbol, self.arch, self.api, self.vndk):
+            if should_omit_symbol(symbol, self.arch, self.api, self.vndk, self.apex):
                 continue
 
             if symbol_versioned_in_api(symbol.tags, self.api):
@@ -447,6 +452,8 @@
         help='Architecture being targeted.')
     parser.add_argument(
         '--vndk', action='store_true', help='Use the VNDK variant.')
+    parser.add_argument(
+        '--apex', action='store_true', help='Use the APEX variant.')
 
     parser.add_argument(
         '--api-map', type=os.path.realpath, required=True,
@@ -481,14 +488,14 @@
     with open(args.symbol_file) as symbol_file:
         try:
             versions = SymbolFileParser(symbol_file, api_map, args.arch, api,
-                                        args.vndk).parse()
+                                        args.vndk, args.apex).parse()
         except MultiplyDefinedSymbolError as ex:
             sys.exit('{}: error: {}'.format(args.symbol_file, ex))
 
     with open(args.stub_src, 'w') as src_file:
         with open(args.version_script, 'w') as version_file:
             generator = Generator(src_file, version_file, args.arch, api,
-                                  args.vndk)
+                                  args.vndk, args.apex)
             generator.write(versions)
 
 
diff --git a/cc/library.go b/cc/library.go
index 524b886..40c1b4f 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -395,7 +395,7 @@
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	if library.buildStubs() {
-		objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "")
+		objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "--apex")
 		library.versionScriptPath = versionScript
 		return objs
 	}
@@ -807,6 +807,7 @@
 			"-I" + android.PathForModuleGen(ctx, "sysprop", "include").String(),
 		}
 		library.reexportFlags(flags)
+		library.reexportDeps(library.baseCompiler.pathDeps)
 		library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
 	}
 
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 53fe314..1b09f88 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -31,9 +31,9 @@
 	genStubSrc = pctx.AndroidStaticRule("genStubSrc",
 		blueprint.RuleParams{
 			Command: "$toolPath --arch $arch --api $apiLevel --api-map " +
-				"$apiMap $vndk $in $out",
+				"$apiMap $flags $in $out",
 			CommandDeps: []string{"$toolPath"},
-		}, "arch", "apiLevel", "apiMap", "vndk")
+		}, "arch", "apiLevel", "apiMap", "flags")
 
 	ndkLibrarySuffix = ".ndk"
 
@@ -271,7 +271,7 @@
 	return addStubLibraryCompilerFlags(flags)
 }
 
-func compileStubLibrary(ctx ModuleContext, flags Flags, symbolFile, apiLevel, vndk string) (Objects, android.ModuleGenPath) {
+func compileStubLibrary(ctx ModuleContext, flags Flags, symbolFile, apiLevel, genstubFlags string) (Objects, android.ModuleGenPath) {
 	arch := ctx.Arch().ArchType.String()
 
 	stubSrcPath := android.PathForModuleGen(ctx, "stub.c")
@@ -288,7 +288,7 @@
 			"arch":     arch,
 			"apiLevel": apiLevel,
 			"apiMap":   apiLevelsJson.String(),
-			"vndk":     vndk,
+			"flags":    genstubFlags,
 		},
 	})
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 5db6bdf..8d33de5 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -58,7 +58,7 @@
 	// TODO(pcc): Remove the -Xclang once LLVM r346526 is rolled into the compiler.
 	minimalRuntimeFlags = []string{"-Xclang", "-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
 		"-fno-sanitize-recover=integer,undefined"}
-	hwasanGlobalOptions = []string{"heap_history_size=4095"}
+	hwasanGlobalOptions = []string{"heap_history_size=1023,stack_history_size=512"}
 )
 
 type sanitizerType int
diff --git a/cc/test_gen_stub_libs.py b/cc/test_gen_stub_libs.py
index 3b5585a..594c1bc 100755
--- a/cc/test_gen_stub_libs.py
+++ b/cc/test_gen_stub_libs.py
@@ -165,92 +165,115 @@
     def test_omit_private(self):
         self.assertFalse(
             gsl.should_omit_version(
-                gsl.Version('foo', None, [], []), 'arm', 9, False))
+                gsl.Version('foo', None, [], []), 'arm', 9, False, False))
 
         self.assertTrue(
             gsl.should_omit_version(
-                gsl.Version('foo_PRIVATE', None, [], []), 'arm', 9, False))
+                gsl.Version('foo_PRIVATE', None, [], []), 'arm', 9, False, False))
         self.assertTrue(
             gsl.should_omit_version(
-                gsl.Version('foo_PLATFORM', None, [], []), 'arm', 9, False))
+                gsl.Version('foo_PLATFORM', None, [], []), 'arm', 9, False, False))
 
         self.assertTrue(
             gsl.should_omit_version(
                 gsl.Version('foo', None, ['platform-only'], []), 'arm', 9,
-                False))
+                False, False))
 
     def test_omit_vndk(self):
         self.assertTrue(
             gsl.should_omit_version(
-                gsl.Version('foo', None, ['vndk'], []), 'arm', 9, False))
+                gsl.Version('foo', None, ['vndk'], []), 'arm', 9, False, False))
 
         self.assertFalse(
             gsl.should_omit_version(
-                gsl.Version('foo', None, [], []), 'arm', 9, True))
+                gsl.Version('foo', None, [], []), 'arm', 9, True, False))
         self.assertFalse(
             gsl.should_omit_version(
-                gsl.Version('foo', None, ['vndk'], []), 'arm', 9, True))
+                gsl.Version('foo', None, ['vndk'], []), 'arm', 9, True, False))
+
+    def test_omit_apex(self):
+        self.assertTrue(
+            gsl.should_omit_version(
+                gsl.Version('foo', None, ['apex'], []), 'arm', 9, False, False))
+
+        self.assertFalse(
+            gsl.should_omit_version(
+                gsl.Version('foo', None, [], []), 'arm', 9, False, True))
+        self.assertFalse(
+            gsl.should_omit_version(
+                gsl.Version('foo', None, ['apex'], []), 'arm', 9, False, True))
 
     def test_omit_arch(self):
         self.assertFalse(
             gsl.should_omit_version(
-                gsl.Version('foo', None, [], []), 'arm', 9, False))
+                gsl.Version('foo', None, [], []), 'arm', 9, False, False))
         self.assertFalse(
             gsl.should_omit_version(
-                gsl.Version('foo', None, ['arm'], []), 'arm', 9, False))
+                gsl.Version('foo', None, ['arm'], []), 'arm', 9, False, False))
 
         self.assertTrue(
             gsl.should_omit_version(
-                gsl.Version('foo', None, ['x86'], []), 'arm', 9, False))
+                gsl.Version('foo', None, ['x86'], []), 'arm', 9, False, False))
 
     def test_omit_api(self):
         self.assertFalse(
             gsl.should_omit_version(
-                gsl.Version('foo', None, [], []), 'arm', 9, False))
+                gsl.Version('foo', None, [], []), 'arm', 9, False, False))
         self.assertFalse(
             gsl.should_omit_version(
                 gsl.Version('foo', None, ['introduced=9'], []), 'arm', 9,
-                False))
+                False, False))
 
         self.assertTrue(
             gsl.should_omit_version(
                 gsl.Version('foo', None, ['introduced=14'], []), 'arm', 9,
-                False))
+                False, False))
 
 
 class OmitSymbolTest(unittest.TestCase):
     def test_omit_vndk(self):
         self.assertTrue(
             gsl.should_omit_symbol(
-                gsl.Symbol('foo', ['vndk']), 'arm', 9, False))
+                gsl.Symbol('foo', ['vndk']), 'arm', 9, False, False))
 
         self.assertFalse(
-            gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, True))
+            gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, True, False))
         self.assertFalse(
             gsl.should_omit_symbol(
-                gsl.Symbol('foo', ['vndk']), 'arm', 9, True))
+                gsl.Symbol('foo', ['vndk']), 'arm', 9, True, False))
+
+    def test_omit_apex(self):
+        self.assertTrue(
+            gsl.should_omit_symbol(
+                gsl.Symbol('foo', ['apex']), 'arm', 9, False, False))
+
+        self.assertFalse(
+            gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, False, True))
+        self.assertFalse(
+            gsl.should_omit_symbol(
+                gsl.Symbol('foo', ['apex']), 'arm', 9, False, True))
 
     def test_omit_arch(self):
         self.assertFalse(
-            gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, False))
+            gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, False, False))
         self.assertFalse(
             gsl.should_omit_symbol(
-                gsl.Symbol('foo', ['arm']), 'arm', 9, False))
+                gsl.Symbol('foo', ['arm']), 'arm', 9, False, False))
 
         self.assertTrue(
             gsl.should_omit_symbol(
-                gsl.Symbol('foo', ['x86']), 'arm', 9, False))
+                gsl.Symbol('foo', ['x86']), 'arm', 9, False, False))
 
     def test_omit_api(self):
         self.assertFalse(
-            gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, False))
+            gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, False, False))
         self.assertFalse(
             gsl.should_omit_symbol(
-                gsl.Symbol('foo', ['introduced=9']), 'arm', 9, False))
+                gsl.Symbol('foo', ['introduced=9']), 'arm', 9, False, False))
 
         self.assertTrue(
             gsl.should_omit_symbol(
-                gsl.Symbol('foo', ['introduced=14']), 'arm', 9, False))
+                gsl.Symbol('foo', ['introduced=14']), 'arm', 9, False, False))
 
 
 class SymbolFileParseTest(unittest.TestCase):
@@ -262,7 +285,7 @@
             # baz
             qux
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
         self.assertIsNone(parser.current_line)
 
         self.assertEqual('foo', parser.next_line().strip())
@@ -287,7 +310,7 @@
             VERSION_2 {
             } VERSION_1; # asdf
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
 
         parser.next_line()
         version = parser.parse_version()
@@ -311,7 +334,7 @@
         input_file = io.StringIO(textwrap.dedent("""\
             VERSION_1 {
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
         parser.next_line()
         with self.assertRaises(gsl.ParseError):
             parser.parse_version()
@@ -322,7 +345,7 @@
                 foo:
             }
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
         parser.next_line()
         with self.assertRaises(gsl.ParseError):
             parser.parse_version()
@@ -332,7 +355,7 @@
             foo;
             bar; # baz qux
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
 
         parser.next_line()
         symbol = parser.parse_symbol()
@@ -350,7 +373,7 @@
                 *;
             };
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
         parser.next_line()
         with self.assertRaises(gsl.ParseError):
             parser.parse_version()
@@ -362,7 +385,7 @@
                     *;
             };
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
         parser.next_line()
         version = parser.parse_version()
         self.assertEqual([], version.symbols)
@@ -373,7 +396,7 @@
                 foo
             };
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
         parser.next_line()
         with self.assertRaises(gsl.ParseError):
             parser.parse_version()
@@ -381,7 +404,7 @@
     def test_parse_fails_invalid_input(self):
         with self.assertRaises(gsl.ParseError):
             input_file = io.StringIO('foo')
-            parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+            parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
             parser.parse()
 
     def test_parse(self):
@@ -402,7 +425,7 @@
                     qwerty;
             } VERSION_1;
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
         versions = parser.parse()
 
         expected = [
@@ -418,6 +441,30 @@
 
         self.assertEqual(expected, versions)
 
+    def test_parse_vndk_apex_symbol(self):
+        input_file = io.StringIO(textwrap.dedent("""\
+            VERSION_1 {
+                foo;
+                bar; # vndk
+                baz; # vndk apex
+                qux; # apex
+            };
+        """))
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, True)
+
+        parser.next_line()
+        version = parser.parse_version()
+        self.assertEqual('VERSION_1', version.name)
+        self.assertIsNone(version.base)
+
+        expected_symbols = [
+            gsl.Symbol('foo', []),
+            gsl.Symbol('bar', ['vndk']),
+            gsl.Symbol('baz', ['vndk', 'apex']),
+            gsl.Symbol('qux', ['apex']),
+        ]
+        self.assertEqual(expected_symbols, version.symbols)
+
 
 class GeneratorTest(unittest.TestCase):
     def test_omit_version(self):
@@ -425,7 +472,7 @@
         # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
         src_file = io.StringIO()
         version_file = io.StringIO()
-        generator = gsl.Generator(src_file, version_file, 'arm', 9, False)
+        generator = gsl.Generator(src_file, version_file, 'arm', 9, False, False)
 
         version = gsl.Version('VERSION_PRIVATE', None, [], [
             gsl.Symbol('foo', []),
@@ -453,7 +500,7 @@
         # SymbolPresenceTest.
         src_file = io.StringIO()
         version_file = io.StringIO()
-        generator = gsl.Generator(src_file, version_file, 'arm', 9, False)
+        generator = gsl.Generator(src_file, version_file, 'arm', 9, False, False)
 
         version = gsl.Version('VERSION_1', None, [], [
             gsl.Symbol('foo', ['x86']),
@@ -476,10 +523,17 @@
         self.assertEqual('', src_file.getvalue())
         self.assertEqual('', version_file.getvalue())
 
+        version = gsl.Version('VERSION_1', None, [], [
+            gsl.Symbol('foo', ['apex']),
+        ])
+        generator.write_version(version)
+        self.assertEqual('', src_file.getvalue())
+        self.assertEqual('', version_file.getvalue())
+
     def test_write(self):
         src_file = io.StringIO()
         version_file = io.StringIO()
-        generator = gsl.Generator(src_file, version_file, 'arm', 9, False)
+        generator = gsl.Generator(src_file, version_file, 'arm', 9, False, False)
 
         versions = [
             gsl.Version('VERSION_1', None, [], [
@@ -554,18 +608,19 @@
             VERSION_4 { # versioned=9
                 wibble;
                 wizzes; # vndk
+                waggle; # apex
             } VERSION_2;
 
             VERSION_5 { # versioned=14
                 wobble;
             } VERSION_4;
         """))
-        parser = gsl.SymbolFileParser(input_file, api_map, 'arm', 9, False)
+        parser = gsl.SymbolFileParser(input_file, api_map, 'arm', 9, False, False)
         versions = parser.parse()
 
         src_file = io.StringIO()
         version_file = io.StringIO()
-        generator = gsl.Generator(src_file, version_file, 'arm', 9, False)
+        generator = gsl.Generator(src_file, version_file, 'arm', 9, False, False)
         generator.write(versions)
 
         expected_src = textwrap.dedent("""\
@@ -610,12 +665,12 @@
                     *;
             };
         """))
-        parser = gsl.SymbolFileParser(input_file, api_map, 'arm', 9001, False)
+        parser = gsl.SymbolFileParser(input_file, api_map, 'arm', 9001, False, False)
         versions = parser.parse()
 
         src_file = io.StringIO()
         version_file = io.StringIO()
-        generator = gsl.Generator(src_file, version_file, 'arm', 9001, False)
+        generator = gsl.Generator(src_file, version_file, 'arm', 9001, False, False)
         generator.write(versions)
 
         expected_src = textwrap.dedent("""\
@@ -658,13 +713,84 @@
             } VERSION_2;
 
         """))
-        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False)
+        parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
 
         with self.assertRaises(gsl.MultiplyDefinedSymbolError) as cm:
             parser.parse()
         self.assertEquals(['bar', 'foo'],
                           cm.exception.multiply_defined_symbols)
 
+    def test_integration_with_apex(self):
+        api_map = {
+            'O': 9000,
+            'P': 9001,
+        }
+
+        input_file = io.StringIO(textwrap.dedent("""\
+            VERSION_1 {
+                global:
+                    foo; # var
+                    bar; # x86
+                    fizz; # introduced=O
+                    buzz; # introduced=P
+                local:
+                    *;
+            };
+
+            VERSION_2 { # arm
+                baz; # introduced=9
+                qux; # versioned=14
+            } VERSION_1;
+
+            VERSION_3 { # introduced=14
+                woodly;
+                doodly; # var
+            } VERSION_2;
+
+            VERSION_4 { # versioned=9
+                wibble;
+                wizzes; # vndk
+                waggle; # apex
+            } VERSION_2;
+
+            VERSION_5 { # versioned=14
+                wobble;
+            } VERSION_4;
+        """))
+        parser = gsl.SymbolFileParser(input_file, api_map, 'arm', 9, False, True)
+        versions = parser.parse()
+
+        src_file = io.StringIO()
+        version_file = io.StringIO()
+        generator = gsl.Generator(src_file, version_file, 'arm', 9, False, True)
+        generator.write(versions)
+
+        expected_src = textwrap.dedent("""\
+            int foo = 0;
+            void baz() {}
+            void qux() {}
+            void wibble() {}
+            void waggle() {}
+            void wobble() {}
+        """)
+        self.assertEqual(expected_src, src_file.getvalue())
+
+        expected_version = textwrap.dedent("""\
+            VERSION_1 {
+                global:
+                    foo;
+            };
+            VERSION_2 {
+                global:
+                    baz;
+            } VERSION_1;
+            VERSION_4 {
+                global:
+                    wibble;
+                    waggle;
+            } VERSION_2;
+        """)
+        self.assertEqual(expected_version, version_file.getvalue())
 
 def main():
     suite = unittest.TestLoader().loadTestsFromName(__name__)
diff --git a/dexpreopt/OWNERS b/dexpreopt/OWNERS
new file mode 100644
index 0000000..166472f
--- /dev/null
+++ b/dexpreopt/OWNERS
@@ -0,0 +1 @@
+per-file * = ngeoffray@google.com,calin@google.com,mathieuc@google.com
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 0c2df6e..0ea32b8 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -224,8 +224,12 @@
 	var classLoaderContextTarget []string
 
 	// Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 28
-	var conditionalClassLoaderContextHost []string
-	var conditionalClassLoaderContextTarget []string
+	var conditionalClassLoaderContextHost28 []string
+	var conditionalClassLoaderContextTarget28 []string
+
+	// Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 29
+	var conditionalClassLoaderContextHost29 []string
+	var conditionalClassLoaderContextTarget29 []string
 
 	if module.EnforceUsesLibraries {
 		verifyUsesLibs = copyOf(module.UsesLibraries)
@@ -251,11 +255,23 @@
 		replace(verifyOptionalUsesLibs, httpLegacyImpl, httpLegacy)
 
 		if !contains(verifyUsesLibs, httpLegacy) && !contains(verifyOptionalUsesLibs, httpLegacy) {
-			conditionalClassLoaderContextHost = append(conditionalClassLoaderContextHost,
+			conditionalClassLoaderContextHost28 = append(conditionalClassLoaderContextHost28,
 				pathForLibrary(module, httpLegacyImpl))
-			conditionalClassLoaderContextTarget = append(conditionalClassLoaderContextTarget,
+			conditionalClassLoaderContextTarget28 = append(conditionalClassLoaderContextTarget28,
 				filepath.Join("/system/framework", httpLegacyImpl+".jar"))
 		}
+
+		const hidlBase = "android.hidl.base-V1.0-java"
+		const hidlManager = "android.hidl.manager-V1.0-java"
+
+		conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
+      pathForLibrary(module, hidlManager))
+		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
+			filepath.Join("/system/framework", hidlManager+".jar"))
+		conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
+      pathForLibrary(module, hidlBase))
+		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
+			filepath.Join("/system/framework", hidlBase+".jar"))
 	} else {
 		// Pass special class loader context to skip the classpath and collision check.
 		// This will get removed once LOCAL_USES_LIBRARIES is enforced.
@@ -272,15 +288,17 @@
 	rule.Command().Text(`stored_class_loader_context_arg=""`)
 
 	if module.EnforceUsesLibraries {
-		rule.Command().FlagWithList("stored_class_loader_context_libs=", classLoaderContextTarget, ":")
-		rule.Command().FlagWithInputList("class_loader_context=", classLoaderContextHost, ":")
 		rule.Command().Textf(`uses_library_names="%s"`, strings.Join(verifyUsesLibs, " "))
 		rule.Command().Textf(`optional_uses_library_names="%s"`, strings.Join(verifyOptionalUsesLibs, " "))
 		rule.Command().Textf(`aapt_binary="%s"`, global.Tools.Aapt)
+		rule.Command().Textf(`dex_preopt_host_libraries="%s"`, strings.Join(classLoaderContextHost, " " ))
+		rule.Command().Textf(`dex_preopt_target_libraries="%s"`, strings.Join(classLoaderContextTarget, " "))
+		rule.Command().Textf(`conditional_host_libs_28="%s"`, strings.Join(conditionalClassLoaderContextHost28, " "))
+		rule.Command().Textf(`conditional_target_libs_28="%s"`, strings.Join(conditionalClassLoaderContextTarget28, " "))
+		rule.Command().Textf(`conditional_host_libs_29="%s"`, strings.Join(conditionalClassLoaderContextHost29, " "))
+		rule.Command().Textf(`conditional_target_libs_29="%s"`, strings.Join(conditionalClassLoaderContextTarget29, " "))
 		rule.Command().Text("source").Tool(global.Tools.VerifyUsesLibraries).Input(module.DexPath)
-		rule.Command().Text("source").Tool(global.Tools.ConstructContext).
-			Textf(`"%s"`, strings.Join(conditionalClassLoaderContextHost, ":")).
-			Textf(`"%s"`, strings.Join(conditionalClassLoaderContextTarget, ":"))
+		rule.Command().Text("source").Tool(global.Tools.ConstructContext)
 	}
 
 	cmd := rule.Command().
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index c010056..46d8795 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -104,6 +104,7 @@
 	installDir := filepath.Join(filepath.Dir(module.BuildPath), "dexpreopt_install")
 
 	dexpreoptRule.Command().FlagWithArg("rm -rf ", installDir)
+	dexpreoptRule.Command().FlagWithArg("mkdir -p ", installDir)
 
 	for _, install := range dexpreoptRule.Installs() {
 		installPath := filepath.Join(installDir, install.To)
diff --git a/java/OWNERS b/java/OWNERS
new file mode 100644
index 0000000..d68a5b0
--- /dev/null
+++ b/java/OWNERS
@@ -0,0 +1 @@
+per-file dexpreopt.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com