Merge "Add default -Wimplicit-fallthrough."
diff --git a/android/arch.go b/android/arch.go
index 95f8803..6516558 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -288,6 +288,30 @@
 	return target.Os.String() + "_" + target.Arch.String()
 }
 
+// archMutator splits a module into a variant for each Target requested by the module.  Target selection
+// for a module is in three levels, OsClass, mulitlib, and then Target.
+// OsClass selection is determined by:
+//    - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
+//      whether the module type can compile for host, device or both.
+//    - The host_supported and device_supported properties on the module.
+// If host is supported for the module, the Host and HostCross OsClasses are  are selected.  If device is supported
+// for the module, the Device OsClass is selected.
+// Within each selected OsClass, the multilib selection is determined by:
+//    - The compile_multilib property if it set (which may be overriden by target.android.compile_multlib or
+//      target.host.compile_multilib).
+//    - The default multilib passed to InitAndroidArchModule if compile_multilib was not set.
+// Valid multilib values include:
+//    "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
+//    "first": compile for only a single preferred Target supported by the OsClass.  This is generally x86_64 or arm64,
+//        but may be arm for a 32-bit only build or a build with TARGET_PREFER_32_BIT=true set.
+//    "32": compile for only a single 32-bit Target supported by the OsClass.
+//    "64": compile for only a single 64-bit Target supported by the OsClass.
+//    "common": compile a for a single Target that will work on all Targets suported by the OsClass (for example Java).
+//
+// Once the list of Targets is determined, the module is split into a variant for each Target.
+//
+// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
+// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
 func archMutator(mctx BottomUpMutatorContext) {
 	var module Module
 	var ok bool
@@ -304,6 +328,7 @@
 	osClasses := base.OsClassSupported()
 
 	var moduleTargets []Target
+	moduleMultiTargets := make(map[int][]Target)
 	primaryModules := make(map[int]bool)
 
 	for _, class := range osClasses {
@@ -311,36 +336,34 @@
 		if len(classTargets) == 0 {
 			continue
 		}
+
 		// only the primary arch in the recovery partition
 		if module.InstallInRecovery() {
 			classTargets = []Target{mctx.Config().Targets[Device][0]}
 		}
 
-		var multilib string
-		switch class {
-		case Device:
-			multilib = String(base.commonProperties.Target.Android.Compile_multilib)
-		case Host, HostCross:
-			multilib = String(base.commonProperties.Target.Host.Compile_multilib)
-		}
-		if multilib == "" {
-			multilib = String(base.commonProperties.Compile_multilib)
-		}
-		if multilib == "" {
-			multilib = base.commonProperties.Default_multilib
-		}
-
 		prefer32 := false
 		if base.prefer32 != nil {
 			prefer32 = base.prefer32(mctx, base, class)
 		}
 
-		targets, err := decodeMultilib(multilib, classTargets, prefer32)
+		multilib, extraMultilib := decodeMultilib(base, class)
+		targets, err := decodeMultilibTargets(multilib, classTargets, prefer32)
 		if err != nil {
 			mctx.ModuleErrorf("%s", err.Error())
 		}
+
+		var multiTargets []Target
+		if extraMultilib != "" {
+			multiTargets, err = decodeMultilibTargets(extraMultilib, classTargets, prefer32)
+			if err != nil {
+				mctx.ModuleErrorf("%s", err.Error())
+			}
+		}
+
 		if len(targets) > 0 {
 			primaryModules[len(moduleTargets)] = true
+			moduleMultiTargets[len(moduleTargets)] = multiTargets
 			moduleTargets = append(moduleTargets, targets...)
 		}
 	}
@@ -358,11 +381,37 @@
 
 	modules := mctx.CreateVariations(targetNames...)
 	for i, m := range modules {
-		m.(Module).base().SetTarget(moduleTargets[i], primaryModules[i])
+		m.(Module).base().SetTarget(moduleTargets[i], moduleMultiTargets[i], primaryModules[i])
 		m.(Module).base().setArchProperties(mctx)
 	}
 }
 
+func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
+	switch class {
+	case Device:
+		multilib = String(base.commonProperties.Target.Android.Compile_multilib)
+	case Host, HostCross:
+		multilib = String(base.commonProperties.Target.Host.Compile_multilib)
+	}
+	if multilib == "" {
+		multilib = String(base.commonProperties.Compile_multilib)
+	}
+	if multilib == "" {
+		multilib = base.commonProperties.Default_multilib
+	}
+
+	if base.commonProperties.UseTargetVariants {
+		return multilib, ""
+	} else {
+		// For app modules a single arch variant will be created per OS class which is expected to handle all the
+		// selected arches.  Return the common-type as multilib and any Android.bp provided multilib as extraMultilib
+		if multilib == base.commonProperties.Default_multilib {
+			multilib = "first"
+		}
+		return base.commonProperties.Default_multilib, multilib
+	}
+}
+
 func filterArchStruct(prop reflect.Type) (reflect.Type, bool) {
 	var fields []reflect.StructField
 
@@ -1114,7 +1163,7 @@
 }
 
 // Use the module multilib setting to select one or more targets from a target list
-func decodeMultilib(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
+func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
 	buildTargets := []Target{}
 
 	switch multilib {
diff --git a/android/module.go b/android/module.go
index 01766b4..9d9d9a9 100644
--- a/android/module.go
+++ b/android/module.go
@@ -58,6 +58,7 @@
 type androidBaseContext interface {
 	Target() Target
 	TargetPrimary() bool
+	MultiTargets() []Target
 	Arch() Arch
 	Os() OsType
 	Host() bool
@@ -215,7 +216,8 @@
 		}
 	}
 
-	Default_multilib string `blueprint:"mutated"`
+	UseTargetVariants bool   `blueprint:"mutated"`
+	Default_multilib  string `blueprint:"mutated"`
 
 	// whether this is a proprietary vendor module, and should be installed into /vendor
 	Proprietary *bool
@@ -264,8 +266,9 @@
 	Notice *string
 
 	// Set by TargetMutator
-	CompileTarget  Target `blueprint:"mutated"`
-	CompilePrimary bool   `blueprint:"mutated"`
+	CompileTarget       Target   `blueprint:"mutated"`
+	CompileMultiTargets []Target `blueprint:"mutated"`
+	CompilePrimary      bool     `blueprint:"mutated"`
 
 	// Set by InitAndroidModule
 	HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
@@ -362,6 +365,7 @@
 	base.commonProperties.HostOrDeviceSupported = hod
 	base.commonProperties.Default_multilib = string(defaultMultilib)
 	base.commonProperties.ArchSpecific = true
+	base.commonProperties.UseTargetVariants = true
 
 	switch hod {
 	case HostAndDeviceSupported, HostAndDeviceDefault:
@@ -371,6 +375,11 @@
 	InitArchModule(m)
 }
 
+func InitAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
+	InitAndroidArchModule(m, hod, defaultMultilib)
+	m.base().commonProperties.UseTargetVariants = false
+}
+
 // A ModuleBase object contains the properties that are common to all Android
 // modules.  It should be included as an anonymous field in every module
 // struct definition.  InitAndroidModule should then be called from the module's
@@ -477,8 +486,9 @@
 	return a
 }
 
-func (a *ModuleBase) SetTarget(target Target, primary bool) {
+func (a *ModuleBase) SetTarget(target Target, multiTargets []Target, primary bool) {
 	a.commonProperties.CompileTarget = target
+	a.commonProperties.CompileMultiTargets = multiTargets
 	a.commonProperties.CompilePrimary = primary
 }
 
@@ -490,6 +500,10 @@
 	return a.commonProperties.CompilePrimary
 }
 
+func (a *ModuleBase) MultiTargets() []Target {
+	return a.commonProperties.CompileMultiTargets
+}
+
 func (a *ModuleBase) Os() OsType {
 	return a.Target().Os
 }
@@ -731,6 +745,7 @@
 	return androidBaseContextImpl{
 		target:        a.commonProperties.CompileTarget,
 		targetPrimary: a.commonProperties.CompilePrimary,
+		multiTargets:  a.commonProperties.CompileMultiTargets,
 		kind:          determineModuleKind(a, ctx),
 		config:        ctx.Config().(Config),
 	}
@@ -785,6 +800,7 @@
 
 type androidBaseContextImpl struct {
 	target        Target
+	multiTargets  []Target
 	targetPrimary bool
 	debug         bool
 	kind          moduleKind
@@ -1022,6 +1038,10 @@
 	return a.targetPrimary
 }
 
+func (a *androidBaseContextImpl) MultiTargets() []Target {
+	return a.multiTargets
+}
+
 func (a *androidBaseContextImpl) Arch() Arch {
 	return a.target.Arch
 }
diff --git a/cc/cc.go b/cc/cc.go
index d04485d..640c552 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -35,11 +35,11 @@
 
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("image", imageMutator).Parallel()
-		ctx.BottomUp("link", linkageMutator).Parallel()
+		ctx.BottomUp("link", LinkageMutator).Parallel()
 		ctx.BottomUp("vndk", vndkMutator).Parallel()
 		ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
 		ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
-		ctx.BottomUp("begin", beginMutator).Parallel()
+		ctx.BottomUp("begin", BeginMutator).Parallel()
 	})
 
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -1093,7 +1093,7 @@
 	}
 }
 
-func beginMutator(ctx android.BottomUpMutatorContext) {
+func BeginMutator(ctx android.BottomUpMutatorContext) {
 	if c, ok := ctx.Module().(*Module); ok && c.Enabled() {
 		c.beginMutator(ctx)
 	}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 01beb66..bca26ea 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -56,17 +56,17 @@
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
 	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
-	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory))
+	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory))
 	ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
 	ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
-	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(objectFactory))
+	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(ObjectFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("image", imageMutator).Parallel()
-		ctx.BottomUp("link", linkageMutator).Parallel()
+		ctx.BottomUp("link", LinkageMutator).Parallel()
 		ctx.BottomUp("vndk", vndkMutator).Parallel()
-		ctx.BottomUp("begin", beginMutator).Parallel()
+		ctx.BottomUp("begin", BeginMutator).Parallel()
 	})
 	ctx.Register()
 
diff --git a/cc/library.go b/cc/library.go
index 0e45af9..4f9b5b2 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -821,7 +821,7 @@
 	}
 }
 
-func linkageMutator(mctx android.BottomUpMutatorContext) {
+func LinkageMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
 		if library, ok := m.linker.(libraryInterface); ok {
 			var modules []blueprint.Module
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 2709a89..63d9f29 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -61,7 +61,7 @@
 	// These libraries have migrated over to the new ndk_library, which is added
 	// as a variation dependency via depsMutator.
 	ndkMigratedLibs     = []string{}
-	ndkMigratedLibsLock sync.Mutex // protects ndkMigratedLibs writes during parallel beginMutator
+	ndkMigratedLibsLock sync.Mutex // protects ndkMigratedLibs writes during parallel BeginMutator
 )
 
 // Creates a stub shared library based on the provided version file.
diff --git a/cc/object.go b/cc/object.go
index 7c134ac..2577195 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -25,7 +25,7 @@
 //
 
 func init() {
-	android.RegisterModuleType("cc_object", objectFactory)
+	android.RegisterModuleType("cc_object", ObjectFactory)
 }
 
 type objectLinker struct {
@@ -33,7 +33,7 @@
 	Properties ObjectLinkerProperties
 }
 
-func objectFactory() android.Module {
+func ObjectFactory() android.Module {
 	module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth)
 	module.linker = &objectLinker{
 		baseLinker: NewBaseLinker(nil),
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 20b0f85..742d1c1 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -23,7 +23,7 @@
 //
 
 func init() {
-	android.RegisterModuleType("toolchain_library", toolchainLibraryFactory)
+	android.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
 }
 
 type toolchainLibraryProperties struct {
@@ -48,7 +48,7 @@
 	return append(props, &library.Properties)
 }
 
-func toolchainLibraryFactory() android.Module {
+func ToolchainLibraryFactory() android.Module {
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyStatic()
 	toolchainLibrary := &toolchainLibraryDecorator{
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index e8ea9b9..d3b349c 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -17,6 +17,7 @@
 import (
 	"flag"
 	"fmt"
+	"io"
 	"log"
 	"os"
 	"path/filepath"
@@ -39,11 +40,13 @@
 
 	staticTime = time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
 
-	excludes excludeArgs
+	excludes   multiFlag
+	uncompress multiFlag
 )
 
 func init() {
 	flag.Var(&excludes, "x", "exclude a filespec from the output")
+	flag.Var(&uncompress, "0", "convert a filespec to uncompressed in the output")
 }
 
 func main() {
@@ -93,7 +96,7 @@
 	}()
 
 	if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime,
-		flag.Args(), excludes); err != nil {
+		flag.Args(), excludes, uncompress); err != nil {
 
 		log.Fatal(err)
 	}
@@ -101,11 +104,12 @@
 
 type pair struct {
 	*zip.File
-	newName string
+	newName    string
+	uncompress bool
 }
 
 func zip2zip(reader *zip.Reader, writer *zip.Writer, sortOutput, sortJava, setTime bool,
-	includes []string, excludes []string) error {
+	includes, excludes, uncompresses []string) error {
 
 	matches := []pair{}
 
@@ -149,7 +153,7 @@
 						newName = output
 					}
 				}
-				includeMatches = append(includeMatches, pair{file, newName})
+				includeMatches = append(includeMatches, pair{file, newName, false})
 			}
 		}
 
@@ -160,7 +164,7 @@
 	if len(includes) == 0 {
 		// implicitly match everything
 		for _, file := range reader.File {
-			matches = append(matches, pair{file, file.Name})
+			matches = append(matches, pair{file, file.Name, false})
 		}
 		sortMatches(matches)
 	}
@@ -193,6 +197,15 @@
 		}
 		seen[match.newName] = match.File
 
+		for _, u := range uncompresses {
+			if uncompressMatch, err := pathtools.Match(u, match.newName); err != nil {
+				return err
+			} else if uncompressMatch {
+				match.uncompress = true
+				break
+			}
+		}
+
 		matchesAfterExcludes = append(matchesAfterExcludes, match)
 	}
 
@@ -200,8 +213,32 @@
 		if setTime {
 			match.File.SetModTime(staticTime)
 		}
-		if err := writer.CopyFrom(match.File, match.newName); err != nil {
-			return err
+		if match.uncompress && match.File.FileHeader.Method != zip.Store {
+			fh := match.File.FileHeader
+			fh.Name = match.newName
+			fh.Method = zip.Store
+			fh.CompressedSize64 = fh.UncompressedSize64
+
+			zw, err := writer.CreateHeaderAndroid(&fh)
+			if err != nil {
+				return err
+			}
+
+			zr, err := match.File.Open()
+			if err != nil {
+				return err
+			}
+
+			_, err = io.Copy(zw, zr)
+			zr.Close()
+			if err != nil {
+				return err
+			}
+		} else {
+			err := writer.CopyFrom(match.File, match.newName)
+			if err != nil {
+				return err
+			}
 		}
 	}
 
@@ -217,13 +254,13 @@
 	}
 }
 
-type excludeArgs []string
+type multiFlag []string
 
-func (e *excludeArgs) String() string {
+func (e *multiFlag) String() string {
 	return strings.Join(*e, " ")
 }
 
-func (e *excludeArgs) Set(s string) error {
+func (e *multiFlag) Set(s string) error {
 	*e = append(*e, s)
 	return nil
 }
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index 212ab28..e032fe6 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -26,13 +26,15 @@
 var testCases = []struct {
 	name string
 
-	inputFiles []string
-	sortGlobs  bool
-	sortJava   bool
-	args       []string
-	excludes   []string
+	inputFiles   []string
+	sortGlobs    bool
+	sortJava     bool
+	args         []string
+	excludes     []string
+	uncompresses []string
 
 	outputFiles []string
+	storedFiles []string
 	err         error
 }{
 	{
@@ -251,6 +253,79 @@
 
 		outputFiles: nil,
 	},
+	{
+		name: "uncompress one",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		uncompresses: []string{"a/a"},
+
+		outputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		storedFiles: []string{
+			"a/a",
+		},
+	},
+	{
+		name: "uncompress two",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		uncompresses: []string{"a/a", "a/b"},
+
+		outputFiles: []string{
+			"a/a",
+			"a/b",
+		},
+		storedFiles: []string{
+			"a/a",
+			"a/b",
+		},
+	},
+	{
+		name: "uncompress glob",
+
+		inputFiles: []string{
+			"a/a",
+			"a/b",
+			"a/c.so",
+			"a/d.so",
+		},
+		uncompresses: []string{"a/*.so"},
+
+		outputFiles: []string{
+			"a/a",
+			"a/b",
+			"a/c.so",
+			"a/d.so",
+		},
+		storedFiles: []string{
+			"a/c.so",
+			"a/d.so",
+		},
+	},
+	{
+		name: "uncompress rename",
+
+		inputFiles: []string{
+			"a/a",
+		},
+		args:         []string{"a/a:a/b"},
+		uncompresses: []string{"a/b"},
+
+		outputFiles: []string{
+			"a/b",
+		},
+		storedFiles: []string{
+			"a/b",
+		},
+	},
 }
 
 func errorString(e error) string {
@@ -282,7 +357,8 @@
 			}
 
 			outputWriter := zip.NewWriter(outputBuf)
-			err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args, testCase.excludes)
+			err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false,
+				testCase.args, testCase.excludes, testCase.uncompresses)
 			if errorString(testCase.err) != errorString(err) {
 				t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err))
 			}
@@ -294,15 +370,22 @@
 				t.Fatal(err)
 			}
 			var outputFiles []string
+			var storedFiles []string
 			if len(outputReader.File) > 0 {
 				outputFiles = make([]string, len(outputReader.File))
 				for i, file := range outputReader.File {
 					outputFiles[i] = file.Name
+					if file.Method == zip.Store {
+						storedFiles = append(storedFiles, file.Name)
+					}
 				}
 			}
 
 			if !reflect.DeepEqual(testCase.outputFiles, outputFiles) {
-				t.Fatalf("Output file list does not match:\n got: %v\nwant: %v", outputFiles, testCase.outputFiles)
+				t.Fatalf("Output file list does not match:\nwant: %v\n got: %v", testCase.outputFiles, outputFiles)
+			}
+			if !reflect.DeepEqual(testCase.storedFiles, storedFiles) {
+				t.Fatalf("Stored file list does not match:\nwant: %v\n got: %v", testCase.storedFiles, storedFiles)
 			}
 		})
 	}