Merge "Update soong copy of java binaries when Make copy is installed"
diff --git a/android/filegroup.go b/android/filegroup.go
index 674a196..c3bf6f8 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -57,9 +57,9 @@
 		Srcs: BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs),
 	}
 
-	props := bazel.NewBazelTargetModuleProperties(fg.Name(), "filegroup", "")
+	props := bazel.BazelTargetModuleProperties{Rule_class: "filegroup"}
 
-	ctx.CreateBazelTargetModule(BazelFileGroupFactory, props, attrs)
+	ctx.CreateBazelTargetModule(BazelFileGroupFactory, fg.Name(), props, attrs)
 }
 
 type fileGroupProperties struct {
diff --git a/android/module.go b/android/module.go
index bf74cad..58675d4 100644
--- a/android/module.go
+++ b/android/module.go
@@ -507,13 +507,17 @@
 type BazelTargetModule interface {
 	Module
 
-	BazelTargetModuleProperties() *bazel.BazelTargetModuleProperties
+	bazelTargetModuleProperties() *bazel.BazelTargetModuleProperties
+	SetBazelTargetModuleProperties(props bazel.BazelTargetModuleProperties)
+
+	RuleClass() string
+	BzlLoadLocation() string
 }
 
 // InitBazelTargetModule is a wrapper function that decorates BazelTargetModule
 // with property structs containing metadata for bp2build conversion.
 func InitBazelTargetModule(module BazelTargetModule) {
-	module.AddProperties(module.BazelTargetModuleProperties())
+	module.AddProperties(module.bazelTargetModuleProperties())
 	InitAndroidModule(module)
 }
 
@@ -524,11 +528,26 @@
 	Properties bazel.BazelTargetModuleProperties
 }
 
-// BazelTargetModuleProperties getter.
-func (btmb *BazelTargetModuleBase) BazelTargetModuleProperties() *bazel.BazelTargetModuleProperties {
+// bazelTargetModuleProperties getter.
+func (btmb *BazelTargetModuleBase) bazelTargetModuleProperties() *bazel.BazelTargetModuleProperties {
 	return &btmb.Properties
 }
 
+// SetBazelTargetModuleProperties setter for BazelTargetModuleProperties
+func (btmb *BazelTargetModuleBase) SetBazelTargetModuleProperties(props bazel.BazelTargetModuleProperties) {
+	btmb.Properties = props
+}
+
+// RuleClass returns the rule class for this Bazel target
+func (b *BazelTargetModuleBase) RuleClass() string {
+	return b.bazelTargetModuleProperties().Rule_class
+}
+
+// BzlLoadLocation returns the rule class for this Bazel target
+func (b *BazelTargetModuleBase) BzlLoadLocation() string {
+	return b.bazelTargetModuleProperties().Bzl_load_location
+}
+
 // Qualified id for a module
 type qualifiedModuleName struct {
 	// The package (i.e. directory) in which the module is defined, without trailing /
diff --git a/android/mutator.go b/android/mutator.go
index c387193..b023001 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -283,7 +283,7 @@
 	// factory method, just like in CreateModule, but also requires
 	// BazelTargetModuleProperties containing additional metadata for the
 	// bp2build codegenerator.
-	CreateBazelTargetModule(ModuleFactory, bazel.BazelTargetModuleProperties, interface{}) BazelTargetModule
+	CreateBazelTargetModule(ModuleFactory, string, bazel.BazelTargetModuleProperties, interface{}) BazelTargetModule
 }
 
 type topDownMutatorContext struct {
@@ -513,17 +513,25 @@
 
 func (t *topDownMutatorContext) CreateBazelTargetModule(
 	factory ModuleFactory,
+	name string,
 	bazelProps bazel.BazelTargetModuleProperties,
 	attrs interface{}) BazelTargetModule {
-	if !strings.HasPrefix(*bazelProps.Name, bazel.BazelTargetModuleNamePrefix) {
+	if strings.HasPrefix(name, bazel.BazelTargetModuleNamePrefix) {
 		panic(fmt.Errorf(
-			"bp2build error: the bazel target module name must start with '%s': %s",
+			"The %s name prefix is added automatically, do not set it manually: %s",
 			bazel.BazelTargetModuleNamePrefix,
-			*bazelProps.Name,
-		))
+			name))
+	}
+	name = bazel.BazelTargetModuleNamePrefix + name
+	nameProp := struct {
+		Name *string
+	}{
+		Name: &name,
 	}
 
-	return t.CreateModule(factory, &bazelProps, attrs).(BazelTargetModule)
+	b := t.CreateModule(factory, &nameProp, attrs).(BazelTargetModule)
+	b.SetBazelTargetModuleProperties(bazelProps)
+	return b
 }
 
 func (t *topDownMutatorContext) AppendProperties(props ...interface{}) {
diff --git a/bazel/properties.go b/bazel/properties.go
index 8055306..a4df4bc 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -14,11 +14,6 @@
 
 package bazel
 
-import (
-	"fmt"
-	"strings"
-)
-
 type bazelModuleProperties struct {
 	// The label of the Bazel target replacing this Soong module.
 	Label string
@@ -37,32 +32,15 @@
 // BazelTargetModuleProperties contain properties and metadata used for
 // Blueprint to BUILD file conversion.
 type BazelTargetModuleProperties struct {
-	Name *string
-
 	// The Bazel rule class for this target.
-	Rule_class string
+	Rule_class string `blueprint:"mutated"`
 
 	// The target label for the bzl file containing the definition of the rule class.
-	Bzl_load_location string
+	Bzl_load_location string `blueprint:"mutated"`
 }
 
 const BazelTargetModuleNamePrefix = "__bp2build__"
 
-func NewBazelTargetModuleProperties(name string, ruleClass string, bzlLoadLocation string) BazelTargetModuleProperties {
-	if strings.HasPrefix(name, BazelTargetModuleNamePrefix) {
-		panic(fmt.Errorf(
-			"The %s name prefix is added automatically, do not set it manually: %s",
-			BazelTargetModuleNamePrefix,
-			name))
-	}
-	name = BazelTargetModuleNamePrefix + name
-	return BazelTargetModuleProperties{
-		Name:              &name,
-		Rule_class:        ruleClass,
-		Bzl_load_location: bzlLoadLocation,
-	}
-}
-
 // Label is used to represent a Bazel compatible Label. Also stores the original bp text to support
 // string replacement.
 type Label struct {
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 41ad409..a4c4a0d 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -19,7 +19,6 @@
 	"android/soong/bazel"
 	"fmt"
 	"reflect"
-	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -178,13 +177,14 @@
 
 		switch ctx.Mode() {
 		case Bp2Build:
-			if _, ok := m.(android.BazelTargetModule); !ok {
+			if b, ok := m.(android.BazelTargetModule); !ok {
 				// Only include regular Soong modules (non-BazelTargetModules) into the total count.
 				totalModuleCount += 1
 				return
+			} else {
+				t = generateBazelTarget(bpCtx, m, b)
+				ruleClassCount[t.ruleClass] += 1
 			}
-			t = generateBazelTarget(bpCtx, m)
-			ruleClassCount[t.ruleClass] += 1
 		case QueryView:
 			// Blocklist certain module types from being generated.
 			if canonicalizeModuleType(bpCtx.ModuleType(m)) == "package" {
@@ -208,36 +208,13 @@
 	return buildFileToTargets, metrics
 }
 
-// Helper method to trim quotes around strings.
-func trimQuotes(s string) string {
-	if s == "" {
-		// strconv.Unquote would error out on empty strings, but this method
-		// allows them, so return the empty string directly.
-		return ""
-	}
-	ret, err := strconv.Unquote(s)
-	if err != nil {
-		// Panic the error immediately.
-		panic(fmt.Errorf("Trying to unquote '%s', but got error: %s", s, err))
-	}
-	return ret
-}
+func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module, b android.BazelTargetModule) BazelTarget {
+	ruleClass := b.RuleClass()
+	bzlLoadLocation := b.BzlLoadLocation()
 
-func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module) BazelTarget {
 	// extract the bazel attributes from the module.
 	props := getBuildProperties(ctx, m)
 
-	// extract the rule class name from the attributes. Since the string value
-	// will be string-quoted, remove the quotes here.
-	ruleClass := trimQuotes(props.Attrs["rule_class"])
-	// Delete it from being generated in the BUILD file.
-	delete(props.Attrs, "rule_class")
-
-	// extract the bzl_load_location, and also remove the quotes around it here.
-	bzlLoadLocation := trimQuotes(props.Attrs["bzl_load_location"])
-	// Delete it from being generated in the BUILD file.
-	delete(props.Attrs, "bzl_load_location")
-
 	delete(props.Attrs, "bp2build_available")
 
 	// Return the Bazel target with rule class and attributes, ready to be
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 9774915..cb50fc8 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -136,9 +136,11 @@
 			String_list_prop: m.props.String_list_prop,
 		}
 
-		props := bazel.NewBazelTargetModuleProperties(m.Name(), "custom", "")
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class: "custom",
+		}
 
-		ctx.CreateBazelTargetModule(customBazelModuleFactory, props, attrs)
+		ctx.CreateBazelTargetModule(customBazelModuleFactory, m.Name(), props, attrs)
 	}
 }
 
@@ -153,26 +155,23 @@
 		baseName := m.Name()
 		attrs := &customBazelModuleAttributes{}
 
-		myLibraryProps := bazel.NewBazelTargetModuleProperties(
-			baseName,
-			"my_library",
-			"//build/bazel/rules:rules.bzl",
-		)
-		ctx.CreateBazelTargetModule(customBazelModuleFactory, myLibraryProps, attrs)
+		myLibraryProps := bazel.BazelTargetModuleProperties{
+			Rule_class:        "my_library",
+			Bzl_load_location: "//build/bazel/rules:rules.bzl",
+		}
+		ctx.CreateBazelTargetModule(customBazelModuleFactory, baseName, myLibraryProps, attrs)
 
-		protoLibraryProps := bazel.NewBazelTargetModuleProperties(
-			baseName+"_proto_library_deps",
-			"proto_library",
-			"//build/bazel/rules:proto.bzl",
-		)
-		ctx.CreateBazelTargetModule(customBazelModuleFactory, protoLibraryProps, attrs)
+		protoLibraryProps := bazel.BazelTargetModuleProperties{
+			Rule_class:        "proto_library",
+			Bzl_load_location: "//build/bazel/rules:proto.bzl",
+		}
+		ctx.CreateBazelTargetModule(customBazelModuleFactory, baseName+"_proto_library_deps", protoLibraryProps, attrs)
 
-		myProtoLibraryProps := bazel.NewBazelTargetModuleProperties(
-			baseName+"_my_proto_library_deps",
-			"my_proto_library",
-			"//build/bazel/rules:proto.bzl",
-		)
-		ctx.CreateBazelTargetModule(customBazelModuleFactory, myProtoLibraryProps, attrs)
+		myProtoLibraryProps := bazel.BazelTargetModuleProperties{
+			Rule_class:        "my_proto_library",
+			Bzl_load_location: "//build/bazel/rules:proto.bzl",
+		}
+		ctx.CreateBazelTargetModule(customBazelModuleFactory, baseName+"_my_proto_library_deps", myProtoLibraryProps, attrs)
 	}
 }
 
diff --git a/cc/library_headers.go b/cc/library_headers.go
index e5a5557..03450c6 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -129,13 +129,12 @@
 		Deps:     headerLibLabels,
 	}
 
-	props := bazel.NewBazelTargetModuleProperties(
-		module.Name(),
-		"cc_library_headers",
-		"//build/bazel/rules:cc_library_headers.bzl",
-	)
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "cc_library_headers",
+		Bzl_load_location: "//build/bazel/rules:cc_library_headers.bzl",
+	}
 
-	ctx.CreateBazelTargetModule(BazelCcLibraryHeadersFactory, props, attrs)
+	ctx.CreateBazelTargetModule(BazelCcLibraryHeadersFactory, module.Name(), props, attrs)
 }
 
 func (m *bazelCcLibraryHeaders) Name() string {
diff --git a/cc/object.go b/cc/object.go
index d92e110..3a7af97 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -150,13 +150,12 @@
 		Local_include_dirs: localIncludeDirs,
 	}
 
-	props := bazel.NewBazelTargetModuleProperties(
-		m.Name(),
-		"cc_object",
-		"//build/bazel/rules:cc_object.bzl",
-	)
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "cc_object",
+		Bzl_load_location: "//build/bazel/rules:cc_object.bzl",
+	}
 
-	ctx.CreateBazelTargetModule(BazelObjectFactory, props, attrs)
+	ctx.CreateBazelTargetModule(BazelObjectFactory, m.Name(), props, attrs)
 }
 
 func (object *objectLinker) appendLdflags(flags []string) {
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index d55204b..36a5e2a 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -84,6 +84,15 @@
 	BootFlags         string        // extra flags to pass to dex2oat for the boot image
 	Dex2oatImageXmx   string        // max heap size for dex2oat for the boot image
 	Dex2oatImageXms   string        // initial heap size for dex2oat for the boot image
+
+	// If true, downgrade the compiler filter of dexpreopt to "extract" when verify_uses_libraries
+	// check fails, instead of failing the build. This will disable any AOT-compilation.
+	//
+	// The intended use case for this flag is to have a smoother migration path for the Java
+	// modules that need to add <uses-library> information in their build files. The flag allows to
+	// quickly silence build errors. This flag should be used with caution and only as a temporary
+	// measure, as it masks real errors and affects performance.
+	RelaxUsesLibraryCheck bool
 }
 
 // GlobalSoongConfig contains the global config that is generated from Soong,
@@ -113,9 +122,10 @@
 	ProfileIsTextListing bool
 	ProfileBootListing   android.OptionalPath
 
-	EnforceUsesLibraries bool
-	ProvidesUsesLibrary  string // the name of the <uses-library> (usually the same as its module)
-	ClassLoaderContexts  ClassLoaderContextMap
+	EnforceUsesLibraries           bool         // turn on build-time verify_uses_libraries check
+	EnforceUsesLibrariesStatusFile android.Path // a file with verify_uses_libraries errors (if any)
+	ProvidesUsesLibrary            string       // library name (usually the same as module name)
+	ClassLoaderContexts            ClassLoaderContextMap
 
 	Archs                   []android.ArchType
 	DexPreoptImages         []android.Path
@@ -258,14 +268,15 @@
 
 		// Copies of entries in ModuleConfig that are not constructable without extra parameters.  They will be
 		// used to construct the real value manually below.
-		BuildPath                   string
-		DexPath                     string
-		ManifestPath                string
-		ProfileClassListing         string
-		ClassLoaderContexts         jsonClassLoaderContextMap
-		DexPreoptImages             []string
-		DexPreoptImageLocations     []string
-		PreoptBootClassPathDexFiles []string
+		BuildPath                      string
+		DexPath                        string
+		ManifestPath                   string
+		ProfileClassListing            string
+		EnforceUsesLibrariesStatusFile string
+		ClassLoaderContexts            jsonClassLoaderContextMap
+		DexPreoptImages                []string
+		DexPreoptImageLocations        []string
+		PreoptBootClassPathDexFiles    []string
 	}
 
 	config := ModuleJSONConfig{}
@@ -280,6 +291,7 @@
 	config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath)
 	config.ModuleConfig.ManifestPath = constructPath(ctx, config.ManifestPath)
 	config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing))
+	config.ModuleConfig.EnforceUsesLibrariesStatusFile = constructPath(ctx, config.EnforceUsesLibrariesStatusFile)
 	config.ModuleConfig.ClassLoaderContexts = fromJsonClassLoaderContext(ctx, config.ClassLoaderContexts)
 	config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
 	config.ModuleConfig.DexPreoptImageLocations = config.DexPreoptImageLocations
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index b0a684e..6e0fe01 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -279,11 +279,12 @@
 
 		// Generate command that saves host and target class loader context in shell variables.
 		clc, paths := ComputeClassLoaderContext(module.ClassLoaderContexts)
-		cmd := rule.Command().
-			Text(`eval "$(`).Tool(globalSoong.ConstructContext).
+		rule.Command().
+			Text("if ! test -s ").Input(module.EnforceUsesLibrariesStatusFile).
+			Text(` ; then eval "$(`).Tool(globalSoong.ConstructContext).
 			Text(` --target-sdk-version ${target_sdk_version}`).
-			Text(clc).Implicits(paths)
-		cmd.Text(`)"`)
+			Text(clc).Implicits(paths).
+			Text(`)" ; fi`)
 
 	} else {
 		// Other libraries or APKs for which the exact <uses-library> list is unknown.
@@ -366,7 +367,16 @@
 		} else {
 			compilerFilter = "quicken"
 		}
-		cmd.FlagWithArg("--compiler-filter=", compilerFilter)
+		if module.EnforceUsesLibraries {
+			// If the verify_uses_libraries check failed (in this case status file contains a
+			// non-empty error message), then use "extract" compiler filter to avoid compiling any
+			// code (it would be rejected on device because of a class loader context mismatch).
+			cmd.Text("--compiler-filter=$(if test -s ").
+				Input(module.EnforceUsesLibrariesStatusFile).
+				Text(" ; then echo extract ; else echo " + compilerFilter + " ; fi)")
+		} else {
+			cmd.FlagWithArg("--compiler-filter=", compilerFilter)
+		}
 	}
 
 	if generateDM {
@@ -542,6 +552,12 @@
 	}
 }
 
+// Returns path to a file containing the reult of verify_uses_libraries check (empty if the check
+// has succeeded, or an error message if it failed).
+func UsesLibrariesStatusFile(ctx android.ModuleContext) android.WritablePath {
+	return android.PathForModuleOut(ctx, "enforce_uses_libraries.status")
+}
+
 func contains(l []string, s string) bool {
 	for _, e := range l {
 		if e == s {
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index af73d0c..12df36b 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -43,6 +43,7 @@
 		PreoptFlags:                     nil,
 		ProfileClassListing:             android.OptionalPath{},
 		ProfileIsTextListing:            false,
+		EnforceUsesLibrariesStatusFile:  android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)),
 		EnforceUsesLibraries:            false,
 		ClassLoaderContexts:             nil,
 		Archs:                           []android.ArchType{android.Arm},
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 9fa6c48..c743fc3 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -853,10 +853,12 @@
 		Tools: tools,
 	}
 
-	props := bazel.NewBazelTargetModuleProperties(m.Name(), "genrule", "")
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class: "genrule",
+	}
 
 	// Create the BazelTargetModule.
-	ctx.CreateBazelTargetModule(BazelGenruleFactory, props, attrs)
+	ctx.CreateBazelTargetModule(BazelGenruleFactory, m.Name(), props, attrs)
 }
 
 func (m *bazelGenrule) Name() string {
diff --git a/java/app.go b/java/app.go
index ce89e9b..5181207 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1260,13 +1260,19 @@
 // in the uses_libs and optional_uses_libs properties.  It returns the path to a copy of the manifest.
 func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
 	outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
+	statusFile := dexpreopt.UsesLibrariesStatusFile(ctx)
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 	cmd := rule.Command().BuiltTool("manifest_check").
 		Flag("--enforce-uses-libraries").
 		Input(manifest).
+		FlagWithOutput("--enforce-uses-libraries-status ", statusFile).
 		FlagWithOutput("-o ", outputFile)
 
+	if dexpreopt.GetGlobalConfig(ctx).RelaxUsesLibraryCheck {
+		cmd.Flag("--enforce-uses-libraries-relax")
+	}
+
 	for _, lib := range u.usesLibraryProperties.Uses_libs {
 		cmd.FlagWithArg("--uses-library ", lib)
 	}
@@ -1284,6 +1290,7 @@
 // in the uses_libs and optional_uses_libs properties.  It returns the path to a copy of the APK.
 func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
 	outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
+	statusFile := dexpreopt.UsesLibrariesStatusFile(ctx)
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 	aapt := ctx.Config().HostToolPath(ctx, "aapt")
@@ -1291,7 +1298,8 @@
 		Textf("aapt_binary=%s", aapt.String()).Implicit(aapt).
 		Textf(`uses_library_names="%s"`, strings.Join(u.usesLibraryProperties.Uses_libs, " ")).
 		Textf(`optional_uses_library_names="%s"`, strings.Join(u.usesLibraryProperties.Optional_uses_libs, " ")).
-		Tool(android.PathForSource(ctx, "build/make/core/verify_uses_libraries.sh")).Input(apk)
+		Textf(`relax_check="%b"`, dexpreopt.GetGlobalConfig(ctx).RelaxUsesLibraryCheck).
+		Tool(android.PathForSource(ctx, "build/make/core/verify_uses_libraries.sh")).Input(apk).Output(statusFile)
 	rule.Command().Text("cp -f").Input(apk).Output(outputFile)
 
 	rule.Build("verify_uses_libraries", "verify <uses-library>")
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 29c73c1..a2961c2 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -35,6 +35,7 @@
 	isPresignedPrebuilt bool
 
 	manifestFile        android.Path
+	statusFile          android.WritablePath
 	enforceUsesLibs     bool
 	classLoaderContexts dexpreopt.ClassLoaderContextMap
 
@@ -226,9 +227,10 @@
 		ProfileIsTextListing: profileIsTextListing,
 		ProfileBootListing:   profileBootListing,
 
-		EnforceUsesLibraries: d.enforceUsesLibs,
-		ProvidesUsesLibrary:  providesUsesLib,
-		ClassLoaderContexts:  d.classLoaderContexts,
+		EnforceUsesLibrariesStatusFile: dexpreopt.UsesLibrariesStatusFile(ctx),
+		EnforceUsesLibraries:           d.enforceUsesLibs,
+		ProvidesUsesLibrary:            providesUsesLib,
+		ClassLoaderContexts:            d.classLoaderContexts,
 
 		Archs:                   archs,
 		DexPreoptImages:         images,
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 9122da1..0eb1b76 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -48,6 +48,13 @@
                       dest='enforce_uses_libraries',
                       action='store_true',
                       help='check the uses-library entries known to the build system against the manifest')
+  parser.add_argument('--enforce-uses-libraries-relax',
+                      dest='enforce_uses_libraries_relax',
+                      action='store_true',
+                      help='do not fail immediately, just save the error message to file')
+  parser.add_argument('--enforce-uses-libraries-status',
+                      dest='enforce_uses_libraries_status',
+                      help='output file to store check status (error message)')
   parser.add_argument('--extract-target-sdk-version',
                       dest='extract_target_sdk_version',
                       action='store_true',
@@ -57,7 +64,7 @@
   return parser.parse_args()
 
 
-def enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries):
+def enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries, relax):
   """Verify that the <uses-library> tags in the manifest match those provided by the build system.
 
   Args:
@@ -80,10 +87,10 @@
       raise ManifestMismatchError('no <application> tag found')
     return
 
-  verify_uses_library(application, uses_libraries, optional_uses_libraries)
+  return verify_uses_library(application, uses_libraries, optional_uses_libraries, relax)
 
 
-def verify_uses_library(application, uses_libraries, optional_uses_libraries):
+def verify_uses_library(application, uses_libraries, optional_uses_libraries, relax):
   """Verify that the uses-library values known to the build system match the manifest.
 
   Args:
@@ -112,8 +119,12 @@
                (', '.join(optional_uses_libraries), ', '.join(manifest_optional_uses_libraries)))
 
   if err:
-    raise ManifestMismatchError('\n'.join(err))
+    errmsg = '\n'.join(err)
+    if not relax:
+      raise ManifestMismatchError(errmsg)
+    return errmsg
 
+  return None
 
 def parse_uses_library(application):
   """Extract uses-library tags from the manifest.
@@ -195,9 +206,19 @@
     doc = minidom.parse(args.input)
 
     if args.enforce_uses_libraries:
-      enforce_uses_libraries(doc,
-                             args.uses_libraries,
-                             args.optional_uses_libraries)
+      # Check if the <uses-library> lists in the build system agree with those
+      # in the manifest. Raise an exception on mismatch, unless the script was
+      # passed a special parameter to suppress exceptions.
+      errmsg = enforce_uses_libraries(doc, args.uses_libraries,
+        args.optional_uses_libraries, args.enforce_uses_libraries_relax)
+
+      # Create a status file that is empty on success, or contains an error
+      # message on failure. When exceptions are suppressed, dexpreopt command
+      # command will check file size to determine if the check has failed.
+      if args.enforce_uses_libraries_status:
+        with open(args.enforce_uses_libraries_status, 'w') as f:
+          if not errmsg == None:
+            f.write("%s\n" % errmsg)
 
     if args.extract_target_sdk_version:
       print(extract_target_sdk_version(doc))
diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py
index 7baad5d..56c2d9e 100755
--- a/scripts/manifest_check_test.py
+++ b/scripts/manifest_check_test.py
@@ -39,7 +39,9 @@
   def run_test(self, input_manifest, uses_libraries=None, optional_uses_libraries=None):
     doc = minidom.parseString(input_manifest)
     try:
-      manifest_check.enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries)
+      relax = False
+      manifest_check.enforce_uses_libraries(doc, uses_libraries,
+        optional_uses_libraries, relax)
       return True
     except manifest_check.ManifestMismatchError:
       return False
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 58f8cf6..3a5c7de 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -514,9 +514,11 @@
 		Srcs: srcs,
 	}
 
-	props := bazel.NewBazelTargetModuleProperties(m.Name(), "sh_binary", "")
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class: "sh_binary",
+	}
 
-	ctx.CreateBazelTargetModule(BazelShBinaryFactory, props, attrs)
+	ctx.CreateBazelTargetModule(BazelShBinaryFactory, m.Name(), props, attrs)
 }
 
 func (m *bazelShBinary) Name() string {