Merge changes from topic "soong-license-metadata"

* changes:
  Add dependency license annotations
  Build license metadata files in Soong
  Escape Host*Variable contents
diff --git a/android/Android.bp b/android/Android.bp
index a20aedc..da36959 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -47,6 +47,7 @@
         "image.go",
         "license.go",
         "license_kind.go",
+        "license_metadata.go",
         "license_sdk_member.go",
         "licenses.go",
         "makefile_goal.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 1f03aa8..4f6e24c 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -474,6 +474,7 @@
 	ModuleDir(module blueprint.Module) string
 	Config() Config
 	ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
+	ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
 }
 
 func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) {
@@ -609,6 +610,11 @@
 		}
 	}
 
+	if ctx.ModuleHasProvider(mod, LicenseMetadataProvider) {
+		licenseMetadata := ctx.ModuleProvider(mod, LicenseMetadataProvider).(*LicenseMetadataInfo)
+		a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
+	}
+
 	extraCtx := &androidMkExtraEntriesContext{
 		ctx: ctx,
 		mod: mod,
diff --git a/android/license_metadata.go b/android/license_metadata.go
new file mode 100644
index 0000000..3bc53d6
--- /dev/null
+++ b/android/license_metadata.go
@@ -0,0 +1,231 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+var (
+	_ = pctx.HostBinToolVariable("licenseMetadataCmd", "build_license_metadata")
+
+	licenseMetadataRule = pctx.AndroidStaticRule("licenseMetadataRule", blueprint.RuleParams{
+		Command:        "${licenseMetadataCmd} -o $out @${out}.rsp",
+		CommandDeps:    []string{"${licenseMetadataCmd}"},
+		Rspfile:        "${out}.rsp",
+		RspfileContent: "${args}",
+	}, "args")
+)
+
+func buildLicenseMetadata(ctx ModuleContext) {
+	base := ctx.Module().base()
+
+	if !base.Enabled() {
+		return
+	}
+
+	if exemptFromRequiredApplicableLicensesProperty(ctx.Module()) {
+		return
+	}
+
+	var allDepMetadataFiles Paths
+	var allDepMetadataArgs []string
+	var allDepOutputFiles Paths
+
+	ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) {
+		dep, _ := bpdep.(Module)
+		if dep == nil {
+			return
+		}
+		if !dep.Enabled() {
+			return
+		}
+
+		if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
+			info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
+			allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
+
+			depAnnotations := licenseAnnotationsFromTag(ctx.OtherModuleDependencyTag(dep))
+
+			allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations)
+
+			if depInstallFiles := dep.base().installFiles; len(depInstallFiles) > 0 {
+				allDepOutputFiles = append(allDepOutputFiles, depInstallFiles.Paths()...)
+			} else if depOutputFiles, err := outputFilesForModule(ctx, dep, ""); err == nil {
+				depOutputFiles = PathsIfNonNil(depOutputFiles...)
+				allDepOutputFiles = append(allDepOutputFiles, depOutputFiles...)
+			}
+		}
+	})
+
+	allDepMetadataFiles = SortedUniquePaths(allDepMetadataFiles)
+	sort.Strings(allDepMetadataArgs)
+	allDepOutputFiles = SortedUniquePaths(allDepOutputFiles)
+
+	var orderOnlyDeps Paths
+	var args []string
+
+	if t := ctx.ModuleType(); t != "" {
+		args = append(args,
+			"-mt "+proptools.NinjaAndShellEscape(t))
+	}
+
+	args = append(args,
+		"-r "+proptools.NinjaAndShellEscape(ctx.ModuleDir()),
+		"-mc UNKNOWN")
+
+	if p := base.commonProperties.Effective_package_name; p != nil {
+		args = append(args,
+			"-p "+proptools.NinjaAndShellEscape(*p))
+	}
+
+	args = append(args,
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_kinds), "-k "))
+
+	args = append(args,
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_conditions), "-c "))
+
+	args = append(args,
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n "))
+
+	args = append(args,
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepMetadataArgs), "-d "))
+	orderOnlyDeps = append(orderOnlyDeps, allDepMetadataFiles...)
+
+	args = append(args,
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepOutputFiles.Strings()), "-s "))
+
+	// Install map
+	args = append(args,
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m "))
+
+	// Built files
+	var outputFiles Paths
+	if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok {
+		outputFiles, _ = outputFileProducer.OutputFiles("")
+		outputFiles = PathsIfNonNil(outputFiles...)
+	}
+
+	if len(outputFiles) > 0 {
+		args = append(args,
+			JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t "))
+	} else {
+		args = append(args, fmt.Sprintf("-t //%s:%s", ctx.ModuleDir(), ctx.ModuleName()))
+	}
+
+	// Installed files
+	args = append(args,
+		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i "))
+
+	isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles)
+	if isContainer {
+		args = append(args, "--is_container")
+	}
+
+	licenseMetadataFile := PathForModuleOut(ctx, "meta_lic")
+
+	ctx.Build(pctx, BuildParams{
+		Rule:        licenseMetadataRule,
+		Output:      licenseMetadataFile,
+		OrderOnly:   orderOnlyDeps,
+		Description: "license metadata",
+		Args: map[string]string{
+			"args": strings.Join(args, " "),
+		},
+	})
+
+	ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{
+		LicenseMetadataPath: licenseMetadataFile,
+	})
+}
+
+func isContainerFromFileExtensions(installPaths InstallPaths, builtPaths Paths) bool {
+	var paths Paths
+	if len(installPaths) > 0 {
+		paths = installPaths.Paths()
+	} else {
+		paths = builtPaths
+	}
+
+	for _, path := range paths {
+		switch path.Ext() {
+		case ".zip", ".tar", ".tgz", ".tar.gz", ".img", ".srcszip", ".apex":
+			return true
+		}
+	}
+
+	return false
+}
+
+// LicenseMetadataProvider is used to propagate license metadata paths between modules.
+var LicenseMetadataProvider = blueprint.NewProvider(&LicenseMetadataInfo{})
+
+// LicenseMetadataInfo stores the license metadata path for a module.
+type LicenseMetadataInfo struct {
+	LicenseMetadataPath Path
+}
+
+// licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into
+// a string, or an empty string if there are none.
+func licenseAnnotationsFromTag(tag blueprint.DependencyTag) string {
+	if annoTag, ok := tag.(LicenseAnnotationsDependencyTag); ok {
+		annos := annoTag.LicenseAnnotations()
+		if len(annos) > 0 {
+			annoStrings := make([]string, len(annos))
+			for i, s := range annos {
+				annoStrings[i] = string(s)
+			}
+			return ":" + strings.Join(annoStrings, ",")
+		}
+	}
+	return ""
+}
+
+// LicenseAnnotationsDependencyTag is implemented by dependency tags in order to provide a
+// list of license dependency annotations.
+type LicenseAnnotationsDependencyTag interface {
+	LicenseAnnotations() []LicenseAnnotation
+}
+
+// LicenseAnnotation is an enum of annotations that can be applied to dependencies for propagating
+// license information.
+type LicenseAnnotation string
+
+const (
+	// LicenseAnnotationSharedDependency should be returned by LicenseAnnotations implementations
+	// of dependency tags when the usage of the dependency is dynamic, for example a shared library
+	// linkage for native modules or as a classpath library for java modules.
+	LicenseAnnotationSharedDependency LicenseAnnotation = "dynamic"
+
+	// LicenseAnnotationToolchain should be returned by LicenseAnnotations implementations of
+	// dependency tags when the dependency is used as a toolchain.
+	//
+	// Dependency tags that need to always return LicenseAnnotationToolchain
+	// can embed LicenseAnnotationToolchainDependencyTag to implement LicenseAnnotations.
+	LicenseAnnotationToolchain LicenseAnnotation = "toolchain"
+)
+
+// LicenseAnnotationToolchainDependencyTag can be embedded in a dependency tag to implement
+// LicenseAnnotations that always returns LicenseAnnotationToolchain.
+type LicenseAnnotationToolchainDependencyTag struct{}
+
+func (LicenseAnnotationToolchainDependencyTag) LicenseAnnotations() []LicenseAnnotation {
+	return []LicenseAnnotation{LicenseAnnotationToolchain}
+}
diff --git a/android/module.go b/android/module.go
index c2cb617..6c7fc65 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1227,6 +1227,10 @@
 
 	initRcPaths         Paths
 	vintfFragmentsPaths Paths
+
+	// set of dependency module:location mappings used to populate the license metadata for
+	// apex containers.
+	licenseInstallMap []string
 }
 
 // A struct containing all relevant information about a Bazel target converted via bp2build.
@@ -1773,6 +1777,12 @@
 	return append(Paths{}, m.vintfFragmentsPaths...)
 }
 
+// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an
+// apex container for use when generation the license metadata file.
+func (m *ModuleBase) SetLicenseInstallMap(installMap []string) {
+	m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
+}
+
 func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
 	var allInstalledFiles InstallPaths
 	var allCheckbuildFiles Paths
@@ -2038,6 +2048,8 @@
 	m.installFilesDepSet = newInstallPathsDepSet(m.installFiles, dependencyInstallFiles)
 	m.packagingSpecsDepSet = newPackagingSpecsDepSet(m.packagingSpecs, dependencyPackagingSpecs)
 
+	buildLicenseMetadata(ctx)
+
 	m.buildParams = ctx.buildParams
 	m.ruleParams = ctx.ruleParams
 	m.variables = ctx.variables
diff --git a/android/package_ctx.go b/android/package_ctx.go
index c19debb..f354db8 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -19,6 +19,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/remoteexec"
 )
@@ -173,7 +174,7 @@
 // package-scoped variable's initialization.
 func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
 	return p.VariableFunc(name, func(ctx PackageVarContext) string {
-		return ctx.Config().HostToolPath(ctx, path).String()
+		return proptools.NinjaAndShellEscape(ctx.Config().HostToolPath(ctx, path).String())
 	})
 }
 
@@ -183,7 +184,7 @@
 // package-scoped variable's initialization.
 func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variable {
 	return p.VariableFunc(name, func(ctx PackageVarContext) string {
-		return ctx.Config().HostJNIToolPath(ctx, path).String()
+		return proptools.NinjaAndShellEscape(ctx.Config().HostJNIToolPath(ctx, path).String())
 	})
 }
 
@@ -193,7 +194,7 @@
 // part of a package-scoped variable's initialization.
 func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
 	return p.VariableFunc(name, func(ctx PackageVarContext) string {
-		return ctx.Config().HostJavaToolPath(ctx, path).String()
+		return proptools.NinjaAndShellEscape(ctx.Config().HostJavaToolPath(ctx, path).String())
 	})
 }
 
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 7764b6b..f001fa2 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -309,19 +309,17 @@
 	return moduleNames
 }
 
-func (a *apexBundle) writeRequiredModules(w io.Writer, apexBundleName string) {
+func (a *apexBundle) writeRequiredModules(w io.Writer) {
 	var required []string
 	var targetRequired []string
 	var hostRequired []string
 	required = append(required, a.RequiredModuleNames()...)
 	targetRequired = append(targetRequired, a.TargetRequiredModuleNames()...)
 	hostRequired = append(hostRequired, a.HostRequiredModuleNames()...)
-	installMapSet := make(map[string]bool) // set of dependency module:location mappings
 	for _, fi := range a.filesInfo {
 		required = append(required, fi.requiredModuleNames...)
 		targetRequired = append(targetRequired, fi.targetRequiredModuleNames...)
 		hostRequired = append(hostRequired, fi.hostRequiredModuleNames...)
-		installMapSet[a.fullModuleName(apexBundleName, &fi)+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
 	}
 
 	if len(required) > 0 {
@@ -333,11 +331,6 @@
 	if len(hostRequired) > 0 {
 		fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES +=", strings.Join(hostRequired, " "))
 	}
-	if len(installMapSet) > 0 {
-		var installs []string
-		installs = append(installs, android.SortedStringKeys(installMapSet)...)
-		fmt.Fprintln(w, "LOCAL_LICENSE_INSTALL_MAP +=", strings.Join(installs, " "))
-	}
 }
 
 func (a *apexBundle) androidMkForType() android.AndroidMkData {
@@ -359,7 +352,7 @@
 				if len(moduleNames) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
 				}
-				a.writeRequiredModules(w, name)
+				a.writeRequiredModules(w)
 				fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
 
 			} else {
@@ -401,7 +394,7 @@
 				if len(a.requiredDeps) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.requiredDeps, " "))
 				}
-				a.writeRequiredModules(w, name)
+				a.writeRequiredModules(w)
 
 				if a.mergedNotices.Merged.Valid() {
 					fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNotices.Merged.Path().String())
diff --git a/apex/builder.go b/apex/builder.go
index 0880e2b..5910784 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -434,7 +434,10 @@
 	// Avoid creating duplicate build rules for multi-installed APEXes.
 	if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
 		installSymbolFiles = false
+
 	}
+	// set of dependency module:location mappings
+	installMapSet := make(map[string]bool)
 
 	// TODO(jiyong): use the RuleBuilder
 	var copyCommands []string
@@ -442,7 +445,6 @@
 	pathWhenActivated := android.PathForModuleInPartitionInstall(ctx, "apex", apexName)
 	for _, fi := range a.filesInfo {
 		destPath := imageDir.Join(ctx, fi.path()).String()
-		var installedPath android.InstallPath
 		// Prepare the destination path
 		destPathDir := filepath.Dir(destPath)
 		if fi.class == appSet {
@@ -450,6 +452,8 @@
 		}
 		copyCommands = append(copyCommands, "mkdir -p "+destPathDir)
 
+		installMapPath := fi.builtFile
+
 		// Copy the built file to the directory. But if the symlink optimization is turned
 		// on, place a symlink to the corresponding file in /system partition instead.
 		if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
@@ -457,6 +461,7 @@
 			pathOnDevice := filepath.Join("/system", fi.path())
 			copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
 		} else {
+			var installedPath android.InstallPath
 			if fi.class == appSet {
 				copyCommands = append(copyCommands,
 					fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
@@ -475,17 +480,19 @@
 			if installSymbolFiles {
 				implicitInputs = append(implicitInputs, installedPath)
 			}
-		}
 
-		// Create additional symlinks pointing the file inside the APEX (if any). Note that
-		// this is independent from the symlink optimization.
-		for _, symlinkPath := range fi.symlinkPaths() {
-			symlinkDest := imageDir.Join(ctx, symlinkPath).String()
-			copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
-			if installSymbolFiles {
-				installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
-				implicitInputs = append(implicitInputs, installedSymlink)
+			// Create additional symlinks pointing the file inside the APEX (if any). Note that
+			// this is independent from the symlink optimization.
+			for _, symlinkPath := range fi.symlinkPaths() {
+				symlinkDest := imageDir.Join(ctx, symlinkPath).String()
+				copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
+				if installSymbolFiles {
+					installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
+					implicitInputs = append(implicitInputs, installedSymlink)
+				}
 			}
+
+			installMapPath = installedPath
 		}
 
 		// Copy the test files (if any)
@@ -502,6 +509,8 @@
 			copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
 			implicitInputs = append(implicitInputs, d.SrcPath)
 		}
+
+		installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
 	}
 	implicitInputs = append(implicitInputs, a.manifestPbOut)
 	if installSymbolFiles {
@@ -510,6 +519,12 @@
 		implicitInputs = append(implicitInputs, installedManifest, installedKey)
 	}
 
+	if len(installMapSet) > 0 {
+		var installs []string
+		installs = append(installs, android.SortedStringKeys(installMapSet)...)
+		a.SetLicenseInstallMap(installs)
+	}
+
 	////////////////////////////////////////////////////////////////////////////////////////////
 	// Step 1.a: Write the list of files in this APEX to a txt file and compare it against
 	// the allowed list given via the allowed_files property. Build fails when the two lists
diff --git a/cc/cc.go b/cc/cc.go
index b3b8f8c..39fdcb7 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -686,6 +686,15 @@
 	return d.Kind == staticLibraryDependency
 }
 
+func (d libraryDependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
+	if d.shared() {
+		return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
+	}
+	return nil
+}
+
+var _ android.LicenseAnnotationsDependencyTag = libraryDependencyTag{}
+
 // InstallDepNeeded returns true for shared libraries so that shared library dependencies of
 // binaries or other shared libraries are installed as dependencies.
 func (d libraryDependencyTag) InstallDepNeeded() bool {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index c9bf958..e7343a2 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -110,6 +110,7 @@
 
 type hostToolDependencyTag struct {
 	blueprint.BaseDependencyTag
+	android.LicenseAnnotationToolchainDependencyTag
 	label string
 }
 type generatorProperties struct {
diff --git a/java/java.go b/java/java.go
index e599146..e7b1f4f 100644
--- a/java/java.go
+++ b/java/java.go
@@ -270,6 +270,9 @@
 type dependencyTag struct {
 	blueprint.BaseDependencyTag
 	name string
+
+	// True if the dependency is relinked at runtime.
+	runtimeLinked bool
 }
 
 // installDependencyTag is a dependency tag that is annotated to cause the installed files of the
@@ -280,6 +283,15 @@
 	name string
 }
 
+func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
+	if d.runtimeLinked {
+		return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
+	}
+	return nil
+}
+
+var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
+
 type usesLibraryDependencyTag struct {
 	dependencyTag
 
@@ -296,10 +308,13 @@
 
 func makeUsesLibraryDependencyTag(sdkVersion int, optional bool, implicit bool) usesLibraryDependencyTag {
 	return usesLibraryDependencyTag{
-		dependencyTag: dependencyTag{name: fmt.Sprintf("uses-library-%d", sdkVersion)},
-		sdkVersion:    sdkVersion,
-		optional:      optional,
-		implicit:      implicit,
+		dependencyTag: dependencyTag{
+			name:          fmt.Sprintf("uses-library-%d", sdkVersion),
+			runtimeLinked: true,
+		},
+		sdkVersion: sdkVersion,
+		optional:   optional,
+		implicit:   implicit,
 	}
 }
 
@@ -310,22 +325,22 @@
 var (
 	dataNativeBinsTag       = dependencyTag{name: "dataNativeBins"}
 	staticLibTag            = dependencyTag{name: "staticlib"}
-	libTag                  = dependencyTag{name: "javalib"}
-	java9LibTag             = dependencyTag{name: "java9lib"}
+	libTag                  = dependencyTag{name: "javalib", runtimeLinked: true}
+	java9LibTag             = dependencyTag{name: "java9lib", runtimeLinked: true}
 	pluginTag               = dependencyTag{name: "plugin"}
 	errorpronePluginTag     = dependencyTag{name: "errorprone-plugin"}
 	exportedPluginTag       = dependencyTag{name: "exported-plugin"}
-	bootClasspathTag        = dependencyTag{name: "bootclasspath"}
-	systemModulesTag        = dependencyTag{name: "system modules"}
+	bootClasspathTag        = dependencyTag{name: "bootclasspath", runtimeLinked: true}
+	systemModulesTag        = dependencyTag{name: "system modules", runtimeLinked: true}
 	frameworkResTag         = dependencyTag{name: "framework-res"}
-	kotlinStdlibTag         = dependencyTag{name: "kotlin-stdlib"}
-	kotlinAnnotationsTag    = dependencyTag{name: "kotlin-annotations"}
+	kotlinStdlibTag         = dependencyTag{name: "kotlin-stdlib", runtimeLinked: true}
+	kotlinAnnotationsTag    = dependencyTag{name: "kotlin-annotations", runtimeLinked: true}
 	kotlinPluginTag         = dependencyTag{name: "kotlin-plugin"}
 	proguardRaiseTag        = dependencyTag{name: "proguard-raise"}
 	certificateTag          = dependencyTag{name: "certificate"}
 	instrumentationForTag   = dependencyTag{name: "instrumentation_for"}
 	extraLintCheckTag       = dependencyTag{name: "extra-lint-check"}
-	jniLibTag               = dependencyTag{name: "jnilib"}
+	jniLibTag               = dependencyTag{name: "jnilib", runtimeLinked: true}
 	syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
 	jniInstallTag           = installDependencyTag{name: "jni install"}
 	binaryInstallTag        = installDependencyTag{name: "binary install"}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 52ab06e..de0d796 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1222,11 +1222,16 @@
 
 func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
 	paths, err := module.commonOutputFiles(tag)
-	if paths == nil && err == nil {
-		return module.Library.OutputFiles(tag)
-	} else {
+	if paths != nil || err != nil {
 		return paths, err
 	}
+	if module.requiresRuntimeImplementationLibrary() {
+		return module.Library.OutputFiles(tag)
+	}
+	if tag == "" {
+		return nil, nil
+	}
+	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 }
 
 func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/rust/rust.go b/rust/rust.go
index b575c7a..300c0f5 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -969,6 +969,7 @@
 	name      string
 	library   bool
 	procMacro bool
+	dynamic   bool
 }
 
 // InstallDepNeeded returns true for rlibs, dylibs, and proc macros so that they or their transitive
@@ -979,10 +980,19 @@
 
 var _ android.InstallNeededDependencyTag = dependencyTag{}
 
+func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
+	if d.library && d.dynamic {
+		return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
+	}
+	return nil
+}
+
+var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
+
 var (
 	customBindgenDepTag = dependencyTag{name: "customBindgenTag"}
 	rlibDepTag          = dependencyTag{name: "rlibTag", library: true}
-	dylibDepTag         = dependencyTag{name: "dylib", library: true}
+	dylibDepTag         = dependencyTag{name: "dylib", library: true, dynamic: true}
 	procMacroDepTag     = dependencyTag{name: "procMacro", procMacro: true}
 	testPerSrcDepTag    = dependencyTag{name: "rust_unit_tests"}
 	sourceDepTag        = dependencyTag{name: "source"}