Merge "Add attribute to disable last-api compat tracking"
diff --git a/android/androidmk.go b/android/androidmk.go
index 062dcb3..73f60d0 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -627,7 +627,7 @@
 
 	fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
 
-	type_stats := make(map[string]int)
+	typeStats := make(map[string]int)
 	for _, mod := range mods {
 		err := translateAndroidMkModule(ctx, buf, mod)
 		if err != nil {
@@ -636,19 +636,19 @@
 		}
 
 		if amod, ok := mod.(Module); ok && ctx.PrimaryModule(amod) == amod {
-			type_stats[ctx.ModuleType(amod)] += 1
+			typeStats[ctx.ModuleType(amod)] += 1
 		}
 	}
 
 	keys := []string{}
 	fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=")
-	for k := range type_stats {
+	for k := range typeStats {
 		keys = append(keys, k)
 	}
 	sort.Strings(keys)
 	for _, mod_type := range keys {
 		fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type)
-		fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, type_stats[mod_type])
+		fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, typeStats[mod_type])
 	}
 
 	// Don't write to the file if it hasn't changed
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 81ca475..357b99f 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -387,25 +387,25 @@
 	if err != nil {
 		return err
 	}
-	cquery_file_relpath := filepath.Join(context.intermediatesDir(), "buildroot.cquery")
+	cqueryFileRelpath := filepath.Join(context.intermediatesDir(), "buildroot.cquery")
 	err = ioutil.WriteFile(
-		absolutePath(cquery_file_relpath),
+		absolutePath(cqueryFileRelpath),
 		context.cqueryStarlarkFileContents(), 0666)
 	if err != nil {
 		return err
 	}
-	workspace_file_relpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel")
+	workspaceFileRelpath := filepath.Join(context.intermediatesDir(), "WORKSPACE.bazel")
 	err = ioutil.WriteFile(
-		absolutePath(workspace_file_relpath),
+		absolutePath(workspaceFileRelpath),
 		context.workspaceFileContents(), 0666)
 	if err != nil {
 		return err
 	}
-	buildroot_label := "//:buildroot"
+	buildrootLabel := "//:buildroot"
 	cqueryOutput, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery",
-		[]string{fmt.Sprintf("deps(%s)", buildroot_label)},
+		[]string{fmt.Sprintf("deps(%s)", buildrootLabel)},
 		"--output=starlark",
-		"--starlark:file="+cquery_file_relpath)
+		"--starlark:file="+cqueryFileRelpath)
 
 	if err != nil {
 		return err
@@ -432,7 +432,7 @@
 	// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
 	var aqueryOutput string
 	aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
-		[]string{fmt.Sprintf("deps(%s)", buildroot_label),
+		[]string{fmt.Sprintf("deps(%s)", buildrootLabel),
 			// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
 			// proto sources, which would add a number of unnecessary dependencies.
 			"--output=jsonproto"})
diff --git a/android/makevars.go b/android/makevars.go
index 5101436..546abcf 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -90,6 +90,7 @@
 	ModuleDir(module blueprint.Module) string
 	ModuleSubDir(module blueprint.Module) string
 	ModuleType(module blueprint.Module) string
+	ModuleProvider(module blueprint.Module, key blueprint.ProviderKey) interface{}
 	BlueprintFile(module blueprint.Module) string
 
 	ModuleErrorf(module blueprint.Module, format string, args ...interface{})
diff --git a/android/namespace.go b/android/namespace.go
index 9d7e8ac..d137636 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -232,13 +232,14 @@
 
 }
 
-func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace *Namespace) (searchOrder []*Namespace) {
-	if sourceNamespace.visibleNamespaces == nil {
+func (r *NameResolver) getNamespacesToSearchForModule(sourceNamespace blueprint.Namespace) (searchOrder []*Namespace) {
+	ns, ok := sourceNamespace.(*Namespace)
+	if !ok || ns.visibleNamespaces == nil {
 		// When handling dependencies before namespaceMutator, assume they are non-Soong Blueprint modules and give
 		// access to all namespaces.
 		return r.sortedNamespaces.sortedItems()
 	}
-	return sourceNamespace.visibleNamespaces
+	return ns.visibleNamespaces
 }
 
 func (r *NameResolver) ModuleFromName(name string, namespace blueprint.Namespace) (group blueprint.ModuleGroup, found bool) {
@@ -252,7 +253,7 @@
 		container := namespace.moduleContainer
 		return container.ModuleFromName(moduleName, nil)
 	}
-	for _, candidate := range r.getNamespacesToSearchForModule(namespace.(*Namespace)) {
+	for _, candidate := range r.getNamespacesToSearchForModule(namespace) {
 		group, found = candidate.moduleContainer.ModuleFromName(name, nil)
 		if found {
 			return group, true
diff --git a/android/neverallow.go b/android/neverallow.go
index 8b8e1ac..031b3f4 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -51,7 +51,6 @@
 func init() {
 	AddNeverAllowRules(createIncludeDirsRules()...)
 	AddNeverAllowRules(createTrebleRules()...)
-	AddNeverAllowRules(createLibcoreRules()...)
 	AddNeverAllowRules(createMediaRules()...)
 	AddNeverAllowRules(createJavaDeviceForHostRules()...)
 	AddNeverAllowRules(createCcSdkVariantRules()...)
@@ -133,38 +132,6 @@
 	}
 }
 
-func createLibcoreRules() []Rule {
-	var coreLibraryProjects = []string{
-		"libcore",
-		"external/apache-harmony",
-		"external/apache-xml",
-		"external/bouncycastle",
-		"external/conscrypt",
-		"external/icu",
-		"external/okhttp",
-		"external/wycheproof",
-		"prebuilts",
-	}
-
-	// Additional whitelisted path only used for ART testing, which needs access to core library
-	// targets. This does not affect the contents of a device image (system, vendor, etc.).
-	var artTests = []string{
-		"art/test",
-	}
-
-	// Core library constraints. The sdk_version: "none" can only be used in core library projects and ART tests.
-	// Access to core library targets is restricted using visibility rules.
-	rules := []Rule{
-		NeverAllow().
-			NotIn(coreLibraryProjects...).
-			NotIn(artTests...).
-			With("sdk_version", "none").
-			WithoutMatcher("name", Regexp("^android_.*stubs_current$")),
-	}
-
-	return rules
-}
-
 func createMediaRules() []Rule {
 	return []Rule{
 		NeverAllow().
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 1d454e5..8c7a538 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -215,50 +215,6 @@
 			"java_device_for_host can only be used in allowed projects",
 		},
 	},
-	// Libcore rule tests
-	{
-		name: "sdk_version: \"none\" inside core libraries",
-		fs: map[string][]byte{
-			"libcore/Android.bp": []byte(`
-				java_library {
-					name: "inside_core_libraries",
-					sdk_version: "none",
-				}`),
-		},
-	},
-	{
-		name: "sdk_version: \"none\" on android_*stubs_current stub",
-		fs: map[string][]byte{
-			"frameworks/base/Android.bp": []byte(`
-				java_library {
-					name: "android_stubs_current",
-					sdk_version: "none",
-				}`),
-		},
-	},
-	{
-		name: "sdk_version: \"none\" outside core libraries",
-		fs: map[string][]byte{
-			"Android.bp": []byte(`
-				java_library {
-					name: "outside_core_libraries",
-					sdk_version: "none",
-				}`),
-		},
-		expectedErrors: []string{
-			"module \"outside_core_libraries\": violates neverallow",
-		},
-	},
-	{
-		name: "sdk_version: \"current\"",
-		fs: map[string][]byte{
-			"Android.bp": []byte(`
-				java_library {
-					name: "outside_core_libraries",
-					sdk_version: "current",
-				}`),
-		},
-	},
 	// CC sdk rule tests
 	{
 		name: `"sdk_variant_only" outside allowed list`,
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 4540a1f..f0f51bf 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -24,8 +24,8 @@
 )
 
 const (
-	clear_vars      = "__android_mk_clear_vars"
-	include_ignored = "__android_mk_include_ignored"
+	clearVarsPath      = "__android_mk_clear_vars"
+	includeIgnoredPath = "__android_mk_include_ignored"
 )
 
 type bpVariable struct {
@@ -913,7 +913,7 @@
 }
 
 func includeIgnored(args []string) []string {
-	return []string{include_ignored}
+	return []string{includeIgnoredPath}
 }
 
 var moduleTypes = map[string]string{
@@ -959,7 +959,7 @@
 }
 
 func mapIncludePath(path string) (string, bool) {
-	if path == clear_vars || path == include_ignored {
+	if path == clearVarsPath || path == includeIgnoredPath {
 		return path, true
 	}
 	module, ok := includePathToModule[path]
@@ -968,7 +968,7 @@
 
 func androidScope() mkparser.Scope {
 	globalScope := mkparser.NewScope(nil)
-	globalScope.Set("CLEAR_VARS", clear_vars)
+	globalScope.Set("CLEAR_VARS", clearVarsPath)
 	globalScope.SetFunc("my-dir", mydir)
 	globalScope.SetFunc("all-java-files-under", allFilesUnder("*.java"))
 	globalScope.SetFunc("all-proto-files-under", allFilesUnder("*.proto"))
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index f4e5fa0..2d1bbb4 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -156,9 +156,9 @@
 					continue
 				}
 				switch module {
-				case clear_vars:
+				case clearVarsPath:
 					resetModule(file)
-				case include_ignored:
+				case includeIgnoredPath:
 					// subdirs are already automatically included in Soong
 					continue
 				default:
diff --git a/apex/apex.go b/apex/apex.go
index 9e66254..9fb616d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -298,12 +298,12 @@
 	// Inputs
 
 	// Keys for apex_paylaod.img
-	public_key_file  android.Path
-	private_key_file android.Path
+	publicKeyFile  android.Path
+	privateKeyFile android.Path
 
 	// Cert/priv-key for the zip container
-	container_certificate_file android.Path
-	container_private_key_file android.Path
+	containerCertificateFile android.Path
+	containerPrivateKeyFile  android.Path
 
 	// Flags for special variants of APEX
 	testApex bool
@@ -1684,16 +1684,16 @@
 				}
 			case keyTag:
 				if key, ok := child.(*apexKey); ok {
-					a.private_key_file = key.private_key_file
-					a.public_key_file = key.public_key_file
+					a.privateKeyFile = key.privateKeyFile
+					a.publicKeyFile = key.publicKeyFile
 				} else {
 					ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
 				}
 				return false
 			case certificateTag:
 				if dep, ok := child.(*java.AndroidAppCertificate); ok {
-					a.container_certificate_file = dep.Certificate.Pem
-					a.container_private_key_file = dep.Certificate.Key
+					a.containerCertificateFile = dep.Certificate.Pem
+					a.containerPrivateKeyFile = dep.Certificate.Key
 				} else {
 					ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
 				}
@@ -1810,7 +1810,7 @@
 		}
 		return false
 	})
-	if a.private_key_file == nil {
+	if a.privateKeyFile == nil {
 		ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
 		return
 	}
@@ -1950,7 +1950,7 @@
 		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   android.Cp,
-			Input:  a.public_key_file,
+			Input:  a.publicKeyFile,
 			Output: copiedPubkey,
 		})
 		a.filesInfo = append(a.filesInfo, newApexFile(ctx, copiedPubkey, "apex_pubkey", ".", etc, nil))
@@ -2839,14 +2839,14 @@
 func createApexPermittedPackagesRules(modules_packages map[string][]string) []android.Rule {
 	rules := make([]android.Rule, 0, len(modules_packages))
 	for module_name, module_packages := range modules_packages {
-		permitted_packages_rule := android.NeverAllow().
+		permittedPackagesRule := android.NeverAllow().
 			BootclasspathJar().
 			With("apex_available", module_name).
 			WithMatcher("permitted_packages", android.NotInList(module_packages)).
 			Because("jars that are part of the " + module_name +
 				" module may only allow these packages: " + strings.Join(module_packages, ",") +
 				". Please jarjar or move code around.")
-		rules = append(rules, permitted_packages_rule)
+		rules = append(rules, permittedPackagesRule)
 	}
 	return rules
 }
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7c82b05..b8d44f4 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1356,9 +1356,9 @@
 			ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
 
 			mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"]
-			ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
+			ensureContains(t, mylibLdFlags, "libbar/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
 			for _, ver := range tc.shouldNotLink {
-				ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so")
+				ensureNotContains(t, mylibLdFlags, "libbar/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so")
 			}
 
 			mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"]
@@ -2680,12 +2680,12 @@
 	// check the APEX keys
 	keys := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey)
 
-	if keys.public_key_file.String() != "vendor/foo/devkeys/testkey.avbpubkey" {
-		t.Errorf("public key %q is not %q", keys.public_key_file.String(),
+	if keys.publicKeyFile.String() != "vendor/foo/devkeys/testkey.avbpubkey" {
+		t.Errorf("public key %q is not %q", keys.publicKeyFile.String(),
 			"vendor/foo/devkeys/testkey.avbpubkey")
 	}
-	if keys.private_key_file.String() != "vendor/foo/devkeys/testkey.pem" {
-		t.Errorf("private key %q is not %q", keys.private_key_file.String(),
+	if keys.privateKeyFile.String() != "vendor/foo/devkeys/testkey.pem" {
+		t.Errorf("private key %q is not %q", keys.privateKeyFile.String(),
 			"vendor/foo/devkeys/testkey.pem")
 	}
 
@@ -4144,12 +4144,12 @@
 
 	apex_key := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey)
 	expected_pubkey := "testkey2.avbpubkey"
-	actual_pubkey := apex_key.public_key_file.String()
+	actual_pubkey := apex_key.publicKeyFile.String()
 	if actual_pubkey != expected_pubkey {
 		t.Errorf("wrong public key path. expected %q. actual %q", expected_pubkey, actual_pubkey)
 	}
 	expected_privkey := "testkey2.pem"
-	actual_privkey := apex_key.private_key_file.String()
+	actual_privkey := apex_key.privateKeyFile.String()
 	if actual_privkey != expected_privkey {
 		t.Errorf("wrong private key path. expected %q. actual %q", expected_privkey, actual_privkey)
 	}
diff --git a/apex/builder.go b/apex/builder.go
index 9db8e59..0e4ba1d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -577,8 +577,8 @@
 		fileContexts := a.buildFileContexts(ctx)
 		implicitInputs = append(implicitInputs, fileContexts)
 
-		implicitInputs = append(implicitInputs, a.private_key_file, a.public_key_file)
-		optFlags = append(optFlags, "--pubkey "+a.public_key_file.String())
+		implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
+		optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
 
 		manifestPackageName := a.getOverrideManifestPackageName(ctx)
 		if manifestPackageName != "" {
@@ -667,7 +667,7 @@
 				"manifest":         a.manifestPbOut.String(),
 				"file_contexts":    fileContexts.String(),
 				"canned_fs_config": cannedFsConfig.String(),
-				"key":              a.private_key_file.String(),
+				"key":              a.privateKeyFile.String(),
 				"opt_flags":        strings.Join(optFlags, " "),
 			},
 		})
@@ -842,8 +842,8 @@
 // the zip container of this APEX. See the description of the 'certificate' property for how
 // the cert and the private key are found.
 func (a *apexBundle) getCertificateAndPrivateKey(ctx android.PathContext) (pem, key android.Path) {
-	if a.container_certificate_file != nil {
-		return a.container_certificate_file, a.container_private_key_file
+	if a.containerCertificateFile != nil {
+		return a.containerCertificateFile, a.containerPrivateKeyFile
 	}
 
 	cert := String(a.properties.Certificate)
diff --git a/apex/key.go b/apex/key.go
index d9e3c10..752888d 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -36,8 +36,8 @@
 
 	properties apexKeyProperties
 
-	public_key_file  android.Path
-	private_key_file android.Path
+	publicKeyFile  android.Path
+	privateKeyFile android.Path
 
 	keyName string
 }
@@ -69,30 +69,30 @@
 	// Otherwise, try to locate the key files in the default cert dir or
 	// in the local module dir
 	if android.SrcIsModule(String(m.properties.Public_key)) != "" {
-		m.public_key_file = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
+		m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
 	} else {
-		m.public_key_file = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key))
+		m.publicKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key))
 		// If not found, fall back to the local key pairs
-		if !android.ExistentPathForSource(ctx, m.public_key_file.String()).Valid() {
-			m.public_key_file = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
+		if !android.ExistentPathForSource(ctx, m.publicKeyFile.String()).Valid() {
+			m.publicKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Public_key))
 		}
 	}
 
 	if android.SrcIsModule(String(m.properties.Private_key)) != "" {
-		m.private_key_file = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
+		m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
 	} else {
-		m.private_key_file = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key))
-		if !android.ExistentPathForSource(ctx, m.private_key_file.String()).Valid() {
-			m.private_key_file = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
+		m.privateKeyFile = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key))
+		if !android.ExistentPathForSource(ctx, m.privateKeyFile.String()).Valid() {
+			m.privateKeyFile = android.PathForModuleSrc(ctx, String(m.properties.Private_key))
 		}
 	}
 
-	pubKeyName := m.public_key_file.Base()[0 : len(m.public_key_file.Base())-len(m.public_key_file.Ext())]
-	privKeyName := m.private_key_file.Base()[0 : len(m.private_key_file.Base())-len(m.private_key_file.Ext())]
+	pubKeyName := m.publicKeyFile.Base()[0 : len(m.publicKeyFile.Base())-len(m.publicKeyFile.Ext())]
+	privKeyName := m.privateKeyFile.Base()[0 : len(m.privateKeyFile.Base())-len(m.privateKeyFile.Ext())]
 
 	if m.properties.Public_key != nil && m.properties.Private_key != nil && pubKeyName != privKeyName {
 		ctx.ModuleErrorf("public_key %q (keyname:%q) and private_key %q (keyname:%q) do not have same keyname",
-			m.public_key_file.String(), pubKeyName, m.private_key_file, privKeyName)
+			m.publicKeyFile.String(), pubKeyName, m.privateKeyFile, privKeyName)
 		return
 	}
 	m.keyName = pubKeyName
@@ -107,20 +107,20 @@
 func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
 	s.output = android.PathForOutput(ctx, "apexkeys.txt")
 	type apexKeyEntry struct {
-		name                  string
-		presigned             bool
-		public_key            string
-		private_key           string
-		container_certificate string
-		container_private_key string
-		partition             string
+		name                 string
+		presigned            bool
+		publicKey            string
+		privateKey           string
+		containerCertificate string
+		containerPrivateKey  string
+		partition            string
 	}
 	toString := func(e apexKeyEntry) string {
 		format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\n"
 		if e.presigned {
 			return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition)
 		} else {
-			return fmt.Sprintf(format, e.name, e.public_key, e.private_key, e.container_certificate, e.container_private_key, e.partition)
+			return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition)
 		}
 	}
 
@@ -129,13 +129,13 @@
 		if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() {
 			pem, key := m.getCertificateAndPrivateKey(ctx)
 			apexKeyMap[m.Name()] = apexKeyEntry{
-				name:                  m.Name() + ".apex",
-				presigned:             false,
-				public_key:            m.public_key_file.String(),
-				private_key:           m.private_key_file.String(),
-				container_certificate: pem.String(),
-				container_private_key: key.String(),
-				partition:             m.PartitionTag(ctx.DeviceConfig()),
+				name:                 m.Name() + ".apex",
+				presigned:            false,
+				publicKey:            m.publicKeyFile.String(),
+				privateKey:           m.privateKeyFile.String(),
+				containerCertificate: pem.String(),
+				containerPrivateKey:  key.String(),
+				partition:            m.PartitionTag(ctx.DeviceConfig()),
 			}
 		}
 	})
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index faec473..94b8252 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -784,9 +784,9 @@
 			return nil
 		}
 
-		bool_variables, ok := getLiteralListProperty(mod, "bool_variables")
+		boolVariables, ok := getLiteralListProperty(mod, "bool_variables")
 		if ok {
-			patchList.Add(bool_variables.RBracePos.Offset, bool_variables.RBracePos.Offset, ","+boolValues.String())
+			patchList.Add(boolVariables.RBracePos.Offset, boolVariables.RBracePos.Offset, ","+boolValues.String())
 		} else {
 			patchList.Add(variables.RBracePos.Offset+2, variables.RBracePos.Offset+2,
 				fmt.Sprintf(`bool_variables: [%s],`, boolValues.String()))
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ddacb70..4ada55d 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -232,8 +232,8 @@
 			if len(library.Properties.Overrides) > 0 {
 				entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
 			}
-			if len(library.post_install_cmds) > 0 {
-				entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.post_install_cmds, "&& "))
+			if len(library.postInstallCmds) > 0 {
+				entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.postInstallCmds, "&& "))
 			}
 		})
 	} else if library.header() {
@@ -269,7 +269,7 @@
 	if library.shared() && !library.buildStubs() {
 		ctx.subAndroidMk(entries, library.baseInstaller)
 	} else {
-		if library.buildStubs() {
+		if library.buildStubs() && library.stubsVersion() != "" {
 			entries.SubName = "." + library.stubsVersion()
 		}
 		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
@@ -328,8 +328,8 @@
 		if len(binary.Properties.Overrides) > 0 {
 			entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
 		}
-		if len(binary.post_install_cmds) > 0 {
-			entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.post_install_cmds, "&& "))
+		if len(binary.postInstallCmds) > 0 {
+			entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.postInstallCmds, "&& "))
 		}
 	})
 }
@@ -471,18 +471,9 @@
 }
 
 func (c *llndkStubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
-	entries.Class = "SHARED_LIBRARIES"
-	entries.OverrideName = c.implementationModuleName(ctx.BaseModuleName())
-
-	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
-		c.libraryDecorator.androidMkWriteExportedFlags(entries)
-		_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
-
-		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
-		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
-		entries.SetString("LOCAL_SOONG_TOC", c.toc().String())
-	})
+	// Don't write anything for an llndk_library module, the vendor variant of the cc_library
+	// module will write the Android.mk entries.
+	entries.Disabled = true
 }
 
 func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
diff --git a/cc/binary.go b/cc/binary.go
index fa3966f..71c865b 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -109,7 +109,7 @@
 
 	// Action command lines to run directly after the binary is installed. For example,
 	// may be used to symlink runtime dependencies (such as bionic) alongside installation.
-	post_install_cmds []string
+	postInstallCmds []string
 }
 
 var _ linker = (*binaryDecorator)(nil)
@@ -481,11 +481,11 @@
 	target := "/" + filepath.Join("apex", "com.android.runtime", dir.Base(), file.Base())
 
 	ctx.InstallAbsoluteSymlink(dir, file.Base(), target)
-	binary.post_install_cmds = append(binary.post_install_cmds, makeSymlinkCmd(dirOnDevice, file.Base(), target))
+	binary.postInstallCmds = append(binary.postInstallCmds, makeSymlinkCmd(dirOnDevice, file.Base(), target))
 
 	for _, symlink := range binary.symlinks {
 		ctx.InstallAbsoluteSymlink(dir, symlink, target)
-		binary.post_install_cmds = append(binary.post_install_cmds, makeSymlinkCmd(dirOnDevice, symlink, target))
+		binary.postInstallCmds = append(binary.postInstallCmds, makeSymlinkCmd(dirOnDevice, symlink, target))
 	}
 }
 
diff --git a/cc/cc.go b/cc/cc.go
index 1cc2bd5..a023f3f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -390,6 +390,13 @@
 	// explicitly marked as `double_loadable: true` by the owner, or the dependency
 	// from the LLNDK lib should be cut if the lib is not designed to be double loaded.
 	Double_loadable *bool
+
+	// IsLLNDK is set to true for the vendor variant of a cc_library module that has LLNDK stubs.
+	IsLLNDK bool `blueprint:"mutated"`
+
+	// IsLLNDKPrivate is set to true for the vendor variant of a cc_library module that has LLNDK
+	// stubs and also sets llndk.vendor_available: false.
+	IsLLNDKPrivate bool `blueprint:"mutated"`
 }
 
 // ModuleContextIntf is an interface (on a module context helper) consisting of functions related
@@ -408,9 +415,10 @@
 	sdkVersion() string
 	useVndk() bool
 	isNdk(config android.Config) bool
-	isLlndk(config android.Config) bool
-	isLlndkPublic(config android.Config) bool
-	isVndkPrivate(config android.Config) bool
+	IsLlndk() bool
+	IsLlndkPublic() bool
+	isImplementationForLLNDKPublic() bool
+	IsVndkPrivate() bool
 	isVndk() bool
 	isVndkSp() bool
 	IsVndkExt() bool
@@ -645,6 +653,7 @@
 	runtimeDepTag         = installDependencyTag{name: "runtime lib"}
 	testPerSrcDepTag      = dependencyTag{name: "test_per_src"}
 	stubImplDepTag        = dependencyTag{name: "stub_impl"}
+	llndkStubDepTag       = dependencyTag{name: "llndk stub"}
 )
 
 type copyDirectlyInAnyApexDependencyTag dependencyTag
@@ -1028,20 +1037,34 @@
 	return inList(c.BaseModuleName(), *getNDKKnownLibs(config))
 }
 
-func (c *Module) isLlndk(config android.Config) bool {
-	// Returns true for both LLNDK (public) and LLNDK-private libs.
-	return isLlndkLibrary(c.BaseModuleName(), config)
+// isLLndk returns true for both LLNDK (public) and LLNDK-private libs.
+func (c *Module) IsLlndk() bool {
+	return c.VendorProperties.IsLLNDK
 }
 
-func (c *Module) isLlndkPublic(config android.Config) bool {
-	// Returns true only for LLNDK (public) libs.
-	name := c.BaseModuleName()
-	return isLlndkLibrary(name, config) && !isVndkPrivateLibrary(name, config)
+// IsLlndkPublic returns true only for LLNDK (public) libs.
+func (c *Module) IsLlndkPublic() bool {
+	return c.VendorProperties.IsLLNDK && !c.VendorProperties.IsLLNDKPrivate
 }
 
-func (c *Module) IsVndkPrivate(config android.Config) bool {
+// isImplementationForLLNDKPublic returns true for any variant of a cc_library that has LLNDK stubs
+// and does not set llndk.vendor_available: false.
+func (c *Module) isImplementationForLLNDKPublic() bool {
+	library, _ := c.library.(*libraryDecorator)
+	return library != nil && library.hasLLNDKStubs() &&
+		(Bool(library.Properties.Llndk.Vendor_available) ||
+			// TODO(b/170784825): until the LLNDK properties are moved into the cc_library,
+			// the non-Vendor variants of the cc_library don't know if the corresponding
+			// llndk_library set vendor_available: false.  Since libft2 is the only
+			// private LLNDK library, hardcode it during the transition.
+			c.BaseModuleName() != "libft2")
+}
+
+func (c *Module) IsVndkPrivate() bool {
 	// Returns true for LLNDK-private, VNDK-SP-private, and VNDK-core-private.
-	return isVndkPrivateLibrary(c.BaseModuleName(), config)
+	library, _ := c.library.(*libraryDecorator)
+	return library != nil && !Bool(library.Properties.Llndk.Vendor_available) &&
+		!Bool(c.VendorProperties.Vendor_available) && !c.IsVndkExt()
 }
 
 func (c *Module) IsVndk() bool {
@@ -1247,16 +1270,20 @@
 	return ctx.mod.IsNdk(config)
 }
 
-func (ctx *moduleContextImpl) isLlndk(config android.Config) bool {
-	return ctx.mod.isLlndk(config)
+func (ctx *moduleContextImpl) IsLlndk() bool {
+	return ctx.mod.IsLlndk()
 }
 
-func (ctx *moduleContextImpl) isLlndkPublic(config android.Config) bool {
-	return ctx.mod.isLlndkPublic(config)
+func (ctx *moduleContextImpl) IsLlndkPublic() bool {
+	return ctx.mod.IsLlndkPublic()
 }
 
-func (ctx *moduleContextImpl) isVndkPrivate(config android.Config) bool {
-	return ctx.mod.IsVndkPrivate(config)
+func (ctx *moduleContextImpl) isImplementationForLLNDKPublic() bool {
+	return ctx.mod.isImplementationForLLNDKPublic()
+}
+
+func (ctx *moduleContextImpl) IsVndkPrivate() bool {
+	return ctx.mod.IsVndkPrivate()
 }
 
 func (ctx *moduleContextImpl) isVndk() bool {
@@ -1407,7 +1434,7 @@
 	if vndkVersion == "current" {
 		vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
 	}
-	if c.Properties.VndkVersion != vndkVersion {
+	if c.Properties.VndkVersion != vndkVersion && c.Properties.VndkVersion != "" {
 		// add version suffix only if the module is using different vndk version than the
 		// version in product or vendor partition.
 		nameSuffix += "." + c.Properties.VndkVersion
@@ -1439,7 +1466,7 @@
 		c.Properties.SubName += nativeBridgeSuffix
 	}
 
-	_, llndk := c.linker.(*llndkStubDecorator)
+	llndk := c.IsLlndk()
 	_, llndkHeader := c.linker.(*llndkHeadersDecorator)
 	if llndk || llndkHeader || (c.UseVndk() && c.HasNonSystemVariants()) {
 		// .vendor.{version} suffix is added for vendor variant or .product.{version} suffix is
@@ -1817,10 +1844,6 @@
 		vendorSnapshotSharedLibs := vendorSnapshotSharedLibs(actx.Config())
 
 		rewriteVendorLibs := func(lib string) string {
-			if isLlndkLibrary(lib, ctx.Config()) {
-				return lib + llndkLibrarySuffix
-			}
-
 			// only modules with BOARD_VNDK_VERSION uses snapshot.
 			if c.VndkVersion() != actx.DeviceConfig().VndkVersion() {
 				return lib
@@ -2237,7 +2260,7 @@
 			return true
 		}
 
-		if to.isVndkSp() || to.isLlndk(ctx.Config()) || Bool(to.VendorProperties.Double_loadable) {
+		if to.isVndkSp() || to.IsLlndk() || Bool(to.VendorProperties.Double_loadable) {
 			return false
 		}
 
@@ -2252,7 +2275,7 @@
 	}
 	if module, ok := ctx.Module().(*Module); ok {
 		if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() {
-			if module.isLlndk(ctx.Config()) || Bool(module.VendorProperties.Double_loadable) {
+			if lib.hasLLNDKStubs() || Bool(module.VendorProperties.Double_loadable) {
 				ctx.WalkDeps(check)
 			}
 		}
@@ -2372,9 +2395,6 @@
 		if depTag == android.ProtoPluginDepTag {
 			return
 		}
-		if depTag == llndkImplDep {
-			return
-		}
 
 		if dep.Target().Os != ctx.Os() {
 			ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
@@ -2744,7 +2764,8 @@
 	vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
 
 	libName := baseLibName(depName)
-	isLLndk := isLlndkLibrary(libName, ctx.Config())
+	ccDepModule, _ := ccDep.(*Module)
+	isLLndk := ccDepModule != nil && ccDepModule.IsLlndk()
 	isVendorPublicLib := inList(libName, *vendorPublicLibraries)
 	bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
 
@@ -2896,17 +2917,14 @@
 
 func GetMakeLinkType(actx android.ModuleContext, c LinkableInterface) string {
 	if c.UseVndk() {
-		if ccModule, ok := c.Module().(*Module); ok {
-			// Only CC modules provide stubs at the moment.
-			if lib, ok := ccModule.linker.(*llndkStubDecorator); ok {
-				if Bool(lib.Properties.Vendor_available) {
-					return "native:vndk"
-				}
+		if c.IsLlndk() {
+			if !c.IsLlndkPublic() {
 				return "native:vndk_private"
 			}
+			return "native:vndk"
 		}
 		if c.IsVndk() && !c.IsVndkExt() {
-			if c.IsVndkPrivate(actx.Config()) {
+			if c.IsVndkPrivate() {
 				return "native:vndk_private"
 			}
 			return "native:vndk"
@@ -3039,7 +3057,7 @@
 			return false
 		}
 	}
-	if depTag == stubImplDepTag || depTag == llndkImplDep {
+	if depTag == stubImplDepTag || depTag == llndkStubDepTag {
 		// We don't track beyond LLNDK or from an implementation library to its stubs.
 		return false
 	}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index c16cce8..fe9db37 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -1049,6 +1049,16 @@
 		name: "obj",
 		vendor_available: true,
 	}
+
+	cc_library {
+		name: "libllndk",
+		llndk_stubs: "libllndk.llndk",
+	}
+
+	llndk_library {
+		name: "libllndk.llndk",
+		symbol_file: "",
+	}
 `
 	config := TestConfig(buildDir, android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
@@ -1080,6 +1090,9 @@
 			filepath.Join(sharedDir, "libvendor.so.json"),
 			filepath.Join(sharedDir, "libvendor_available.so.json"))
 
+		// LLNDK modules are not captured
+		checkSnapshotExclude(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", sharedDir, sharedVariant)
+
 		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
 		// Also cfi variants are captured, except for prebuilts like toolchain_library
 		staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
@@ -2899,7 +2912,7 @@
 		{vendorVariant, "libvndkprivate", "native:vndk_private"},
 		{vendorVariant, "libvendor", "native:vendor"},
 		{vendorVariant, "libvndkext", "native:vendor"},
-		{vendorVariant, "libllndk.llndk", "native:vndk"},
+		{vendorVariant, "libllndk", "native:vndk"},
 		{vendorVariant27, "prevndk.vndk.27.arm.binder32", "native:vndk"},
 		{coreVariant, "libvndk", "native:platform"},
 		{coreVariant, "libvndkprivate", "native:platform"},
@@ -3178,8 +3191,39 @@
 	llndk_library {
 		name: "libllndk.llndk",
 	}
+
+	cc_prebuilt_library_shared {
+		name: "libllndkprebuilt",
+		stubs: { versions: ["1", "2"] },
+		llndk_stubs: "libllndkprebuilt.llndk",
+	}
+	llndk_library {
+		name: "libllndkprebuilt.llndk",
+	}
+
+	cc_library {
+		name: "libllndk_with_external_headers",
+		stubs: { versions: ["1", "2"] },
+		llndk_stubs: "libllndk_with_external_headers.llndk",
+		header_libs: ["libexternal_headers"],
+		export_header_lib_headers: ["libexternal_headers"],
+	}
+	llndk_library {
+		name: "libllndk_with_external_headers.llndk",
+	}
+	cc_library_headers {
+		name: "libexternal_headers",
+		export_include_dirs: ["include"],
+		vendor_available: true,
+	}
 	`)
-	actual := ctx.ModuleVariantsForTests("libllndk.llndk")
+	actual := ctx.ModuleVariantsForTests("libllndk")
+	for i := 0; i < len(actual); i++ {
+		if !strings.HasPrefix(actual[i], "android_vendor.VER_") {
+			actual = append(actual[:i], actual[i+1:]...)
+			i--
+		}
+	}
 	expected := []string{
 		"android_vendor.VER_arm64_armv8-a_shared_1",
 		"android_vendor.VER_arm64_armv8-a_shared_2",
@@ -3190,10 +3234,10 @@
 	}
 	checkEquals(t, "variants for llndk stubs", expected, actual)
 
-	params := ctx.ModuleForTests("libllndk.llndk", "android_vendor.VER_arm_armv7-a-neon_shared").Description("generate stub")
+	params := ctx.ModuleForTests("libllndk", "android_vendor.VER_arm_armv7-a-neon_shared").Description("generate stub")
 	checkEquals(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"])
 
-	params = ctx.ModuleForTests("libllndk.llndk", "android_vendor.VER_arm_armv7-a-neon_shared_1").Description("generate stub")
+	params = ctx.ModuleForTests("libllndk", "android_vendor.VER_arm_armv7-a-neon_shared_1").Description("generate stub")
 	checkEquals(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"])
 }
 
diff --git a/cc/check.go b/cc/check.go
index 0058b8c..a357a97 100644
--- a/cc/check.go
+++ b/cc/check.go
@@ -104,7 +104,7 @@
 
 // Check for bad host_ldlibs
 func CheckBadHostLdlibs(ctx ModuleContext, prop string, flags []string) {
-	allowed_ldlibs := ctx.toolchain().AvailableLibraries()
+	allowedLdlibs := ctx.toolchain().AvailableLibraries()
 
 	if !ctx.Host() {
 		panic("Invalid call to CheckBadHostLdlibs")
@@ -116,7 +116,7 @@
 		// TODO: Probably should just redo this property to prefix -l in Soong
 		if !strings.HasPrefix(flag, "-l") && !strings.HasPrefix(flag, "-framework") {
 			ctx.PropertyErrorf(prop, "Invalid flag: `%s`, must start with `-l` or `-framework`", flag)
-		} else if !inList(flag, allowed_ldlibs) {
+		} else if !inList(flag, allowedLdlibs) {
 			ctx.PropertyErrorf(prop, "Host library `%s` not available", flag)
 		}
 	}
diff --git a/cc/cmakelists.go b/cc/cmakelists.go
index f7d9081..d441c57 100644
--- a/cc/cmakelists.go
+++ b/cc/cmakelists.go
@@ -125,15 +125,15 @@
 	}
 
 	// Only write CMakeLists.txt for the first variant of each architecture of each module
-	clionproject_location := getCMakeListsForModule(ccModule, ctx)
-	if seenProjects[clionproject_location] {
+	clionprojectLocation := getCMakeListsForModule(ccModule, ctx)
+	if seenProjects[clionprojectLocation] {
 		return
 	}
 
-	seenProjects[clionproject_location] = true
+	seenProjects[clionprojectLocation] = true
 
 	// Ensure the directory hosting the cmakelists.txt exists
-	projectDir := path.Dir(clionproject_location)
+	projectDir := path.Dir(clionprojectLocation)
 	os.MkdirAll(projectDir, os.ModePerm)
 
 	// Create cmakelists.txt
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 8a0d7bd..4bcad4b 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -22,6 +22,7 @@
 	"android.hardware.light-ndk_platform",
 	"android.hardware.identity-ndk_platform",
 	"android.hardware.nfc@1.2",
+	"android.hardware.memtrack-unstable-ndk_platform",
 	"android.hardware.power-ndk_platform",
 	"android.hardware.rebootescrow-ndk_platform",
 	"android.hardware.security.keymint-unstable-ndk_platform",
diff --git a/cc/image.go b/cc/image.go
index cca454a..380c1db 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -308,6 +308,18 @@
 		} else {
 			vendorVariants = append(vendorVariants, platformVndkVersion)
 		}
+	} else if lib := moduleLibraryInterface(m); lib != nil && lib.hasLLNDKStubs() {
+		// This is an LLNDK library.  The implementation of the library will be on /system,
+		// and vendor and product variants will be created with LLNDK stubs.
+		coreVariantNeeded = true
+		vendorVariants = append(vendorVariants,
+			platformVndkVersion,
+			boardVndkVersion,
+		)
+		productVariants = append(productVariants,
+			platformVndkVersion,
+			productVndkVersion,
+		)
 	} else {
 		// This is either in /system (or similar: /data), or is a
 		// modules built with the NDK. Modules built with the NDK
diff --git a/cc/library.go b/cc/library.go
index 11ee7dd..f4400a9 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -22,6 +22,7 @@
 	"strings"
 	"sync"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
@@ -114,6 +115,10 @@
 
 	// If this is an LLNDK library, the name of the equivalent llndk_library module.
 	Llndk_stubs *string
+
+	// If this is an LLNDK library, properties to describe the LLNDK stubs.  Will be copied from
+	// the module pointed to by llndk_stubs if it is set.
+	Llndk llndkLibraryProperties
 }
 
 // StaticProperties is a properties stanza to affect only attributes of the "static" variants of a
@@ -382,7 +387,7 @@
 
 	versionScriptPath android.OptionalPath
 
-	post_install_cmds []string
+	postInstallCmds []string
 
 	// If useCoreVariant is true, the vendor variant of a VNDK library is
 	// not installed.
@@ -570,6 +575,12 @@
 	}
 
 	flags = library.baseCompiler.compilerFlags(ctx, flags, deps)
+	if ctx.IsLlndk() {
+		// LLNDK libraries ignore most of the properties on the cc_library and use the
+		// LLNDK-specific properties instead.
+		// Wipe all the module-local properties, leaving only the global properties.
+		flags.Local = LocalOrGlobalFlags{}
+	}
 	if library.buildStubs() {
 		// Remove -include <file> when compiling stubs. Otherwise, the force included
 		// headers might cause conflicting types error with the symbols in the
@@ -603,6 +614,22 @@
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+	if ctx.IsLlndk() {
+		// This is the vendor variant of an LLNDK library, build the LLNDK stubs.
+		vndkVer := ctx.Module().(*Module).VndkVersion()
+		if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" {
+			// For non-enforcing devices, vndkVer is empty. Use "current" in that case, too.
+			vndkVer = "current"
+		}
+		if library.stubsVersion() != "" {
+			vndkVer = library.stubsVersion()
+		}
+		objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Llndk.Symbol_file), vndkVer, "--llndk")
+		if !Bool(library.Properties.Llndk.Unversioned) {
+			library.versionScriptPath = android.OptionalPathForPath(versionScript)
+		}
+		return objs
+	}
 	if library.buildStubs() {
 		objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "--apex")
 		library.versionScriptPath = android.OptionalPathForPath(versionScript)
@@ -631,9 +658,9 @@
 			SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude)
 		}
 		flags.SAbiFlags = SourceAbiFlags
-		total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) +
+		totalLength := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) +
 			len(library.SharedProperties.Shared.Srcs) + len(library.StaticProperties.Static.Srcs)
-		if total_length > 0 {
+		if totalLength > 0 {
 			flags.SAbiDump = true
 		}
 	}
@@ -693,6 +720,7 @@
 	allStubsVersions() []string
 
 	implementationModuleName(name string) string
+	hasLLNDKStubs() bool
 }
 
 var _ libraryInterface = (*libraryDecorator)(nil)
@@ -768,12 +796,27 @@
 }
 
 func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
+	if ctx.IsLlndk() {
+		// LLNDK libraries ignore most of the properties on the cc_library and use the
+		// LLNDK-specific properties instead.
+		return deps
+	}
+
 	deps = library.baseCompiler.compilerDeps(ctx, deps)
 
 	return deps
 }
 
 func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
+	if ctx.IsLlndk() {
+		// LLNDK libraries ignore most of the properties on the cc_library and use the
+		// LLNDK-specific properties instead.
+		deps.HeaderLibs = append(deps.HeaderLibs, library.Properties.Llndk.Export_llndk_headers...)
+		deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders,
+			library.Properties.Llndk.Export_llndk_headers...)
+		return deps
+	}
+
 	if library.static() {
 		// Compare with nil because an empty list needs to be propagated.
 		if library.StaticProperties.Static.System_shared_libs != nil {
@@ -977,7 +1020,12 @@
 	transformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
 
 	stripFlags := flagsToStripFlags(flags)
-	if library.stripper.NeedsStrip(ctx) {
+	needsStrip := library.stripper.NeedsStrip(ctx)
+	if library.buildStubs() {
+		// No need to strip stubs libraries
+		needsStrip = false
+	}
+	if needsStrip {
 		if ctx.Darwin() {
 			stripFlags.StripUseGnuStrip = true
 		}
@@ -1017,7 +1065,7 @@
 	linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
 	linkerDeps = append(linkerDeps, objs.tidyFiles...)
 
-	if Bool(library.Properties.Sort_bss_symbols_by_size) {
+	if Bool(library.Properties.Sort_bss_symbols_by_size) && !library.buildStubs() {
 		unsortedOutputFile := android.PathForModuleOut(ctx, "unsorted", fileName)
 		transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
 			deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
@@ -1071,7 +1119,7 @@
 		ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
 			SharedStubLibraries: stubsInfo,
 
-			IsLLNDK: ctx.isLlndk(ctx.Config()),
+			IsLLNDK: ctx.IsLlndk(),
 		})
 	}
 
@@ -1100,7 +1148,7 @@
 func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
 	// The logic must be consistent with classifySourceAbiDump.
 	isNdk := ctx.isNdk(ctx.Config())
-	isLlndkOrVndk := ctx.isLlndkPublic(ctx.Config()) || (ctx.useVndk() && ctx.isVndk())
+	isLlndkOrVndk := ctx.IsLlndkPublic() || (ctx.useVndk() && ctx.isVndk())
 
 	refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, false)
 	refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, true)
@@ -1153,17 +1201,64 @@
 			library.sAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
 				refAbiDumpFile, fileName, exportedHeaderFlags,
 				Bool(library.Properties.Header_abi_checker.Check_all_apis),
-				ctx.isLlndk(ctx.Config()), ctx.isNdk(ctx.Config()), ctx.IsVndkExt())
+				ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt())
 		}
 	}
 }
 
+func processLLNDKHeaders(ctx ModuleContext, srcHeaderDir string, outDir android.ModuleGenPath) android.Path {
+	srcDir := android.PathForModuleSrc(ctx, srcHeaderDir)
+	srcFiles := ctx.GlobFiles(filepath.Join(srcDir.String(), "**/*.h"), nil)
+
+	var installPaths []android.WritablePath
+	for _, header := range srcFiles {
+		headerDir := filepath.Dir(header.String())
+		relHeaderDir, err := filepath.Rel(srcDir.String(), headerDir)
+		if err != nil {
+			ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s",
+				srcDir.String(), headerDir, err)
+			continue
+		}
+
+		installPaths = append(installPaths, outDir.Join(ctx, relHeaderDir, header.Base()))
+	}
+
+	return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths)
+}
+
 // link registers actions to link this library, and sets various fields
 // on this library to reflect information that should be exported up the build
 // tree (for example, exported flags and include paths).
 func (library *libraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
+	if ctx.IsLlndk() {
+		if len(library.Properties.Llndk.Export_preprocessed_headers) > 0 {
+			// This is the vendor variant of an LLNDK library with preprocessed headers.
+			genHeaderOutDir := android.PathForModuleGen(ctx, "include")
+
+			var timestampFiles android.Paths
+			for _, dir := range library.Properties.Llndk.Export_preprocessed_headers {
+				timestampFiles = append(timestampFiles, processLLNDKHeaders(ctx, dir, genHeaderOutDir))
+			}
+
+			if Bool(library.Properties.Llndk.Export_headers_as_system) {
+				library.reexportSystemDirs(genHeaderOutDir)
+			} else {
+				library.reexportDirs(genHeaderOutDir)
+			}
+
+			library.reexportDeps(timestampFiles...)
+		}
+
+		if Bool(library.Properties.Llndk.Export_headers_as_system) {
+			library.flagExporter.Properties.Export_system_include_dirs = append(
+				library.flagExporter.Properties.Export_system_include_dirs,
+				library.flagExporter.Properties.Export_include_dirs...)
+			library.flagExporter.Properties.Export_include_dirs = nil
+		}
+	}
+
 	// Linking this library consists of linking `deps.Objs` (.o files in dependencies
 	// of this library), together with `objs` (.o files created by compiling this
 	// library).
@@ -1246,7 +1341,7 @@
 }
 
 func (library *libraryDecorator) exportVersioningMacroIfNeeded(ctx android.BaseModuleContext) {
-	if library.buildStubs() && !library.skipAPIDefine {
+	if library.buildStubs() && library.stubsVersion() != "" && !library.skipAPIDefine {
 		name := versioningMacroName(ctx.Module().(*Module).ImplementationModuleName(ctx))
 		ver := library.stubsVersion()
 		library.reexportFlags("-D" + name + "=" + ver)
@@ -1282,7 +1377,7 @@
 	dirOnDevice := android.InstallPathToOnDevicePath(ctx, dir)
 	target := "/" + filepath.Join("apex", "com.android.runtime", dir.Base(), "bionic", file.Base())
 	ctx.InstallAbsoluteSymlink(dir, file.Base(), target)
-	library.post_install_cmds = append(library.post_install_cmds, makeSymlinkCmd(dirOnDevice, file.Base(), target))
+	library.postInstallCmds = append(library.postInstallCmds, makeSymlinkCmd(dirOnDevice, file.Base(), target))
 }
 
 func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
@@ -1334,7 +1429,7 @@
 				}
 				library.baseInstaller.subDir = "bootstrap"
 			}
-		} else if ctx.directlyInAnyApex() && ctx.isLlndk(ctx.Config()) && !isBionic(ctx.baseModuleName()) {
+		} else if ctx.directlyInAnyApex() && ctx.IsLlndk() && !isBionic(ctx.baseModuleName()) {
 			// Skip installing LLNDK (non-bionic) libraries moved to APEX.
 			ctx.Module().HideFromMake()
 		}
@@ -1411,6 +1506,11 @@
 	library.MutatedProperties.BuildStatic = false
 }
 
+// hasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs.
+func (library *libraryDecorator) hasLLNDKStubs() bool {
+	return String(library.Properties.Llndk_stubs) != ""
+}
+
 func (library *libraryDecorator) implementationModuleName(name string) string {
 	return name
 }
@@ -1423,6 +1523,9 @@
 	if library.Properties.Header_abi_checker.Symbol_file != nil {
 		return library.Properties.Header_abi_checker.Symbol_file
 	}
+	if ctx.Module().(*Module).IsLlndk() {
+		return library.Properties.Llndk.Symbol_file
+	}
 	if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
 		return library.Properties.Stubs.Symbol_file
 	}
@@ -1579,15 +1682,17 @@
 // LinkageMutator adds "static" or "shared" variants for modules depending
 // on whether the module can be built as a static library or a shared library.
 func LinkageMutator(mctx android.BottomUpMutatorContext) {
-	cc_prebuilt := false
+	ccPrebuilt := false
 	if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
-		_, cc_prebuilt = m.linker.(prebuiltLibraryInterface)
+		_, ccPrebuilt = m.linker.(prebuiltLibraryInterface)
 	}
-	if cc_prebuilt {
+	if ccPrebuilt {
 		library := mctx.Module().(*Module).linker.(prebuiltLibraryInterface)
 
 		// Differentiate between header only and building an actual static/shared library
-		if library.buildStatic() || library.buildShared() {
+		buildStatic := library.buildStatic()
+		buildShared := library.buildShared()
+		if buildStatic || buildShared {
 			// Always create both the static and shared variants for prebuilt libraries, and then disable the one
 			// that is not being used.  This allows them to share the name of a cc_library module, which requires that
 			// all the variants of the cc_library also exist on the prebuilt.
@@ -1598,16 +1703,16 @@
 			static.linker.(prebuiltLibraryInterface).setStatic()
 			shared.linker.(prebuiltLibraryInterface).setShared()
 
-			if library.buildShared() {
+			if buildShared {
 				mctx.AliasVariation("shared")
-			} else if library.buildStatic() {
+			} else if buildStatic {
 				mctx.AliasVariation("static")
 			}
 
-			if !library.buildStatic() {
+			if !buildStatic {
 				static.linker.(prebuiltLibraryInterface).disablePrebuilt()
 			}
-			if !library.buildShared() {
+			if !buildShared {
 				shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
 			}
 		} else {
@@ -1622,7 +1727,18 @@
 			variations = append(variations, "")
 		}
 
-		if library.BuildStaticVariant() && library.BuildSharedVariant() {
+		isLLNDK := false
+		if m, ok := mctx.Module().(*Module); ok {
+			isLLNDK = m.IsLlndk()
+			// Don't count the vestigial llndk_library module as isLLNDK, it needs a static
+			// variant so that a cc_library_prebuilt can depend on it.
+			if _, ok := m.linker.(*llndkStubDecorator); ok {
+				isLLNDK = false
+			}
+		}
+		buildStatic := library.BuildStaticVariant() && !isLLNDK
+		buildShared := library.BuildSharedVariant()
+		if buildStatic && buildShared {
 			variations := append([]string{"static", "shared"}, variations...)
 
 			modules := mctx.CreateLocalVariations(variations...)
@@ -1636,13 +1752,13 @@
 				reuseStaticLibrary(mctx, static.(*Module), shared.(*Module))
 			}
 			mctx.AliasVariation("shared")
-		} else if library.BuildStaticVariant() {
+		} else if buildStatic {
 			variations := append([]string{"static"}, variations...)
 
 			modules := mctx.CreateLocalVariations(variations...)
 			modules[0].(LinkableInterface).SetStatic()
 			mctx.AliasVariation("static")
-		} else if library.BuildSharedVariant() {
+		} else if buildShared {
 			variations := append([]string{"shared"}, variations...)
 
 			modules := mctx.CreateLocalVariations(variations...)
@@ -1675,22 +1791,32 @@
 }
 
 func createVersionVariations(mctx android.BottomUpMutatorContext, versions []string) {
-	// "" is for the non-stubs (implementation) variant.
+	// "" is for the non-stubs (implementation) variant for system modules, or the LLNDK variant
+	// for LLNDK modules.
 	variants := append(android.CopyOf(versions), "")
 
+	m := mctx.Module().(*Module)
+	isLLNDK := m.IsLlndk()
+
 	modules := mctx.CreateLocalVariations(variants...)
 	for i, m := range modules {
-		if variants[i] != "" {
+
+		if variants[i] != "" || isLLNDK {
+			// A stubs or LLNDK stubs variant.
 			c := m.(*Module)
-			c.Properties.HideFromMake = true
 			c.sanitize = nil
 			c.stl = nil
 			c.Properties.PreventInstall = true
 			lib := moduleLibraryInterface(m)
 			lib.setBuildStubs()
-			lib.setStubsVersion(variants[i])
-			// The implementation depends on the stubs
-			mctx.AddInterVariantDependency(stubImplDepTag, modules[len(modules)-1], modules[i])
+
+			if variants[i] != "" {
+				// A non-LLNDK stubs module is hidden from make and has a dependency from the
+				// implementation module to the stubs module.
+				c.Properties.HideFromMake = true
+				lib.setStubsVersion(variants[i])
+				mctx.AddInterVariantDependency(stubImplDepTag, modules[len(modules)-1], modules[i])
+			}
 		}
 	}
 	mctx.AliasVariation("")
@@ -1737,7 +1863,7 @@
 		module.CcLibraryInterface() && module.Shared()
 }
 
-func moduleLibraryInterface(module android.Module) libraryInterface {
+func moduleLibraryInterface(module blueprint.Module) libraryInterface {
 	if m, ok := module.(*Module); ok {
 		return m.library
 	}
@@ -1758,7 +1884,15 @@
 				// Set the versions on the pre-mutated module so they can be read by any llndk modules that
 				// depend on the implementation library and haven't been mutated yet.
 				library.setAllStubsVersions(versions)
-				return
+			}
+
+			if mctx.Module().(*Module).UseVndk() && library.hasLLNDKStubs() {
+				// Propagate the version to the llndk stubs module.
+				mctx.VisitDirectDepsWithTag(llndkStubDepTag, func(stubs android.Module) {
+					if stubsLib := moduleLibraryInterface(stubs); stubsLib != nil {
+						stubsLib.setAllStubsVersions(library.allStubsVersions())
+					}
+				})
 			}
 		}
 	}
diff --git a/cc/linkable.go b/cc/linkable.go
index d010985..489063f 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -43,9 +43,11 @@
 	UseSdk() bool
 	UseVndk() bool
 	MustUseVendorVariant() bool
+	IsLlndk() bool
+	IsLlndkPublic() bool
 	IsVndk() bool
 	IsVndkExt() bool
-	IsVndkPrivate(config android.Config) bool
+	IsVndkPrivate() bool
 	HasVendorVariant() bool
 	InProduct() bool
 
diff --git a/cc/linker.go b/cc/linker.go
index 7bc4105..815cdab 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -469,14 +469,14 @@
 	flags.Local.LdFlags = append(flags.Local.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
 
 	if ctx.Host() && !ctx.Windows() {
-		rpath_prefix := `\$$ORIGIN/`
+		rpathPrefix := `\$$ORIGIN/`
 		if ctx.Darwin() {
-			rpath_prefix = "@loader_path/"
+			rpathPrefix = "@loader_path/"
 		}
 
 		if !ctx.static() {
 			for _, rpath := range linker.dynamicProperties.RunPaths {
-				flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
+				flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,-rpath,"+rpathPrefix+rpath)
 			}
 		}
 	}
@@ -580,8 +580,8 @@
 // Rule to generate .bss symbol ordering file.
 
 var (
-	_                      = pctx.SourcePathVariable("genSortedBssSymbolsPath", "build/soong/scripts/gen_sorted_bss_symbols.sh")
-	gen_sorted_bss_symbols = pctx.AndroidStaticRule("gen_sorted_bss_symbols",
+	_                   = pctx.SourcePathVariable("genSortedBssSymbolsPath", "build/soong/scripts/gen_sorted_bss_symbols.sh")
+	genSortedBssSymbols = pctx.AndroidStaticRule("gen_sorted_bss_symbols",
 		blueprint.RuleParams{
 			Command:     "CROSS_COMPILE=$crossCompile $genSortedBssSymbolsPath ${in} ${out}",
 			CommandDeps: []string{"$genSortedBssSymbolsPath", "${crossCompile}nm"},
@@ -592,7 +592,7 @@
 func (linker *baseLinker) sortBssSymbolsBySize(ctx ModuleContext, in android.Path, symbolOrderingFile android.ModuleOutPath, flags builderFlags) string {
 	crossCompile := gccCmd(flags.toolchain, "")
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        gen_sorted_bss_symbols,
+		Rule:        genSortedBssSymbols,
 		Description: "generate bss symbol order " + symbolOrderingFile.Base(),
 		Output:      symbolOrderingFile,
 		Input:       in,
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 212720b..d0fbc48 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -15,21 +15,21 @@
 package cc
 
 import (
-	"fmt"
-	"path/filepath"
 	"strings"
 
 	"android/soong/android"
 )
 
-var llndkImplDep = dependencyTag{name: "llndk impl"}
-
 var (
 	llndkLibrarySuffix = ".llndk"
 	llndkHeadersSuffix = ".llndk"
 )
 
-// Creates a stub shared library based on the provided version file.
+// Holds properties to describe a stub shared library based on the provided version file.
+// The stub library will actually be built by the cc_library module that points to this
+// module with the llndk_stubs property.
+// TODO(ccross): move the properties from llndk_library modules directly into the cc_library
+//  modules and remove the llndk_library modules.
 //
 // Example:
 //
@@ -64,43 +64,32 @@
 
 	// list of llndk headers to re-export include directories from.
 	Export_llndk_headers []string `android:"arch_variant"`
+
+	// whether this module can be directly depended upon by libs that are installed
+	// to /vendor and /product.
+	// When set to true, this module can only be depended on by VNDK libraries, not
+	// vendor nor product libraries. This effectively hides this module from
+	// non-system modules. Default value is false.
+	Private *bool
 }
 
 type llndkStubDecorator struct {
 	*libraryDecorator
 
 	Properties llndkLibraryProperties
-
-	movedToApex bool
 }
 
 var _ versionedInterface = (*llndkStubDecorator)(nil)
 
 func (stub *llndkStubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
-	flags = stub.baseCompiler.compilerFlags(ctx, flags, deps)
-	return addStubLibraryCompilerFlags(flags)
+	return flags
 }
 
 func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
-	vndkVer := ctx.Module().(*Module).VndkVersion()
-	if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" {
-		// For non-enforcing devices, vndkVer is empty. Use "current" in that case, too.
-		vndkVer = "current"
-	}
-	if stub.stubsVersion() != "" {
-		vndkVer = stub.stubsVersion()
-	}
-	objs, versionScript := compileStubLibrary(ctx, flags, String(stub.Properties.Symbol_file), vndkVer, "--llndk")
-	if !Bool(stub.Properties.Unversioned) {
-		stub.versionScriptPath = android.OptionalPathForPath(versionScript)
-	}
-	return objs
+	return Objects{}
 }
 
 func (stub *llndkStubDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
-	headers := addSuffix(stub.Properties.Export_llndk_headers, llndkHeadersSuffix)
-	deps.HeaderLibs = append(deps.HeaderLibs, headers...)
-	deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, headers...)
 	return deps
 }
 
@@ -116,57 +105,9 @@
 	return stub.libraryDecorator.linkerFlags(ctx, flags)
 }
 
-func (stub *llndkStubDecorator) processHeaders(ctx ModuleContext, srcHeaderDir string, outDir android.ModuleGenPath) android.Path {
-	srcDir := android.PathForModuleSrc(ctx, srcHeaderDir)
-	srcFiles := ctx.GlobFiles(filepath.Join(srcDir.String(), "**/*.h"), nil)
-
-	var installPaths []android.WritablePath
-	for _, header := range srcFiles {
-		headerDir := filepath.Dir(header.String())
-		relHeaderDir, err := filepath.Rel(srcDir.String(), headerDir)
-		if err != nil {
-			ctx.ModuleErrorf("filepath.Rel(%q, %q) failed: %s",
-				srcDir.String(), headerDir, err)
-			continue
-		}
-
-		installPaths = append(installPaths, outDir.Join(ctx, relHeaderDir, header.Base()))
-	}
-
-	return processHeadersWithVersioner(ctx, srcDir, outDir, srcFiles, installPaths)
-}
-
 func (stub *llndkStubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
 	objs Objects) android.Path {
-
-	impl := ctx.GetDirectDepWithTag(stub.implementationModuleName(ctx.ModuleName()), llndkImplDep)
-	if implApexModule, ok := impl.(android.ApexModule); ok {
-		stub.movedToApex = implApexModule.DirectlyInAnyApex()
-	}
-
-	if len(stub.Properties.Export_preprocessed_headers) > 0 {
-		genHeaderOutDir := android.PathForModuleGen(ctx, "include")
-
-		var timestampFiles android.Paths
-		for _, dir := range stub.Properties.Export_preprocessed_headers {
-			timestampFiles = append(timestampFiles, stub.processHeaders(ctx, dir, genHeaderOutDir))
-		}
-
-		if Bool(stub.Properties.Export_headers_as_system) {
-			stub.reexportSystemDirs(genHeaderOutDir)
-		} else {
-			stub.reexportDirs(genHeaderOutDir)
-		}
-
-		stub.reexportDeps(timestampFiles...)
-	}
-
-	if Bool(stub.Properties.Export_headers_as_system) {
-		stub.exportIncludesAsSystem(ctx)
-		stub.libraryDecorator.flagExporter.Properties.Export_include_dirs = []string{}
-	}
-
-	return stub.libraryDecorator.link(ctx, flags, deps, objs)
+	return nil
 }
 
 func (stub *llndkStubDecorator) nativeCoverage() bool {
@@ -181,20 +122,8 @@
 	return true
 }
 
-func (stub *llndkStubDecorator) stubsVersions(ctx android.BaseMutatorContext) []string {
-	// Get the versions from the implementation module.
-	impls := ctx.GetDirectDepsWithTag(llndkImplDep)
-	if len(impls) > 1 {
-		panic(fmt.Errorf("Expected single implmenetation library, got %d", len(impls)))
-	} else if len(impls) == 1 {
-		return moduleLibraryInterface(impls[0]).allStubsVersions()
-	}
-	return nil
-}
-
 func NewLLndkStubLibrary() *Module {
 	module, library := NewLibrary(android.DeviceSupported)
-	library.BuildOnlyShared()
 	module.stl = nil
 	module.sanitize = nil
 	library.disableStripping()
@@ -235,10 +164,6 @@
 	*libraryDecorator
 }
 
-func (headers *llndkHeadersDecorator) Name(name string) string {
-	return name + llndkHeadersSuffix
-}
-
 // llndk_headers contains a set of c/c++ llndk headers files which are imported
 // by other soongs cc modules.
 func llndkHeadersFactory() android.Module {
diff --git a/cc/pgo.go b/cc/pgo.go
index 3cf550a..ada694b 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -103,7 +103,7 @@
 }
 
 func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
-	profile_file := *props.Pgo.Profile_file
+	profileFile := *props.Pgo.Profile_file
 
 	// Test if the profile_file is present in any of the PGO profile projects
 	for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
@@ -112,24 +112,24 @@
 		// <profile_file>.<arbitrary-version> when available.  This
 		// works around an issue where ccache serves stale cache
 		// entries when the profile file has changed.
-		globPattern := filepath.Join(profileProject, profile_file+".*")
-		versioned_profiles, err := ctx.GlobWithDeps(globPattern, nil)
+		globPattern := filepath.Join(profileProject, profileFile+".*")
+		versionedProfiles, err := ctx.GlobWithDeps(globPattern, nil)
 		if err != nil {
 			ctx.ModuleErrorf("glob: %s", err.Error())
 		}
 
-		path := android.ExistentPathForSource(ctx, profileProject, profile_file)
+		path := android.ExistentPathForSource(ctx, profileProject, profileFile)
 		if path.Valid() {
-			if len(versioned_profiles) != 0 {
-				ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profile_file)+", "+strings.Join(versioned_profiles, ", "))
+			if len(versionedProfiles) != 0 {
+				ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profileFile)+", "+strings.Join(versionedProfiles, ", "))
 			}
 			return path
 		}
 
-		if len(versioned_profiles) > 1 {
-			ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versioned_profiles, ", "))
-		} else if len(versioned_profiles) == 1 {
-			return android.OptionalPathForPath(android.PathForSource(ctx, versioned_profiles[0]))
+		if len(versionedProfiles) > 1 {
+			ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versionedProfiles, ", "))
+		} else if len(versionedProfiles) == 1 {
+			return android.OptionalPathForPath(android.PathForSource(ctx, versionedProfiles[0]))
 		}
 	}
 
diff --git a/cc/sabi.go b/cc/sabi.go
index c357f8d..4a1ba3c 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -80,10 +80,10 @@
 	if m.IsNdk(ctx.Config()) {
 		return "NDK"
 	}
-	if m.isLlndkPublic(ctx.Config()) {
+	if m.isImplementationForLLNDKPublic() {
 		return "LLNDK"
 	}
-	if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate(ctx.Config()) {
+	if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate() {
 		if m.isVndkSp() {
 			if m.IsVndkExt() {
 				return "VNDK-SP-ext"
@@ -156,7 +156,7 @@
 	}
 
 	// Don't create ABI dump for stubs.
-	if m.isNDKStubLibrary() || m.IsStubs() {
+	if m.isNDKStubLibrary() || m.IsLlndk() || m.IsStubs() {
 		return false
 	}
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 22ee25f..d7df5dc 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1002,9 +1002,6 @@
 
 		if runtimeLibrary != "" && (toolchain.Bionic() || c.sanitize.Properties.UbsanRuntimeDep) {
 			// UBSan is supported on non-bionic linux host builds as well
-			if isLlndkLibrary(runtimeLibrary, mctx.Config()) && !c.static() && c.UseVndk() {
-				runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
-			}
 
 			// Adding dependency to the runtime library. We are using *FarVariation*
 			// because the runtime libraries themselves are not mutated by sanitizer
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index f5f8121..4c4e9b6 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -787,11 +787,11 @@
 	if !module.SocSpecific() {
 		// But we can't just check SocSpecific() since we already passed the image mutator.
 		// Check ramdisk and recovery to see if we are real "vendor: true" module.
-		ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
-		vendor_ramdisk_available := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk()
-		recovery_available := module.InRecovery() && !module.OnlyInRecovery()
+		ramdiskAvailable := module.InRamdisk() && !module.OnlyInRamdisk()
+		vendorRamdiskAvailable := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk()
+		recoveryAvailable := module.InRecovery() && !module.OnlyInRecovery()
 
-		if !ramdisk_available && !recovery_available && !vendor_ramdisk_available {
+		if !ramdiskAvailable && !recoveryAvailable && !vendorRamdiskAvailable {
 			vendorSnapshotsLock.Lock()
 			defer vendorSnapshotsLock.Unlock()
 
@@ -805,7 +805,7 @@
 	}
 
 	// .. and also filter out llndk library
-	if module.isLlndk(ctx.Config()) {
+	if module.IsLlndk() {
 		return
 	}
 
diff --git a/cc/test.go b/cc/test.go
index a9be6f9..4ff5bf6 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -211,15 +211,15 @@
 				// name or even their number.
 				testNames = append(testNames, "")
 				tests := mctx.CreateLocalVariations(testNames...)
-				all_tests := tests[numTests]
-				all_tests.(*Module).linker.(testPerSrc).unsetSrc()
+				allTests := tests[numTests]
+				allTests.(*Module).linker.(testPerSrc).unsetSrc()
 				// Prevent the "all tests" variation from being installable nor
 				// exporting to Make, as it won't create any output file.
-				all_tests.(*Module).Properties.PreventInstall = true
-				all_tests.(*Module).Properties.HideFromMake = true
+				allTests.(*Module).Properties.PreventInstall = true
+				allTests.(*Module).Properties.HideFromMake = true
 				for i, src := range test.srcs() {
 					tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src)
-					mctx.AddInterVariantDependency(testPerSrcDepTag, all_tests, tests[i])
+					mctx.AddInterVariantDependency(testPerSrcDepTag, allTests, tests[i])
 				}
 				mctx.AliasVariation("")
 			}
@@ -369,9 +369,9 @@
 		}
 	})
 
-	var api_level_prop string
+	var apiLevelProp string
 	var configs []tradefed.Config
-	var min_level string
+	var minLevel string
 	for _, module := range test.Properties.Test_mainline_modules {
 		configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
 	}
@@ -398,16 +398,16 @@
 	if test.Properties.Test_min_api_level != nil && test.Properties.Test_min_sdk_version != nil {
 		ctx.PropertyErrorf("test_min_api_level", "'test_min_api_level' and 'test_min_sdk_version' should not be set at the same time.")
 	} else if test.Properties.Test_min_api_level != nil {
-		api_level_prop = "ro.product.first_api_level"
-		min_level = strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10)
+		apiLevelProp = "ro.product.first_api_level"
+		minLevel = strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10)
 	} else if test.Properties.Test_min_sdk_version != nil {
-		api_level_prop = "ro.build.version.sdk"
-		min_level = strconv.FormatInt(int64(*test.Properties.Test_min_sdk_version), 10)
+		apiLevelProp = "ro.build.version.sdk"
+		minLevel = strconv.FormatInt(int64(*test.Properties.Test_min_sdk_version), 10)
 	}
-	if api_level_prop != "" {
+	if apiLevelProp != "" {
 		var options []tradefed.Option
-		options = append(options, tradefed.Option{Name: "min-api-level", Value: min_level})
-		options = append(options, tradefed.Option{Name: "api-level-prop", Value: api_level_prop})
+		options = append(options, tradefed.Option{Name: "min-api-level", Value: minLevel})
+		options = append(options, tradefed.Option{Name: "api-level-prop", Value: apiLevelProp})
 		configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options})
 	}
 
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index bca76dc..d2c29d6 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -210,6 +210,9 @@
 		return false
 	}
 	// skip llndk_library and llndk_headers which are backward compatible
+	if m.IsLlndk() {
+		return false
+	}
 	if _, ok := m.linker.(*llndkStubDecorator); ok {
 		return false
 	}
diff --git a/cc/vndk.go b/cc/vndk.go
index 1529ac5..bfa6b59 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -156,9 +156,15 @@
 	}
 	if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
 		// Check only shared libraries.
-		// Other (static and LL-NDK) libraries are allowed to link.
+		// Other (static) libraries are allowed to link.
 		return
 	}
+
+	if to.IsLlndk() {
+		// LL-NDK libraries are allowed to link
+		return
+	}
+
 	if !to.UseVndk() {
 		ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library",
 			vndk.typeName(), to.Name())
@@ -250,22 +256,12 @@
 	}).(map[string]string)
 }
 
-func isLlndkLibrary(baseModuleName string, config android.Config) bool {
-	_, ok := llndkLibraries(config)[strings.TrimSuffix(baseModuleName, llndkLibrarySuffix)]
-	return ok
-}
-
 func llndkLibraries(config android.Config) map[string]string {
 	return config.Once(llndkLibrariesKey, func() interface{} {
 		return make(map[string]string)
 	}).(map[string]string)
 }
 
-func isVndkPrivateLibrary(baseModuleName string, config android.Config) bool {
-	_, ok := vndkPrivateLibraries(config)[baseModuleName]
-	return ok
-}
-
 func vndkPrivateLibraries(config android.Config) map[string]string {
 	return config.Once(vndkPrivateLibrariesKey, func() interface{} {
 		return make(map[string]string)
@@ -301,12 +297,10 @@
 	defer vndkLibrariesLock.Unlock()
 
 	llndkLibraries(mctx.Config())[name] = filename
+	m.VendorProperties.IsLLNDK = true
 	if !Bool(lib.Properties.Vendor_available) {
 		vndkPrivateLibraries(mctx.Config())[name] = filename
-	}
-
-	if mctx.OtherModuleExists(name) {
-		mctx.AddFarVariationDependencies(m.Target().Variations(), llndkImplDep, name)
+		m.VendorProperties.IsLLNDKPrivate = true
 	}
 }
 
@@ -410,10 +404,32 @@
 		return
 	}
 
-	lib, is_lib := m.linker.(*libraryDecorator)
-	prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+	// This is a temporary measure to copy the properties from an llndk_library into the cc_library
+	// that will actually build the stubs.  It will be removed once the properties are moved into
+	// the cc_library in the Android.bp files.
+	mergeLLNDKToLib := func(llndk *Module, llndkProperties *llndkLibraryProperties, flagExporter *flagExporter) {
+		if llndkLib := moduleLibraryInterface(llndk); llndkLib != nil {
+			*llndkProperties = llndkLib.(*llndkStubDecorator).Properties
+			flagExporter.Properties = llndkLib.(*llndkStubDecorator).flagExporter.Properties
 
-	if (is_lib && lib.buildShared()) || (is_prebuilt_lib && prebuilt_lib.buildShared()) {
+			m.VendorProperties.IsLLNDK = llndk.VendorProperties.IsLLNDK
+			m.VendorProperties.IsLLNDKPrivate = llndk.VendorProperties.IsLLNDKPrivate
+		}
+	}
+
+	lib, isLib := m.linker.(*libraryDecorator)
+	prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker)
+
+	if m.UseVndk() && isLib && lib.hasLLNDKStubs() {
+		llndk := mctx.AddVariationDependencies(nil, llndkStubDepTag, String(lib.Properties.Llndk_stubs))
+		mergeLLNDKToLib(llndk[0].(*Module), &lib.Properties.Llndk, &lib.flagExporter)
+	}
+	if m.UseVndk() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() {
+		llndk := mctx.AddVariationDependencies(nil, llndkStubDepTag, String(prebuiltLib.Properties.Llndk_stubs))
+		mergeLLNDKToLib(llndk[0].(*Module), &prebuiltLib.Properties.Llndk, &prebuiltLib.flagExporter)
+	}
+
+	if (isLib && lib.buildShared()) || (isPrebuiltLib && prebuiltLib.buildShared()) {
 		if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
 			processVndkLibrary(mctx, m)
 			return
@@ -819,13 +835,11 @@
 	// they been moved to an apex.
 	movedToApexLlndkLibraries := make(map[string]bool)
 	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(*Module); ok {
-			if llndk, ok := m.linker.(*llndkStubDecorator); ok {
-				// Skip bionic libs, they are handled in different manner
-				name := llndk.implementationModuleName(m.BaseModuleName())
-				if llndk.movedToApex && !isBionic(name) {
-					movedToApexLlndkLibraries[name] = true
-				}
+		if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() {
+			// Skip bionic libs, they are handled in different manner
+			name := library.implementationModuleName(module.(*Module).BaseModuleName())
+			if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) {
+				movedToApexLlndkLibraries[name] = true
 			}
 		}
 	})
diff --git a/cmd/host_bionic_inject/host_bionic_inject.go b/cmd/host_bionic_inject/host_bionic_inject.go
index 629f6cc..ce8b062 100644
--- a/cmd/host_bionic_inject/host_bionic_inject.go
+++ b/cmd/host_bionic_inject/host_bionic_inject.go
@@ -58,7 +58,7 @@
 		os.Exit(4)
 	}
 
-	start_addr, err := parseElf(r, linker)
+	startAddr, err := parseElf(r, linker)
 	if err != nil {
 		fmt.Fprintln(os.Stderr, err.Error())
 		os.Exit(5)
@@ -71,7 +71,7 @@
 	}
 	defer w.Close()
 
-	err = symbol_inject.InjectUint64Symbol(file, w, "__dlwrap_original_start", start_addr)
+	err = symbol_inject.InjectUint64Symbol(file, w, "__dlwrap_original_start", startAddr)
 	if err != nil {
 		fmt.Fprintln(os.Stderr, err.Error())
 		os.Exit(7)
@@ -128,7 +128,7 @@
 
 // Check that all of the PT_LOAD segments have been embedded properly
 func checkLinker(file, linker *elf.File, fileSyms []elf.Symbol) error {
-	dlwrap_linker_offset, err := findSymbol(fileSyms, "__dlwrap_linker_offset")
+	dlwrapLinkerOffset, err := findSymbol(fileSyms, "__dlwrap_linker_offset")
 	if err != nil {
 		return err
 	}
@@ -138,7 +138,7 @@
 			continue
 		}
 
-		laddr := lprog.Vaddr + dlwrap_linker_offset.Value
+		laddr := lprog.Vaddr + dlwrapLinkerOffset.Value
 
 		found := false
 		for _, prog := range file.Progs {
@@ -163,7 +163,7 @@
 		}
 		if !found {
 			return fmt.Errorf("Linker prog %d (0x%x) not found at offset 0x%x",
-				i, lprog.Vaddr, dlwrap_linker_offset.Value)
+				i, lprog.Vaddr, dlwrapLinkerOffset.Value)
 		}
 	}
 
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index deaf77f..874edca 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -335,11 +335,14 @@
 	}
 }
 
-// Add class loader context for the given SDK version. Fail on unknown build/install paths.
+// Add class loader context for the given SDK version. Don't fail on unknown build/install paths, as
+// libraries with unknown paths still need to be processed by manifest_fixer (which doesn't care
+// about paths). For the subset of libraries that are used in dexpreopt, their build/install paths
+// are validated later before CLC is used (in validateClassLoaderContext).
 func (clcMap ClassLoaderContextMap) AddContextForSdk(ctx android.ModuleInstallPathContext, sdkVer int,
 	lib string, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) {
 
-	clcMap.addContextOrReportError(ctx, sdkVer, lib, hostPath, installPath, true, nestedClcMap)
+	clcMap.addContextOrReportError(ctx, sdkVer, lib, hostPath, installPath, false, nestedClcMap)
 }
 
 // Merge the other class loader context map into this one, do not override existing entries.
diff --git a/java/aar.go b/java/aar.go
index dfcd956..e3ad252 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -416,7 +416,6 @@
 	}
 
 	ctx.VisitDirectDeps(func(module android.Module) {
-		depName := ctx.OtherModuleName(module)
 		depTag := ctx.OtherModuleDependencyTag(module)
 
 		var exportPackage android.Path
@@ -432,15 +431,6 @@
 			if exportPackage != nil {
 				sharedLibs = append(sharedLibs, exportPackage)
 			}
-
-			// If the module is (or possibly could be) a component of a java_sdk_library
-			// (including the java_sdk_library) itself then append any implicit sdk library
-			// names to the list of sdk libraries to be added to the manifest.
-			if component, ok := module.(SdkLibraryComponentDependency); ok {
-				classLoaderContexts.MaybeAddContext(ctx, component.OptionalImplicitSdkLibrary(),
-					component.DexJarBuildPath(), component.DexJarInstallPath())
-			}
-
 		case frameworkResTag:
 			if exportPackage != nil {
 				sharedLibs = append(sharedLibs, exportPackage)
@@ -468,8 +458,7 @@
 			}
 		}
 
-		// Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
-		maybeAddCLCFromDep(module, depTag, depName, classLoaderContexts)
+		addCLCFromDep(ctx, module, classLoaderContexts)
 	})
 
 	deps = append(deps, sharedLibs...)
diff --git a/java/app.go b/java/app.go
index c0ac9c2..272d836 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1546,11 +1546,11 @@
 	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
 	a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 
-	dexOutput := a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
+	a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
 	if a.dexpreopter.uncompressedDex {
 		dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk")
-		a.uncompressDex(ctx, dexOutput, dexUncompressed.OutputPath)
-		dexOutput = dexUncompressed
+		a.uncompressDex(ctx, jnisUncompressed, dexUncompressed.OutputPath)
+		jnisUncompressed = dexUncompressed
 	}
 
 	apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
@@ -1574,11 +1574,11 @@
 		if lineage := String(a.properties.Lineage); lineage != "" {
 			lineageFile = android.PathForModuleSrc(ctx, lineage)
 		}
-		SignAppPackage(ctx, signed, dexOutput, certificates, nil, lineageFile)
+		SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile)
 		a.outputFile = signed
 	} else {
 		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
-		TransformZipAlign(ctx, alignedApk, dexOutput)
+		TransformZipAlign(ctx, alignedApk, jnisUncompressed)
 		a.outputFile = alignedApk
 		a.certificate = PresignedCertificate
 	}
@@ -1990,7 +1990,7 @@
 		ctx.VisitDirectDeps(func(m android.Module) {
 			if tag, ok := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag); ok {
 				dep := ctx.OtherModuleName(m)
-				if lib, ok := m.(Dependency); ok {
+				if lib, ok := m.(UsesLibraryDependency); ok {
 					clcMap.AddContextForSdk(ctx, tag.sdkVersion, dep,
 						lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
 				} else if ctx.Config().AllowMissingDependencies() {
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 67738d4..b5830c7 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -112,13 +112,13 @@
 	return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
 }
 
-func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
+func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) {
 	// TODO(b/148690468): The check on d.installPath is to bail out in cases where
 	// the dexpreopter struct hasn't been fully initialized before we're called,
 	// e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
 	// disabled, even if installable is true.
 	if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." {
-		return dexJarFile
+		return
 	}
 
 	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
@@ -213,12 +213,10 @@
 	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
 	if err != nil {
 		ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
-		return dexJarFile
+		return
 	}
 
 	dexpreoptRule.Build("dexpreopt", "dexpreopt")
 
 	d.builtInstalled = dexpreoptRule.Installs().String()
-
-	return dexJarFile
 }
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 9c88a3c..cbca12a 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -305,17 +305,17 @@
 }
 
 func ignoreMissingModules(ctx android.BottomUpMutatorContext, apiToCheck *ApiToCheck) {
-	api_file := String(apiToCheck.Api_file)
-	removed_api_file := String(apiToCheck.Removed_api_file)
+	apiFile := String(apiToCheck.Api_file)
+	removedApiFile := String(apiToCheck.Removed_api_file)
 
-	api_module := android.SrcIsModule(api_file)
-	removed_api_module := android.SrcIsModule(removed_api_file)
+	apiModule := android.SrcIsModule(apiFile)
+	removedApiModule := android.SrcIsModule(removedApiFile)
 
-	if api_module == "" || removed_api_module == "" {
+	if apiModule == "" || removedApiModule == "" {
 		return
 	}
 
-	if ctx.OtherModuleExists(api_module) || ctx.OtherModuleExists(removed_api_module) {
+	if ctx.OtherModuleExists(apiModule) || ctx.OtherModuleExists(removedApiModule) {
 		return
 	}
 
diff --git a/java/java.go b/java/java.go
index 02d78f2..04c49de 100644
--- a/java/java.go
+++ b/java/java.go
@@ -510,6 +510,7 @@
 type UsesLibraryDependency interface {
 	DexJarBuildPath() android.Path
 	DexJarInstallPath() android.Path
+	ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
 }
 
 type Dependency interface {
@@ -518,7 +519,6 @@
 	ImplementationJars() android.Paths
 	ResourceJars() android.Paths
 	AidlIncludeDirs() android.Paths
-	ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
 	ExportedPlugins() (android.Paths, []string, bool)
 	SrcJarArgs() ([]string, android.Paths)
 	BaseModuleName() string
@@ -1081,8 +1081,6 @@
 			switch tag {
 			case libTag:
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
-				j.classLoaderContexts.MaybeAddContext(ctx, dep.OptionalImplicitSdkLibrary(),
-					dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			case staticLibTag:
 				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
 			}
@@ -1092,7 +1090,6 @@
 				deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
 			case libTag, instrumentationForTag:
 				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
-				j.classLoaderContexts.AddContextMap(dep.ClassLoaderContexts(), otherName)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
 				pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins()
 				addPlugins(&deps, pluginJars, pluginClasses...)
@@ -1179,8 +1176,7 @@
 			}
 		}
 
-		// Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
-		maybeAddCLCFromDep(module, tag, otherName, j.classLoaderContexts)
+		addCLCFromDep(ctx, module, j.classLoaderContexts)
 	})
 
 	return deps
@@ -1509,11 +1505,11 @@
 	j.compiledJavaSrcs = uniqueSrcFiles
 	j.compiledSrcJars = srcJars
 
-	enable_sharding := false
+	enableSharding := false
 	var headerJarFileWithoutJarjar android.Path
 	if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine {
 		if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
-			enable_sharding = true
+			enableSharding = true
 			// Formerly, there was a check here that prevented annotation processors
 			// from being used when sharding was enabled, as some annotation processors
 			// do not function correctly in sharded environments. It was removed to
@@ -1539,7 +1535,7 @@
 			extraJarDeps = append(extraJarDeps, errorprone)
 		}
 
-		if enable_sharding {
+		if enableSharding {
 			flags.classpath = append(flags.classpath, headerJarFileWithoutJarjar)
 			shardSize := int(*(j.properties.Javac_shard_size))
 			var shardSrcs []android.Paths
@@ -1786,7 +1782,7 @@
 		j.dexJarFile = dexOutputFile
 
 		// Dexpreopting
-		dexOutputFile = j.dexpreopt(ctx, dexOutputFile)
+		j.dexpreopt(ctx, dexOutputFile)
 
 		j.maybeStrippedDexJarFile = dexOutputFile
 
@@ -2137,18 +2133,6 @@
 		j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
-
-	// If this is a component library (stubs, etc.) for a java_sdk_library then
-	// add the name of that java_sdk_library to the exported sdk libs to make sure
-	// that, if necessary, a <uses-library> element for that java_sdk_library is
-	// added to the Android manifest.
-	j.classLoaderContexts.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
-		j.DexJarBuildPath(), j.DexJarInstallPath())
-
-	// A non-SDK library may provide a <uses-library> (the name may be different from the module name).
-	if lib := proptools.String(j.usesLibraryProperties.Provides_uses_lib); lib != "" {
-		j.classLoaderContexts.AddContext(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath())
-	}
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -2810,7 +2794,6 @@
 	var flags javaBuilderFlags
 
 	ctx.VisitDirectDeps(func(module android.Module) {
-		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
 
 		switch dep := module.(type) {
@@ -2825,27 +2808,17 @@
 			switch tag {
 			case libTag:
 				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
-				j.classLoaderContexts.AddContext(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath())
 			}
 		}
 
-		// Merge dep's CLC after processing the dep itself (which may add its own <uses-library>).
-		maybeAddCLCFromDep(module, tag, otherName, j.classLoaderContexts)
+		addCLCFromDep(ctx, module, j.classLoaderContexts)
 	})
 
-	var installFile android.Path
 	if Bool(j.properties.Installable) {
-		installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			jarName, outputFile)
 	}
 
-	// If this is a component library (impl, stubs, etc.) for a java_sdk_library then
-	// add the name of that java_sdk_library to the exported sdk libs to make sure
-	// that, if necessary, a <uses-library> element for that java_sdk_library is
-	// added to the Android manifest.
-	j.classLoaderContexts.MaybeAddContext(ctx, j.OptionalImplicitSdkLibrary(),
-		outputFile, installFile)
-
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
 
 	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
@@ -3123,7 +3096,7 @@
 
 	j.dexJarFile = dexOutputFile
 
-	dexOutputFile = j.dexpreopt(ctx, dexOutputFile)
+	j.dexpreopt(ctx, dexOutputFile)
 
 	j.maybeStrippedDexJarFile = dexOutputFile
 
@@ -3259,30 +3232,63 @@
 var String = proptools.String
 var inList = android.InList
 
-// Add class loader context of a given dependency to the given class loader context, provided that
-// all the necessary conditions are met.
-func maybeAddCLCFromDep(depModule android.Module, depTag blueprint.DependencyTag,
-	depName string, clcMap dexpreopt.ClassLoaderContextMap) {
+// TODO(b/132357300) Generalize SdkLibrarComponentDependency to non-SDK libraries and merge with
+// this interface.
+type ProvidesUsesLib interface {
+	ProvidesUsesLib() *string
+}
 
-	if dep, ok := depModule.(Dependency); ok {
-		if depTag == libTag {
-			// Ok, propagate <uses-library> through non-static library dependencies.
-		} else if depTag == staticLibTag {
-			// Propagate <uses-library> through static library dependencies, unless it is a
-			// component library (such as stubs). Component libraries have a dependency on their
-			// SDK library, which should not be pulled just because of a static component library.
-			if comp, isComp := depModule.(SdkLibraryComponentDependency); isComp {
-				if compName := comp.OptionalImplicitSdkLibrary(); compName != nil {
-					dep = nil
-				}
-			}
-		} else {
-			// Don't propagate <uses-library> for other dependency tags.
-			dep = nil
-		}
+func (j *Module) ProvidesUsesLib() *string {
+	return j.usesLibraryProperties.Provides_uses_lib
+}
 
-		if dep != nil {
-			clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
+// Add class loader context (CLC) of a given dependency to the current CLC.
+func addCLCFromDep(ctx android.ModuleContext, depModule android.Module,
+	clcMap dexpreopt.ClassLoaderContextMap) {
+
+	dep, ok := depModule.(UsesLibraryDependency)
+	if !ok {
+		return
+	}
+
+	// Find out if the dependency is either an SDK library or an ordinary library that is disguised
+	// as an SDK library by the means of `provides_uses_lib` property. If yes, the library is itself
+	// a <uses-library> and should be added as a node in the CLC tree, and its CLC should be added
+	// as subtree of that node. Otherwise the library is not a <uses_library> and should not be
+	// added to CLC, but the transitive <uses-library> dependencies from its CLC should be added to
+	// the current CLC.
+	var implicitSdkLib *string
+	comp, isComp := depModule.(SdkLibraryComponentDependency)
+	if isComp {
+		implicitSdkLib = comp.OptionalImplicitSdkLibrary()
+		// OptionalImplicitSdkLibrary() may be nil so need to fall through to ProvidesUsesLib().
+	}
+	if implicitSdkLib == nil {
+		if ulib, ok := depModule.(ProvidesUsesLib); ok {
+			implicitSdkLib = ulib.ProvidesUsesLib()
 		}
 	}
+
+	depTag := ctx.OtherModuleDependencyTag(depModule)
+	if depTag == libTag || depTag == usesLibTag {
+		// Ok, propagate <uses-library> through non-static library dependencies.
+	} else if depTag == staticLibTag {
+		// Propagate <uses-library> through static library dependencies, unless it is a component
+		// library (such as stubs). Component libraries have a dependency on their SDK library,
+		// which should not be pulled just because of a static component library.
+		if implicitSdkLib != nil {
+			return
+		}
+	} else {
+		// Don't propagate <uses-library> for other dependency tags.
+		return
+	}
+
+	if implicitSdkLib != nil {
+		clcMap.AddContextForSdk(ctx, dexpreopt.AnySdkVersion, *implicitSdkLib,
+			dep.DexJarBuildPath(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
+	} else {
+		depName := ctx.OtherModuleName(depModule)
+		clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
+	}
 }
diff --git a/java/sdk.go b/java/sdk.go
index 32a4b5a..a68abfb 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -371,8 +371,8 @@
 		jar := filepath.Join(dir, "android.jar")
 		// There's no aidl for other SDKs yet.
 		// TODO(77525052): Add aidl files for other SDKs too.
-		public_dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), "public")
-		aidl := filepath.Join(public_dir, "framework.aidl")
+		publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), "public")
+		aidl := filepath.Join(publicDir, "framework.aidl")
 		jarPath := android.ExistentPathForSource(ctx, jar)
 		aidlPath := android.ExistentPathForSource(ctx, aidl)
 		lambdaStubsPath := android.PathForSource(ctx, config.SdkLambdaStubsPath)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index c6a9527..f279b95 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -28,6 +28,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/dexpreopt"
 )
 
 const (
@@ -1538,7 +1539,7 @@
 	hasSystemAndTestApis := sdkDep.hasStandardLibs()
 	module.sdkLibraryProperties.Generate_system_and_test_apis = hasSystemAndTestApis
 
-	missing_current_api := false
+	missingCurrentApi := false
 
 	generatedScopes := module.getGeneratedApiScopes(mctx)
 
@@ -1549,12 +1550,12 @@
 			p := android.ExistentPathForSource(mctx, path)
 			if !p.Valid() {
 				mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
-				missing_current_api = true
+				missingCurrentApi = true
 			}
 		}
 	}
 
-	if missing_current_api {
+	if missingCurrentApi {
 		script := "build/soong/scripts/gen-java-current-api-files.sh"
 		p := android.ExistentPathForSource(mctx, script)
 
@@ -2025,7 +2026,7 @@
 	return module.sdkJars(ctx, sdkVersion, false)
 }
 
-// to satisfy SdkLibraryDependency interface
+// to satisfy UsesLibraryDependency interface
 func (module *SdkLibraryImport) DexJarBuildPath() android.Path {
 	if module.implLibraryModule == nil {
 		return nil
@@ -2034,7 +2035,7 @@
 	}
 }
 
-// to satisfy SdkLibraryDependency interface
+// to satisfy UsesLibraryDependency interface
 func (module *SdkLibraryImport) DexJarInstallPath() android.Path {
 	if module.implLibraryModule == nil {
 		return nil
@@ -2043,6 +2044,11 @@
 	}
 }
 
+// to satisfy UsesLibraryDependency interface
+func (module *SdkLibraryImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
+	return nil
+}
+
 // to satisfy apex.javaDependency interface
 func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path {
 	if module.implLibraryModule == nil {
diff --git a/rust/builder.go b/rust/builder.go
index 8ec2da2..e5f0ab5 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -137,13 +137,13 @@
 	var implicitOutputs android.WritablePaths
 
 	output.outputFile = outputFile
-	crate_name := ctx.RustModule().CrateName()
+	crateName := ctx.RustModule().CrateName()
 	targetTriple := ctx.toolchain().RustTriple()
 
 	// libstd requires a specific environment variable to be set. This is
 	// not officially documented and may be removed in the future. See
 	// https://github.com/rust-lang/rust/blob/master/library/std/src/env.rs#L866.
-	if crate_name == "std" {
+	if crateName == "std" {
 		envVars = append(envVars, "STD_ENV_ARCH="+config.StdEnvArch[ctx.RustModule().Arch().ArchType])
 	}
 
@@ -153,8 +153,8 @@
 	rustcFlags = append(rustcFlags, flags.GlobalRustFlags...)
 	rustcFlags = append(rustcFlags, flags.RustFlags...)
 	rustcFlags = append(rustcFlags, "--crate-type="+crate_type)
-	if crate_name != "" {
-		rustcFlags = append(rustcFlags, "--crate-name="+crate_name)
+	if crateName != "" {
+		rustcFlags = append(rustcFlags, "--crate-name="+crateName)
 	}
 	if targetTriple != "" {
 		rustcFlags = append(rustcFlags, "--target="+targetTriple)
diff --git a/rust/compiler.go b/rust/compiler.go
index 4312452..ee88a27 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -214,9 +214,9 @@
 	flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags())
 
 	if ctx.Host() && !ctx.Windows() {
-		rpath_prefix := `\$$ORIGIN/`
+		rpathPrefix := `\$$ORIGIN/`
 		if ctx.Darwin() {
-			rpath_prefix = "@loader_path/"
+			rpathPrefix = "@loader_path/"
 		}
 
 		var rpath string
@@ -225,8 +225,8 @@
 		} else {
 			rpath = "lib"
 		}
-		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+rpath)
-		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpath_prefix+"../"+rpath)
+		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+rpath)
+		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+"../"+rpath)
 	}
 
 	return flags
diff --git a/rust/rust.go b/rust/rust.go
index 21da5ae..1053846 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -189,7 +189,15 @@
 	return false
 }
 
-func (c *Module) IsVndkPrivate(config android.Config) bool {
+func (c *Module) IsVndkPrivate() bool {
+	return false
+}
+
+func (c *Module) IsLlndk() bool {
+	return false
+}
+
+func (c *Module) IsLlndkPublic() bool {
 	return false
 }
 
@@ -474,6 +482,16 @@
 	panic(fmt.Errorf("CoverageFiles called on non-library module: %q", mod.BaseModuleName()))
 }
 
+func (mod *Module) installable(apexInfo android.ApexInfo) bool {
+	// The apex variant is not installable because it is included in the APEX and won't appear
+	// in the system partition as a standalone file.
+	if !apexInfo.IsForPlatform() {
+		return false
+	}
+
+	return mod.outputFile.Valid() && !mod.Properties.PreventInstall
+}
+
 var _ cc.LinkableInterface = (*Module)(nil)
 
 func (mod *Module) Init() android.Module {
@@ -645,7 +663,9 @@
 		outputFile := mod.compiler.compile(ctx, flags, deps)
 
 		mod.outputFile = android.OptionalPathForPath(outputFile)
-		if mod.outputFile.Valid() && !mod.Properties.PreventInstall {
+
+		apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+		if mod.installable(apexInfo) {
 			mod.compiler.install(ctx)
 		}
 	}
@@ -678,15 +698,15 @@
 
 type dependencyTag struct {
 	blueprint.BaseDependencyTag
-	name       string
-	library    bool
-	proc_macro bool
+	name      string
+	library   bool
+	procMacro bool
 }
 
 // InstallDepNeeded returns true for rlibs, dylibs, and proc macros so that they or their transitive
 // dependencies (especially C/C++ shared libs) are installed as dependencies of a rust binary.
 func (d dependencyTag) InstallDepNeeded() bool {
-	return d.library || d.proc_macro
+	return d.library || d.procMacro
 }
 
 var _ android.InstallNeededDependencyTag = dependencyTag{}
@@ -695,7 +715,7 @@
 	customBindgenDepTag = dependencyTag{name: "customBindgenTag"}
 	rlibDepTag          = dependencyTag{name: "rlibTag", library: true}
 	dylibDepTag         = dependencyTag{name: "dylib", library: true}
-	procMacroDepTag     = dependencyTag{name: "procMacro", proc_macro: true}
+	procMacroDepTag     = dependencyTag{name: "procMacro", procMacro: true}
 	testPerSrcDepTag    = dependencyTag{name: "rust_unit_tests"}
 	sourceDepTag        = dependencyTag{name: "source"}
 )
diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index 1a33219..c27f098 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -56,6 +56,12 @@
     "Ndk_abis": true,
     "Exclude_draft_ndk_apis": true,
 
+    "VendorVars": {
+        "art_module": {
+            "source_build": "true"
+        }
+    },
+
     "MissingUsesLibraries": ${MISSING_USES_LIBRARIES}
 }
 EOF
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index f86e1fd..8db33a3 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -205,14 +205,14 @@
 func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) {
 	s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src))
 	filename := proptools.String(s.properties.Filename)
-	filename_from_src := proptools.Bool(s.properties.Filename_from_src)
+	filenameFromSrc := proptools.Bool(s.properties.Filename_from_src)
 	if filename == "" {
-		if filename_from_src {
+		if filenameFromSrc {
 			filename = s.sourceFilePath.Base()
 		} else {
 			filename = ctx.ModuleName()
 		}
-	} else if filename_from_src {
+	} else if filenameFromSrc {
 		ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
 		return
 	}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 93a3fe0..42caff2 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -392,18 +392,18 @@
 		ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs")
 	}
 
-	missing_api := false
+	missingApi := false
 
 	for _, txt := range []string{"-current.txt", "-latest.txt"} {
 		path := path.Join(ctx.ModuleDir(), "api", m.BaseModuleName()+txt)
 		file := android.ExistentPathForSource(ctx, path)
 		if !file.Valid() {
 			ctx.ModuleErrorf("API file %#v doesn't exist", path)
-			missing_api = true
+			missingApi = true
 		}
 	}
 
-	if missing_api {
+	if missingApi {
 		script := "build/soong/scripts/gen-sysprop-api-files.sh"
 		p := android.ExistentPathForSource(ctx, script)
 
diff --git a/third_party/zip/android_test.go b/third_party/zip/android_test.go
index 5154a17..9932c1b 100644
--- a/third_party/zip/android_test.go
+++ b/third_party/zip/android_test.go
@@ -74,3 +74,69 @@
 		}
 	}
 }
+
+func TestCopyFromZip64(t *testing.T) {
+	if testing.Short() {
+		t.Skip("slow test; skipping")
+	}
+
+	const size = uint32max + 1
+	fromZipBytes := &bytes.Buffer{}
+	fromZip := NewWriter(fromZipBytes)
+	w, err := fromZip.CreateHeaderAndroid(&FileHeader{
+		Name:               "large",
+		Method:             Store,
+		UncompressedSize64: size,
+		CompressedSize64:   size,
+	})
+	if err != nil {
+		t.Fatalf("Create: %v", err)
+	}
+	_, err = w.Write(make([]byte, size))
+	if err != nil {
+		t.Fatalf("Write: %v", err)
+	}
+	err = fromZip.Close()
+	if err != nil {
+		t.Fatalf("Close: %v", err)
+	}
+	fromZip = nil
+
+	fromZipReader, err := NewReader(bytes.NewReader(fromZipBytes.Bytes()), int64(fromZipBytes.Len()))
+	if err != nil {
+		t.Fatalf("NewReader: %v", err)
+	}
+
+	toZipBytes := &bytes.Buffer{}
+	toZip := NewWriter(toZipBytes)
+	err = toZip.CopyFrom(fromZipReader.File[0], fromZipReader.File[0].Name)
+	if err != nil {
+		t.Fatalf("CopyFrom: %v", err)
+	}
+
+	err = toZip.Close()
+	if err != nil {
+		t.Fatalf("Close: %v", err)
+	}
+
+	// Save some memory
+	fromZipReader = nil
+	fromZipBytes.Reset()
+
+	toZipReader, err := NewReader(bytes.NewReader(toZipBytes.Bytes()), int64(toZipBytes.Len()))
+	if err != nil {
+		t.Fatalf("NewReader: %v", err)
+	}
+
+	if len(toZipReader.File) != 1 {
+		t.Fatalf("Expected 1 file in toZip, got %d", len(toZipReader.File))
+	}
+
+	if g, w := toZipReader.File[0].CompressedSize64, uint64(size); g != w {
+		t.Errorf("Expected CompressedSize64 %d, got %d", w, g)
+	}
+
+	if g, w := toZipReader.File[0].UncompressedSize64, uint64(size); g != w {
+		t.Errorf("Expected UnompressedSize64 %d, got %d", w, g)
+	}
+}
diff --git a/third_party/zip/writer.go b/third_party/zip/writer.go
index 4c5eb78..8dd986e 100644
--- a/third_party/zip/writer.go
+++ b/third_party/zip/writer.go
@@ -276,9 +276,6 @@
 	} else {
 		b.uint32(h.CRC32)
 
-		if h.CompressedSize64 > uint32max || h.UncompressedSize64 > uint32max {
-			panic("skipping writing the data descriptor for a 64-bit value is not yet supported")
-		}
 		compressedSize := uint32(h.CompressedSize64)
 		if compressedSize == 0 {
 			compressedSize = h.CompressedSize
@@ -289,6 +286,21 @@
 			uncompressedSize = h.UncompressedSize
 		}
 
+		if h.CompressedSize64 > uint32max || h.UncompressedSize64 > uint32max {
+			// Sizes don't fit in a 32-bit field, put them in a zip64 extra instead.
+			compressedSize = uint32max
+			uncompressedSize = uint32max
+
+			// append a zip64 extra block to Extra
+			var buf [20]byte // 2x uint16 + 2x uint64
+			eb := writeBuf(buf[:])
+			eb.uint16(zip64ExtraId)
+			eb.uint16(16) // size = 2x uint64
+			eb.uint64(h.UncompressedSize64)
+			eb.uint64(h.CompressedSize64)
+			h.Extra = append(h.Extra, buf[:]...)
+		}
+
 		b.uint32(compressedSize)
 		b.uint32(uncompressedSize)
 	}
diff --git a/ui/build/config.go b/ui/build/config.go
index ecca4de..1152cd7 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -617,19 +617,19 @@
 
 	// For LANG and LC_*, only preserve the evaluated version of
 	// LC_MESSAGES
-	user_lang := ""
+	userLang := ""
 	if lc_all, ok := c.environ.Get("LC_ALL"); ok {
-		user_lang = lc_all
+		userLang = lc_all
 	} else if lc_messages, ok := c.environ.Get("LC_MESSAGES"); ok {
-		user_lang = lc_messages
+		userLang = lc_messages
 	} else if lang, ok := c.environ.Get("LANG"); ok {
-		user_lang = lang
+		userLang = lang
 	}
 
 	c.environ.UnsetWithPrefix("LC_")
 
-	if user_lang != "" {
-		c.environ.Set("LC_MESSAGES", user_lang)
+	if userLang != "" {
+		c.environ.Set("LC_MESSAGES", userLang)
 	}
 
 	// The for LANG, use C.UTF-8 if it exists (Debian currently, proposed
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 999af07..fe0aca9 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -254,7 +254,7 @@
 		"BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY",
 	}, exportEnvVars...), BannerVars...)
 
-	make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "")
+	makeVars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "")
 	if err != nil {
 		ctx.Fatalln("Error dumping make vars:", err)
 	}
@@ -262,24 +262,24 @@
 	env := config.Environment()
 	// Print the banner like make does
 	if !env.IsEnvTrue("ANDROID_QUIET_BUILD") {
-		fmt.Fprintln(ctx.Writer, Banner(make_vars))
+		fmt.Fprintln(ctx.Writer, Banner(makeVars))
 	}
 
 	// Populate the environment
 	for _, name := range exportEnvVars {
-		if make_vars[name] == "" {
+		if makeVars[name] == "" {
 			env.Unset(name)
 		} else {
-			env.Set(name, make_vars[name])
+			env.Set(name, makeVars[name])
 		}
 	}
 
-	config.SetKatiArgs(strings.Fields(make_vars["KATI_GOALS"]))
-	config.SetNinjaArgs(strings.Fields(make_vars["NINJA_GOALS"]))
-	config.SetTargetDevice(make_vars["TARGET_DEVICE"])
-	config.SetTargetDeviceDir(make_vars["TARGET_DEVICE_DIR"])
+	config.SetKatiArgs(strings.Fields(makeVars["KATI_GOALS"]))
+	config.SetNinjaArgs(strings.Fields(makeVars["NINJA_GOALS"]))
+	config.SetTargetDevice(makeVars["TARGET_DEVICE"])
+	config.SetTargetDeviceDir(makeVars["TARGET_DEVICE_DIR"])
 
-	config.SetBuildBrokenDupRules(make_vars["BUILD_BROKEN_DUP_RULES"] == "true")
-	config.SetBuildBrokenUsesNetwork(make_vars["BUILD_BROKEN_USES_NETWORK"] == "true")
-	config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(make_vars["BUILD_BROKEN_NINJA_USES_ENV_VARS"]))
+	config.SetBuildBrokenDupRules(makeVars["BUILD_BROKEN_DUP_RULES"] == "true")
+	config.SetBuildBrokenUsesNetwork(makeVars["BUILD_BROKEN_USES_NETWORK"] == "true")
+	config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(makeVars["BUILD_BROKEN_NINJA_USES_ENV_VARS"]))
 }
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 41acc26..a910c06 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -50,10 +50,10 @@
 	// Get a list of leaf nodes in the dependency graph from ninja
 	executable := config.PrebuiltBuildTool("ninja")
 
-	common_args := []string{}
-	common_args = append(common_args, config.NinjaArgs()...)
-	common_args = append(common_args, "-f", config.CombinedNinjaFile())
-	args := append(common_args, "-t", "targets", "rule")
+	commonArgs := []string{}
+	commonArgs = append(commonArgs, config.NinjaArgs()...)
+	commonArgs = append(commonArgs, "-f", config.CombinedNinjaFile())
+	args := append(commonArgs, "-t", "targets", "rule")
 
 	cmd := Command(ctx, config, "ninja", executable, args...)
 	stdout, err := cmd.StdoutPipe()
@@ -114,28 +114,28 @@
 		title := "Dependencies in out found with no rule to create them:"
 		fmt.Fprintln(sb, title)
 
-		report_lines := 1
+		reportLines := 1
 		for i, dep := range danglingRulesList {
-			if report_lines > 20 {
+			if reportLines > 20 {
 				fmt.Fprintf(sb, "  ... and %d more\n", len(danglingRulesList)-i)
 				break
 			}
 			// It's helpful to see the reverse dependencies. ninja -t query is the
 			// best tool we got for that. Its output starts with the dependency
 			// itself.
-			query_cmd := Command(ctx, config, "ninja", executable,
-				append(common_args, "-t", "query", dep)...)
-			query_stdout, err := query_cmd.StdoutPipe()
+			queryCmd := Command(ctx, config, "ninja", executable,
+				append(commonArgs, "-t", "query", dep)...)
+			queryStdout, err := queryCmd.StdoutPipe()
 			if err != nil {
 				ctx.Fatal(err)
 			}
-			query_cmd.StartOrFatal()
-			scanner := bufio.NewScanner(query_stdout)
+			queryCmd.StartOrFatal()
+			scanner := bufio.NewScanner(queryStdout)
 			for scanner.Scan() {
-				report_lines++
+				reportLines++
 				fmt.Fprintln(sb, " ", scanner.Text())
 			}
-			query_cmd.WaitOrFatal()
+			queryCmd.WaitOrFatal()
 		}
 
 		ts.FinishAction(status.ActionResult{
diff --git a/ui/terminal/util.go b/ui/terminal/util.go
index 7a603d7..28d97fe 100644
--- a/ui/terminal/util.go
+++ b/ui/terminal/util.go
@@ -41,13 +41,13 @@
 func termSize(w io.Writer) (width int, height int, ok bool) {
 	if f, ok := w.(*os.File); ok {
 		var winsize struct {
-			ws_row, ws_column    uint16
-			ws_xpixel, ws_ypixel uint16
+			wsRow, wsColumn    uint16
+			wsXpixel, wsYpixel uint16
 		}
 		_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, f.Fd(),
 			syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&winsize)),
 			0, 0, 0)
-		return int(winsize.ws_column), int(winsize.ws_row), err == 0
+		return int(winsize.wsColumn), int(winsize.wsRow), err == 0
 	} else if f, ok := w.(*fakeSmartTerminal); ok {
 		return f.termWidth, f.termHeight, true
 	}