Merge changes Iae2bda98,I68e64888,I75af16e7

* changes:
  Remove gcc-specific optimizations
  Move some flags to affect all devices
  Move -fvisibility-inlines-hidden to global device cppflags
diff --git a/android/paths.go b/android/paths.go
index d6a1c66..4adaa2d 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"path/filepath"
 	"reflect"
+	"sort"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -380,6 +381,38 @@
 	return ret
 }
 
+// DirectorySortedPaths is a slice of paths that are sorted such that all files in a directory
+// (including subdirectories) are in a contiguous subslice of the list, and can be found in
+// O(log(N)) time using a binary search on the directory prefix.
+type DirectorySortedPaths Paths
+
+func PathsToDirectorySortedPaths(paths Paths) DirectorySortedPaths {
+	ret := append(DirectorySortedPaths(nil), paths...)
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i].String() < ret[j].String()
+	})
+	return ret
+}
+
+// PathsInDirectory returns a subslice of the DirectorySortedPaths as a Paths that contains all entries
+// that are in the specified directory and its subdirectories.
+func (p DirectorySortedPaths) PathsInDirectory(dir string) Paths {
+	prefix := filepath.Clean(dir) + "/"
+	start := sort.Search(len(p), func(i int) bool {
+		return prefix < p[i].String()
+	})
+
+	ret := p[start:]
+
+	end := sort.Search(len(ret), func(i int) bool {
+		return !strings.HasPrefix(ret[i].String(), prefix)
+	})
+
+	ret = ret[:end]
+
+	return Paths(ret)
+}
+
 // WritablePaths is a slice of WritablePaths, used for multiple outputs.
 type WritablePaths []WritablePath
 
diff --git a/android/paths_test.go b/android/paths_test.go
index 248f4d4..82ae4dc 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -340,3 +340,75 @@
 		})
 	}
 }
+
+func TestDirectorySortedPaths(t *testing.T) {
+	makePaths := func() Paths {
+		return Paths{
+			PathForTesting("a.txt"),
+			PathForTesting("a/txt"),
+			PathForTesting("a/b/c"),
+			PathForTesting("a/b/d"),
+			PathForTesting("b"),
+			PathForTesting("b/b.txt"),
+			PathForTesting("a/a.txt"),
+		}
+	}
+
+	expected := []string{
+		"a.txt",
+		"a/a.txt",
+		"a/b/c",
+		"a/b/d",
+		"a/txt",
+		"b",
+		"b/b.txt",
+	}
+
+	paths := makePaths()
+	reversePaths := make(Paths, len(paths))
+	for i, v := range paths {
+		reversePaths[len(paths)-i-1] = v
+	}
+
+	sortedPaths := PathsToDirectorySortedPaths(paths)
+	reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
+
+	if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
+		t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
+	}
+
+	if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
+		t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
+	}
+
+	expectedA := []string{
+		"a/a.txt",
+		"a/b/c",
+		"a/b/d",
+		"a/txt",
+	}
+
+	inA := sortedPaths.PathsInDirectory("a")
+	if !reflect.DeepEqual(inA.Strings(), expectedA) {
+		t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
+	}
+
+	expectedA_B := []string{
+		"a/b/c",
+		"a/b/d",
+	}
+
+	inA_B := sortedPaths.PathsInDirectory("a/b")
+	if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
+		t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
+	}
+
+	expectedB := []string{
+		"b/b.txt",
+	}
+
+	inB := sortedPaths.PathsInDirectory("b")
+	if !reflect.DeepEqual(inB.Strings(), expectedB) {
+		t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
+	}
+}
diff --git a/android/variable.go b/android/variable.go
index d89c146..4272817 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -205,26 +205,29 @@
 
 func (v *productVariables) SetDefaultConfig() {
 	*v = productVariables{
-		Platform_sdk_version:       intPtr(24),
+		Platform_sdk_version:              intPtr(26),
+		Platform_version_active_codenames: []string{"P"},
+		Platform_version_future_codenames: []string{"P"},
+
 		HostArch:                   stringPtr("x86_64"),
 		HostSecondaryArch:          stringPtr("x86"),
-		DeviceName:                 stringPtr("flounder"),
+		DeviceName:                 stringPtr("generic_arm64"),
 		DeviceArch:                 stringPtr("arm64"),
 		DeviceArchVariant:          stringPtr("armv8-a"),
-		DeviceCpuVariant:           stringPtr("denver64"),
+		DeviceCpuVariant:           stringPtr("generic"),
 		DeviceAbi:                  &[]string{"arm64-v8a"},
 		DeviceUsesClang:            boolPtr(true),
 		DeviceSecondaryArch:        stringPtr("arm"),
-		DeviceSecondaryArchVariant: stringPtr("armv7-a-neon"),
-		DeviceSecondaryCpuVariant:  stringPtr("denver"),
-		DeviceSecondaryAbi:         &[]string{"armeabi-v7a"},
+		DeviceSecondaryArchVariant: stringPtr("armv8-a"),
+		DeviceSecondaryCpuVariant:  stringPtr("generic"),
+		DeviceSecondaryAbi:         &[]string{"armeabi-v7a", "armeabi"},
 
 		AAPTConfig:          &[]string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
 		AAPTPreferredConfig: stringPtr("xhdpi"),
 		AAPTCharacteristics: stringPtr("nosdcard"),
 		AAPTPrebuiltDPI:     &[]string{"xhdpi", "xxhdpi"},
 
-		Malloc_not_svelte: boolPtr(false),
+		Malloc_not_svelte: boolPtr(true),
 		Safestack:         boolPtr(false),
 	}
 
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 40373cc..154b3f4 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -151,7 +151,7 @@
 	return stub.libraryDecorator.link(ctx, flags, deps, objs)
 }
 
-func newLLndkStubLibrary() *Module {
+func NewLLndkStubLibrary() *Module {
 	module, library := NewLibrary(android.DeviceSupported)
 	library.BuildOnlyShared()
 	module.stl = nil
@@ -175,7 +175,7 @@
 }
 
 func llndkLibraryFactory() android.Module {
-	module := newLLndkStubLibrary()
+	module := NewLLndkStubLibrary()
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
 	return module
 }
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 2ca7ebf..0619b5c 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -114,11 +114,7 @@
 	} else if os.Args[1] == "--dumpvars-mode" {
 		dumpVars(buildCtx, config, os.Args[2:])
 	} else {
-		toBuild := build.BuildAll
-		if config.Checkbuild() {
-			toBuild |= build.RunBuildTests
-		}
-		build.Build(buildCtx, config, toBuild)
+		build.Build(buildCtx, config, build.BuildAll)
 	}
 }
 
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 5809894..d1b4943 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -36,7 +36,6 @@
         "proc_sync.go",
         "signal.go",
         "soong.go",
-        "test_build.go",
         "util.go",
     ],
     testSrcs: [
diff --git a/ui/build/build.go b/ui/build/build.go
index 78eb6a3..0df22b3 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -68,7 +68,6 @@
 	BuildSoong         = 1 << iota
 	BuildKati          = 1 << iota
 	BuildNinja         = 1 << iota
-	RunBuildTests      = 1 << iota
 	BuildAll           = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
 )
 
@@ -173,18 +172,14 @@
 		}
 	}
 
-	// Write combined ninja file
-	createCombinedBuildNinjaFile(ctx, config)
-
-	if what&RunBuildTests != 0 {
-		testForDanglingRules(ctx, config)
-	}
-
 	if what&BuildNinja != 0 {
 		if !config.SkipMake() {
 			installCleanIfNecessary(ctx, config)
 		}
 
+		// Write combined ninja file
+		createCombinedBuildNinjaFile(ctx, config)
+
 		// Run ninja
 		runNinja(ctx, config)
 	}
diff --git a/ui/build/config.go b/ui/build/config.go
index 99ae2da..940bb2f 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -34,12 +34,11 @@
 	environ   *Environment
 
 	// From the arguments
-	parallel   int
-	keepGoing  int
-	verbose    bool
-	checkbuild bool
-	dist       bool
-	skipMake   bool
+	parallel  int
+	keepGoing int
+	verbose   bool
+	dist      bool
+	skipMake  bool
 
 	// From the product config
 	katiArgs     []string
@@ -207,8 +206,6 @@
 		} else {
 			if arg == "dist" {
 				c.dist = true
-			} else if arg == "checkbuild" {
-				c.checkbuild = true
 			}
 			c.arguments = append(c.arguments, arg)
 		}
@@ -316,12 +313,6 @@
 	panic("SetKatiSuffix has not been called")
 }
 
-// Checkbuild returns true if "checkbuild" was one of the build goals, which means that the
-// user is interested in additional checks at the expense of build time.
-func (c *configImpl) Checkbuild() bool {
-	return c.checkbuild
-}
-
 func (c *configImpl) Dist() bool {
 	return c.dist
 }
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
deleted file mode 100644
index d5e244c..0000000
--- a/ui/build/test_build.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2017 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 build
-
-import (
-	"bufio"
-	"path/filepath"
-	"strings"
-)
-
-// Checks for files in the out directory that have a rule that depends on them but no rule to
-// create them. This catches a common set of build failures where a rule to generate a file is
-// deleted (either by deleting a module in an Android.mk file, or by modifying the build system
-// incorrectly).  These failures are often not caught by a local incremental build because the
-// previously built files are still present in the output directory.
-func testForDanglingRules(ctx Context, config Config) {
-	ctx.BeginTrace("test for dangling rules")
-	defer ctx.EndTrace()
-
-	// Get a list of leaf nodes in the dependency graph from ninja
-	executable := config.PrebuiltBuildTool("ninja")
-
-	args := []string{}
-	args = append(args, config.NinjaArgs()...)
-	args = append(args, "-f", config.CombinedNinjaFile())
-	args = append(args, "-t", "targets", "rule")
-
-	cmd := Command(ctx, config, "ninja", executable, args...)
-	stdout, err := cmd.StdoutPipe()
-	if err != nil {
-		ctx.Fatal(err)
-	}
-
-	cmd.StartOrFatal()
-
-	outDir := config.OutDir()
-	bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
-	miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
-
-	var danglingRules []string
-
-	scanner := bufio.NewScanner(stdout)
-	for scanner.Scan() {
-		line := scanner.Text()
-		if !strings.HasPrefix(line, outDir) {
-			// Leaf node is not in the out directory.
-			continue
-		}
-		if strings.HasPrefix(line, bootstrapDir) || strings.HasPrefix(line, miniBootstrapDir) {
-			// Leaf node is in one of Soong's bootstrap directories, which do not have
-			// full build rules in the primary build.ninja file.
-			continue
-		}
-		danglingRules = append(danglingRules, line)
-	}
-
-	cmd.WaitOrFatal()
-
-	if len(danglingRules) > 0 {
-		ctx.Println("Dependencies in out found with no rule to create them:")
-		for _, dep := range danglingRules {
-			ctx.Println(dep)
-		}
-		ctx.Fatal("")
-	}
-}
diff --git a/zip/Android.bp b/zip/Android.bp
index d708089..3bb4f25 100644
--- a/zip/Android.bp
+++ b/zip/Android.bp
@@ -19,6 +19,7 @@
     pkgPath: "android/soong/zip",
     deps: [
         "android-archive-zip",
+        "blueprint-pathtools",
         "soong-jar",
     ],
     srcs: [
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index 348728c..c0418f7 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -120,14 +120,15 @@
 }
 
 var (
-	out          = flag.String("o", "", "file to write zip file to")
-	manifest     = flag.String("m", "", "input jar manifest file name")
-	directories  = flag.Bool("d", false, "include directories in zip")
-	rootPrefix   = flag.String("P", "", "path prefix within the zip at which to place files")
-	relativeRoot = flag.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments")
-	parallelJobs = flag.Int("j", runtime.NumCPU(), "number of parallel threads to use")
-	compLevel    = flag.Int("L", 5, "deflate compression level (0-9)")
-	emulateJar   = flag.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
+	out            = flag.String("o", "", "file to write zip file to")
+	manifest       = flag.String("m", "", "input jar manifest file name")
+	directories    = flag.Bool("d", false, "include directories in zip")
+	rootPrefix     = flag.String("P", "", "path prefix within the zip at which to place files")
+	relativeRoot   = flag.String("C", "", "path to use as relative root of files in following -f, -l, or -D arguments")
+	parallelJobs   = flag.Int("j", runtime.NumCPU(), "number of parallel threads to use")
+	compLevel      = flag.Int("L", 5, "deflate compression level (0-9)")
+	emulateJar     = flag.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'")
+	writeIfChanged = flag.Bool("write_if_changed", false, "only update resultant .zip if it has changed")
 
 	fArgs            zip.FileArgs
 	nonDeflatedFiles = make(uniqueSet)
@@ -163,6 +164,7 @@
 		ManifestSourcePath:       *manifest,
 		NumParallelJobs:          *parallelJobs,
 		NonDeflatedFiles:         nonDeflatedFiles,
+		WriteIfChanged:           *writeIfChanged,
 	})
 	if err != nil {
 		fmt.Fprintln(os.Stderr, err.Error())
diff --git a/zip/zip.go b/zip/zip.go
index 95520fe..c878a0c 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -32,6 +32,8 @@
 	"sync"
 	"time"
 
+	"github.com/google/blueprint/pathtools"
+
 	"android/soong/jar"
 	"android/soong/third_party/zip"
 )
@@ -127,6 +129,7 @@
 	ManifestSourcePath       string
 	NumParallelJobs          int
 	NonDeflatedFiles         map[string]bool
+	WriteIfChanged           bool
 }
 
 func Run(args ZipArgs) (err error) {
@@ -186,8 +189,38 @@
 		}
 	}
 
-	return w.write(args.OutputFilePath, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.NumParallelJobs)
+	buf := &bytes.Buffer{}
+	var out io.Writer = buf
 
+	if !args.WriteIfChanged {
+		f, err := os.Create(args.OutputFilePath)
+		if err != nil {
+			return err
+		}
+
+		defer f.Close()
+		defer func() {
+			if err != nil {
+				os.Remove(args.OutputFilePath)
+			}
+		}()
+
+		out = f
+	}
+
+	err = w.write(out, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.NumParallelJobs)
+	if err != nil {
+		return err
+	}
+
+	if args.WriteIfChanged {
+		err := pathtools.WriteFileIfChanged(args.OutputFilePath, buf.Bytes(), 0666)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
 }
 
 func fillPathPairs(prefix, rel, src string, pathMappings *[]pathMapping, nonDeflatedFiles map[string]bool) error {
@@ -226,19 +259,7 @@
 	io.Seeker
 }
 
-func (z *ZipWriter) write(out string, pathMappings []pathMapping, manifest string, emulateJar bool, parallelJobs int) error {
-	f, err := os.Create(out)
-	if err != nil {
-		return err
-	}
-
-	defer f.Close()
-	defer func() {
-		if err != nil {
-			os.Remove(out)
-		}
-	}()
-
+func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, emulateJar bool, parallelJobs int) error {
 	z.errors = make(chan error)
 	defer close(z.errors)
 
@@ -324,6 +345,7 @@
 		case op := <-writeOpChan:
 			currentWriteOpChan = nil
 
+			var err error
 			if op.fh.Method == zip.Deflate {
 				currentWriter, err = zipw.CreateCompressedHeader(op.fh)
 			} else {
@@ -356,21 +378,21 @@
 			currentReader = futureReader
 
 		case reader := <-currentReader:
-			_, err = io.Copy(currentWriter, reader)
+			_, err := io.Copy(currentWriter, reader)
 			if err != nil {
 				return err
 			}
 
 			currentReader = nil
 
-		case err = <-z.errors:
+		case err := <-z.errors:
 			return err
 		}
 	}
 
 	// One last chance to catch an error
 	select {
-	case err = <-z.errors:
+	case err := <-z.errors:
 		return err
 	default:
 		zipw.Close()