Merge "sbox error message now lists the files that were created"
diff --git a/android/testing.go b/android/testing.go
index 03572b3..fc58cec 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -131,7 +131,7 @@
 			outputs = append(outputs, p.Output)
 		}
 		for _, f := range outputs {
-			if f.Rel() == file {
+			if f.String() == file || f.Rel() == file {
 				return p
 			}
 		}
diff --git a/java/aapt2.go b/java/aapt2.go
index cebd6d1..84e3729 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"sort"
 	"strconv"
 	"strings"
 
@@ -85,6 +86,9 @@
 		})
 	}
 
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].String() < ret[j].String()
+	})
 	return ret
 }
 
diff --git a/java/androidmk.go b/java/androidmk.go
index 86e000d..2e67639 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -143,6 +143,13 @@
 						// framework_res.
 						fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true")
 					}
+
+					if len(app.rroDirs) > 0 {
+						fmt.Fprintln(w, "LOCAL_SOONG_RRO_DIRS :=", strings.Join(app.rroDirs.Strings(), " "))
+					}
+					fmt.Fprintln(w, "LOCAL_EXPORT_PACKAGE_RESOURCES :=",
+						Bool(app.appProperties.Export_package_resources))
+					fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", app.manifestPath.String())
 				}
 			},
 		},
diff --git a/java/app.go b/java/app.go
index b66eb4b..6866e2a 100644
--- a/java/app.go
+++ b/java/app.go
@@ -70,6 +70,8 @@
 
 	aaptSrcJar    android.Path
 	exportPackage android.Path
+	rroDirs       android.Paths
+	manifestPath  android.Path
 }
 
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -86,7 +88,7 @@
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	linkFlags, linkDeps, resDirs, overlayDirs := a.aapt2Flags(ctx)
+	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath := a.aapt2Flags(ctx)
 
 	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
 	srcJar := android.PathForModuleGen(ctx, "R.jar")
@@ -144,6 +146,8 @@
 	CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
 
 	a.outputFile = packageFile
+	a.rroDirs = rroDirs
+	a.manifestPath = manifestPath
 
 	if ctx.ModuleName() == "framework-res" {
 		// framework-res.apk is installed as system/framework/framework-res.apk
@@ -171,7 +175,7 @@
 }
 
 func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
-	resDirs, overlayDirs []globbedResourceDir) {
+	resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths, manifestPath android.Path) {
 
 	hasVersionCode := false
 	hasVersionName := false
@@ -205,7 +209,9 @@
 			dir:   dir,
 			files: resourceGlob(ctx, dir),
 		})
-		overlayDirs = append(overlayDirs, overlayResourceGlob(ctx, dir)...)
+		resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
+		overlayDirs = append(overlayDirs, resOverlayDirs...)
+		rroDirs = append(rroDirs, resRRODirs...)
 	}
 
 	var assetFiles android.Paths
@@ -221,7 +227,7 @@
 		manifestFile = *a.properties.Manifest
 	}
 
-	manifestPath := android.PathForModuleSrc(ctx, manifestFile)
+	manifestPath = android.PathForModuleSrc(ctx, manifestFile)
 	linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
 	linkDeps = append(linkDeps, manifestPath)
 
@@ -288,7 +294,7 @@
 	// TODO: LOCAL_PACKAGE_OVERRIDES
 	//    $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
 
-	return linkFlags, linkDeps, resDirs, overlayDirs
+	return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath
 }
 
 func AndroidAppFactory() android.Module {
@@ -320,26 +326,49 @@
 type overlayGlobResult struct {
 	dir   string
 	paths android.DirectorySortedPaths
+
+	// Set to true of the product has selected that values in this overlay should not be moved to
+	// Runtime Resource Overlay (RRO) packages.
+	excludeFromRRO bool
 }
 
 const overlayDataKey = "overlayDataKey"
 
-func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) []globbedResourceDir {
+func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
+	rroDirs android.Paths) {
+
 	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
 
-	var ret []globbedResourceDir
+	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
+	rroEnabled := false
+	enforceRROTargets := ctx.Config().ProductVariables.EnforceRROTargets
+	if enforceRROTargets != nil {
+		if len(*enforceRROTargets) == 1 && (*enforceRROTargets)[0] == "*" {
+			rroEnabled = true
+		} else if inList(ctx.ModuleName(), *enforceRROTargets) {
+			rroEnabled = true
+		}
+	}
 
 	for _, data := range overlayData {
 		files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
 		if len(files) > 0 {
-			ret = append(ret, globbedResourceDir{
-				dir:   android.PathForSource(ctx, data.dir, dir.String()),
-				files: files,
-			})
+			overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
+			// If enforce RRO is enabled for this module and this overlay is not in the
+			// exclusion list, ignore the overlay.  The list of ignored overlays will be
+			// passed to Make to be turned into an RRO package.
+			if rroEnabled && !data.excludeFromRRO {
+				rroDirs = append(rroDirs, overlayModuleDir)
+			} else {
+				res = append(res, globbedResourceDir{
+					dir:   overlayModuleDir,
+					files: files,
+				})
+			}
 		}
 	}
 
-	return ret
+	return res, rroDirs
 }
 
 func OverlaySingletonFactory() android.Singleton {
@@ -349,10 +378,25 @@
 type overlaySingleton struct{}
 
 func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+
+	// Specific overlays may be excluded from Runtime Resource Overlays by the product config
+	var rroExcludedOverlays []string
+	if ctx.Config().ProductVariables.EnforceRROExcludedOverlays != nil {
+		rroExcludedOverlays = *ctx.Config().ProductVariables.EnforceRROExcludedOverlays
+	}
+
 	var overlayData []overlayGlobResult
 	for _, overlay := range ctx.Config().ResourceOverlays() {
 		var result overlayGlobResult
 		result.dir = overlay
+
+		// Mark overlays that will not have Runtime Resource Overlays enforced on them
+		for _, exclude := range rroExcludedOverlays {
+			if strings.HasPrefix(overlay, exclude) {
+				result.excludeFromRRO = true
+			}
+		}
+
 		files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
 		if err != nil {
 			ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
diff --git a/java/app_test.go b/java/app_test.go
index 37489f5..73ac3f7 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"reflect"
+	"sort"
 	"testing"
 )
 
@@ -79,7 +80,11 @@
 		t.Errorf("expected aapt2 compile inputs expected:\n  %#v\n got:\n  %#v",
 			resourceFiles, compile.Inputs.Strings())
 	}
-	expectedLinkImplicits = append(expectedLinkImplicits, compile.Outputs.Strings()...)
+
+	compiledResourceOutputs := compile.Outputs.Strings()
+	sort.Strings(compiledResourceOutputs)
+
+	expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
 
 	list := foo.Output("aapt2/res.list")
 	expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
@@ -91,3 +96,144 @@
 			expectedLinkImplicits, res.Implicits.Strings())
 	}
 }
+
+var testEnforceRROTests = []struct {
+	name                       string
+	enforceRROTargets          []string
+	enforceRROExcludedOverlays []string
+	fooOverlayFiles            []string
+	fooRRODirs                 []string
+	barOverlayFiles            []string
+	barRRODirs                 []string
+}{
+	{
+		name:                       "no RRO",
+		enforceRROTargets:          nil,
+		enforceRROExcludedOverlays: nil,
+		fooOverlayFiles: []string{
+			"device/vendor/blah/overlay/foo/res/values/strings.xml",
+			"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+		},
+		fooRRODirs: nil,
+		barOverlayFiles: []string{
+			"device/vendor/blah/overlay/bar/res/values/strings.xml",
+			"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+		},
+		barRRODirs: nil,
+	},
+	{
+		name:                       "enforce RRO on foo",
+		enforceRROTargets:          []string{"foo"},
+		enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
+		fooOverlayFiles: []string{
+			"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+		},
+		fooRRODirs: []string{
+			"device/vendor/blah/overlay/foo/res",
+		},
+		barOverlayFiles: []string{
+			"device/vendor/blah/overlay/bar/res/values/strings.xml",
+			"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+		},
+		barRRODirs: nil,
+	},
+	{
+		name:                       "enforce RRO on all",
+		enforceRROTargets:          []string{"*"},
+		enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
+		fooOverlayFiles: []string{
+			"device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+		},
+		fooRRODirs: []string{
+			"device/vendor/blah/overlay/foo/res",
+		},
+		barOverlayFiles: []string{
+			"device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+		},
+		barRRODirs: []string{
+			"device/vendor/blah/overlay/bar/res",
+		},
+	},
+}
+
+func TestEnforceRRO(t *testing.T) {
+	resourceOverlays := []string{
+		"device/vendor/blah/overlay",
+		"device/vendor/blah/overlay2",
+		"device/vendor/blah/static_overlay",
+	}
+
+	fs := map[string][]byte{
+		"foo/res/res/values/strings.xml":                               nil,
+		"bar/res/res/values/strings.xml":                               nil,
+		"device/vendor/blah/overlay/foo/res/values/strings.xml":        nil,
+		"device/vendor/blah/overlay/bar/res/values/strings.xml":        nil,
+		"device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil,
+		"device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil,
+		"device/vendor/blah/overlay2/res/values/strings.xml":           nil,
+	}
+
+	bp := `
+			android_app {
+				name: "foo",
+				resource_dirs: ["foo/res"],
+			}
+
+			android_app {
+				name: "bar",
+				resource_dirs: ["bar/res"],
+			}
+		`
+
+	for _, testCase := range testEnforceRROTests {
+		t.Run(testCase.name, func(t *testing.T) {
+			config := testConfig(nil)
+			config.ProductVariables.ResourceOverlays = &resourceOverlays
+			if testCase.enforceRROTargets != nil {
+				config.ProductVariables.EnforceRROTargets = &testCase.enforceRROTargets
+			}
+			if testCase.enforceRROExcludedOverlays != nil {
+				config.ProductVariables.EnforceRROExcludedOverlays = &testCase.enforceRROExcludedOverlays
+			}
+
+			ctx := testAppContext(config, bp, fs)
+			run(t, ctx, config)
+
+			getOverlays := func(moduleName string) ([]string, []string) {
+				module := ctx.ModuleForTests(moduleName, "android_common")
+				overlayCompiledPaths := module.Output("aapt2/overlay.list").Inputs.Strings()
+
+				var overlayFiles []string
+				for _, o := range overlayCompiledPaths {
+					overlayFiles = append(overlayFiles, module.Output(o).Inputs.Strings()...)
+				}
+
+				rroDirs := module.Module().(*AndroidApp).rroDirs.Strings()
+
+				return overlayFiles, rroDirs
+			}
+
+			fooOverlayFiles, fooRRODirs := getOverlays("foo")
+			barOverlayFiles, barRRODirs := getOverlays("bar")
+
+			if !reflect.DeepEqual(fooOverlayFiles, testCase.fooOverlayFiles) {
+				t.Errorf("expected foo overlay files:\n  %#v\n got:\n  %#v",
+					testCase.fooOverlayFiles, fooOverlayFiles)
+			}
+			if !reflect.DeepEqual(fooRRODirs, testCase.fooRRODirs) {
+				t.Errorf("expected foo rroDirs:  %#v\n got:\n  %#v",
+					testCase.fooRRODirs, fooRRODirs)
+			}
+
+			if !reflect.DeepEqual(barOverlayFiles, testCase.barOverlayFiles) {
+				t.Errorf("expected bar overlay files:\n  %#v\n got:\n  %#v",
+					testCase.barOverlayFiles, barOverlayFiles)
+			}
+			if !reflect.DeepEqual(barRRODirs, testCase.barRRODirs) {
+				t.Errorf("expected bar rroDirs:  %#v\n got:\n  %#v",
+					testCase.barRRODirs, barRRODirs)
+			}
+
+		})
+	}
+}
diff --git a/python/androidmk.go b/python/androidmk.go
index 4c94450..5fa01ab 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -39,7 +39,7 @@
 }
 
 func (p *Module) AndroidMk() android.AndroidMkData {
-	ret := android.AndroidMkData{}
+	ret := android.AndroidMkData{OutputFile: p.installSource}
 
 	p.subAndroidMk(&ret, p.installer)
 
@@ -55,7 +55,7 @@
 				strings.Join(p.binaryProperties.Test_suites, " "))
 		}
 	})
-	base.subAndroidMk(ret, p.baseInstaller)
+	base.subAndroidMk(ret, p.pythonInstaller)
 }
 
 func (p *testDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) {
@@ -67,7 +67,7 @@
 				strings.Join(p.binaryDecorator.binaryProperties.Test_suites, " "))
 		}
 	})
-	base.subAndroidMk(ret, p.binaryDecorator.baseInstaller)
+	base.subAndroidMk(ret, p.binaryDecorator.pythonInstaller)
 }
 
 func (installer *pythonInstaller) AndroidMk(base *Module, ret *android.AndroidMkData) {
diff --git a/python/binary.go b/python/binary.go
index 14c4952..457c7fa 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -49,24 +49,20 @@
 type binaryDecorator struct {
 	binaryProperties BinaryProperties
 
-	baseInstaller *pythonInstaller
+	*pythonInstaller
 }
 
 type IntermPathProvider interface {
 	IntermPathForModuleOut() android.OptionalPath
 }
 
-func (binary *binaryDecorator) install(ctx android.ModuleContext, file android.Path) {
-	binary.baseInstaller.install(ctx, file)
-}
-
 var (
 	stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
 )
 
 func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
 	module := newModule(hod, android.MultilibFirst)
-	decorator := &binaryDecorator{baseInstaller: NewPythonInstaller("bin")}
+	decorator := &binaryDecorator{pythonInstaller: NewPythonInstaller("bin", "")}
 
 	module.bootstrapper = decorator
 	module.installer = decorator
diff --git a/python/installer.go b/python/installer.go
index 04698c5..ab3d9b4 100644
--- a/python/installer.go
+++ b/python/installer.go
@@ -15,26 +15,47 @@
 package python
 
 import (
+	"path/filepath"
+
 	"android/soong/android"
 )
 
 // This file handles installing python executables into their final location
 
+type installLocation int
+
+const (
+	InstallInData installLocation = iota
+)
+
 type pythonInstaller struct {
-	dir string
+	dir      string
+	dir64    string
+	relative string
 
 	path android.OutputPath
 }
 
-func NewPythonInstaller(dir string) *pythonInstaller {
+func NewPythonInstaller(dir, dir64 string) *pythonInstaller {
 	return &pythonInstaller{
-		dir: dir,
+		dir:   dir,
+		dir64: dir64,
 	}
 }
 
 var _ installer = (*pythonInstaller)(nil)
 
+func (installer *pythonInstaller) installDir(ctx android.ModuleContext) android.OutputPath {
+	dir := installer.dir
+	if ctx.Arch().ArchType.Multilib == "lib64" && installer.dir64 != "" {
+		dir = installer.dir64
+	}
+	if !ctx.Host() && !ctx.Arch().Native {
+		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
+	}
+	return android.PathForModuleInstall(ctx, dir, installer.relative)
+}
+
 func (installer *pythonInstaller) install(ctx android.ModuleContext, file android.Path) {
-	installer.path = ctx.InstallFile(android.PathForModuleInstall(ctx, installer.dir),
-		file.Base(), file)
+	installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
 }
diff --git a/python/library.go b/python/library.go
index 58ee55f..65c1352 100644
--- a/python/library.go
+++ b/python/library.go
@@ -22,6 +22,7 @@
 
 func init() {
 	android.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
+	android.RegisterModuleType("python_library", PythonLibraryFactory)
 }
 
 func PythonLibraryHostFactory() android.Module {
@@ -29,3 +30,9 @@
 
 	return module.Init()
 }
+
+func PythonLibraryFactory() android.Module {
+	module := newModule(android.HostAndDeviceSupported, android.MultilibBoth)
+
+	return module.Init()
+}
diff --git a/python/python.go b/python/python.go
index 9d6d6a7..05efbea 100644
--- a/python/python.go
+++ b/python/python.go
@@ -558,5 +558,9 @@
 	return true
 }
 
+func (p *Module) InstallInData() bool {
+	return true
+}
+
 var Bool = proptools.Bool
 var String = proptools.String
diff --git a/python/test.go b/python/test.go
index de2b13e..825e63c 100644
--- a/python/test.go
+++ b/python/test.go
@@ -22,6 +22,7 @@
 
 func init() {
 	android.RegisterModuleType("python_test_host", PythonTestHostFactory)
+	android.RegisterModuleType("python_test", PythonTestFactory)
 }
 
 type testDecorator struct {
@@ -29,13 +30,18 @@
 }
 
 func (test *testDecorator) install(ctx android.ModuleContext, file android.Path) {
-	test.binaryDecorator.baseInstaller.install(ctx, file)
+	test.binaryDecorator.pythonInstaller.dir = "nativetest"
+	test.binaryDecorator.pythonInstaller.dir64 = "nativetest64"
+
+	test.binaryDecorator.pythonInstaller.relative = ctx.ModuleName()
+
+	test.binaryDecorator.pythonInstaller.install(ctx, file)
 }
 
 func NewTest(hod android.HostOrDeviceSupported) *Module {
 	module, binary := NewBinary(hod)
 
-	binary.baseInstaller = NewPythonInstaller("nativetest")
+	binary.pythonInstaller = NewPythonInstaller("nativetest", "nativetest64")
 
 	test := &testDecorator{binaryDecorator: binary}
 
@@ -50,3 +56,10 @@
 
 	return module.Init()
 }
+
+func PythonTestFactory() android.Module {
+	module := NewTest(android.HostAndDeviceSupported)
+	module.multilib = android.MultilibBoth
+
+	return module.Init()
+}