Merge "Changed droiddoc.go to compile Metalava based android.jar"
diff --git a/android/paths.go b/android/paths.go
index 8cc3182..af2f956 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -950,7 +950,8 @@
 		if ctx.InstallInData() {
 			partition = "data"
 		} else if ctx.InstallInRecovery() {
-			partition = "recovery/root"
+			// the layout of recovery partion is the same as that of system partition
+			partition = "recovery/root/system"
 		} else if ctx.SocSpecific() {
 			partition = ctx.DeviceConfig().VendorPath()
 		} else if ctx.DeviceSpecific() {
diff --git a/cc/binary.go b/cc/binary.go
index 04b912a..4a6eb93 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -357,11 +357,6 @@
 }
 
 func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) {
-	// <recovery>/bin is a symlink to /system/bin. Recovery binaries are all in /sbin.
-	if ctx.inRecovery() {
-		binary.baseInstaller.dir = "sbin"
-	}
-
 	binary.baseInstaller.install(ctx, file)
 	for _, symlink := range binary.Properties.Symlinks {
 		binary.symlinks = append(binary.symlinks,
diff --git a/cc/compiler.go b/cc/compiler.go
index 10cec8c..8d034c9 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -332,6 +332,10 @@
 			"-D__ANDROID_API__="+version, "-D__ANDROID_VNDK__")
 	}
 
+	if ctx.inRecovery() {
+		flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_RECOVERY__")
+	}
+
 	instructionSet := String(compiler.Properties.Instruction_set)
 	if flags.RequiredInstructionSet != "" {
 		instructionSet = flags.RequiredInstructionSet
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 73cee5c..172784a 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -53,15 +53,12 @@
 			"-mcpu=cortex-a53",
 		},
 		"cortex-a55": []string{
-			// The cortex-a55 target is not yet supported,
-			// so use cortex-a53.
-			"-mcpu=cortex-a53",
+			"-mcpu=cortex-a55",
 		},
 		"cortex-a75": []string{
-			// Use the cortex-a53 since it is similar to the little
+			// Use the cortex-a55 since it is similar to the little
 			// core (cortex-a55) and is sensitive to ordering.
-			// The cortex-a55 target is not yet supported.
-			"-mcpu=cortex-a53",
+			"-mcpu=cortex-a55",
 		},
 		"kryo": []string{
 			// Use the cortex-a57 cpu since some compilers
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 398df90..4719fb7 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -100,7 +100,7 @@
 			"-D__ARM_FEATURE_LPAE=1",
 		},
 		"cortex-a55": []string{
-			"-mcpu=cortex-a53",
+			"-mcpu=cortex-a55",
 			"-mfpu=neon-fp-armv8",
 			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
 			// don't advertise.
@@ -109,7 +109,7 @@
 			"-D__ARM_FEATURE_LPAE=1",
 		},
 		"cortex-a75": []string{
-			"-mcpu=cortex-a53",
+			"-mcpu=cortex-a55",
 			"-mfpu=neon-fp-armv8",
 			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
 			// don't advertise.
diff --git a/cc/sabi.go b/cc/sabi.go
index f5a7c77..42b2f35 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -74,8 +74,13 @@
 
 	// RSClang does not support recent mcpu option likes exynos-m2.
 	// So we need overriding mcpu option when we want to use it.
-	if ctx.Arch().CpuVariant == "exynos-m2" {
-		flags.ToolingCFlags = append(flags.ToolingCFlags, "-mcpu=cortex-a53")
+	mappedArch := map[string]string{
+		"exynos-m2":  "cortex-a53",
+		"cortex-a55": "cortex-a53",
+		"cortex-a75": "cortex-a57",
+	}
+	if arch, ok := mappedArch[ctx.Arch().CpuVariant]; ok {
+		flags.ToolingCFlags = append(flags.ToolingCFlags, "-mcpu="+arch)
 	}
 
 	return flags
diff --git a/java/config/config.go b/java/config/config.go
index c6555f1..2fa48cb 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -132,4 +132,6 @@
 	}
 
 	hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilts/sdk/tools", "aapt2")
+
+	pctx.SourcePathVariable("ManifestFixerCmd", "build/soong/scripts/manifest_fixer.py")
 }
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 4dffa02..0e62274 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -72,4 +72,6 @@
 	ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultJacocoExcludeFilter, ","))
 
 	ctx.Strict("EXTRACT_JAR_PACKAGES", "${ExtractJarPackagesCmd}")
+
+	ctx.Strict("MANIFEST_FIXER", "${ManifestFixerCmd}")
 }
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 50318bb..3f4b076 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -50,6 +50,20 @@
 	// no need to implement
 }
 
+func parseJarPath(ctx android.BaseModuleContext, path string) (module string, apiver string, scope string) {
+	elements := strings.Split(path, "/")
+
+	apiver = elements[0]
+	scope = elements[1]
+	if scope != "public" && scope != "system" && scope != "test" && scope != "core" {
+		// scope must be public, system or test
+		return
+	}
+
+	module = strings.TrimSuffix(elements[2], ".jar")
+	return
+}
+
 func parseApiFilePath(ctx android.BaseModuleContext, path string) (module string, apiver int, scope string) {
 	elements := strings.Split(path, "/")
 	ver, err := strconv.Atoi(elements[0])
@@ -70,6 +84,22 @@
 	return
 }
 
+func createImport(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
+	props := struct {
+		Name        *string
+		Jars        []string
+		Sdk_version *string
+		Installable *bool
+	}{}
+	props.Name = proptools.StringPtr("sdk_" + scope + "_" + apiver + "_" + module)
+	props.Jars = append(props.Jars, path)
+	// TODO(hansson): change to scope after migration is done.
+	props.Sdk_version = proptools.StringPtr("current")
+	props.Installable = proptools.BoolPtr(false)
+
+	mctx.CreateModule(android.ModuleFactoryAdaptor(ImportFactory), &props)
+}
+
 func createFilegroup(mctx android.TopDownMutatorContext, module string, scope string, apiver string, path string) {
 	fgName := module + ".api." + scope + "." + apiver
 	filegroupProps := struct {
@@ -81,55 +111,82 @@
 	mctx.CreateModule(android.ModuleFactoryAdaptor(android.FileGroupFactory), &filegroupProps)
 }
 
+func prebuiltSdkStubs(mctx android.TopDownMutatorContext) {
+	mydir := mctx.ModuleDir() + "/"
+	// <apiver>/<scope>/<module>.jar
+	files, err := mctx.GlobWithDeps(mydir+"*/*/*.jar", nil)
+	if err != nil {
+		mctx.ModuleErrorf("failed to glob jar files under %q: %s", mydir, err)
+	}
+	if len(files) == 0 {
+		mctx.ModuleErrorf("no jar file found under %q", mydir)
+	}
+
+	for _, f := range files {
+		// create a Import module for each jar file
+		localPath := strings.TrimPrefix(f, mydir)
+		module, apiver, scope := parseJarPath(mctx, localPath)
+
+		if len(module) != 0 {
+			createImport(mctx, module, scope, apiver, localPath)
+		}
+	}
+}
+
+func prebuiltApiFiles(mctx android.TopDownMutatorContext) {
+	mydir := mctx.ModuleDir() + "/"
+	// <apiver>/<scope>/api/<module>.txt
+	files, err := mctx.GlobWithDeps(mydir+"*/*/api/*.txt", nil)
+	if err != nil {
+		mctx.ModuleErrorf("failed to glob api txt files under %q: %s", mydir, err)
+	}
+	if len(files) == 0 {
+		mctx.ModuleErrorf("no api file found under %q", mydir)
+	}
+
+	// construct a map to find out the latest api file path
+	// for each (<module>, <scope>) pair.
+	type latestApiInfo struct {
+		module string
+		scope  string
+		apiver int
+		path   string
+	}
+	m := make(map[string]latestApiInfo)
+
+	for _, f := range files {
+		// create a filegroup for each api txt file
+		localPath := strings.TrimPrefix(f, mydir)
+		module, apiver, scope := parseApiFilePath(mctx, localPath)
+		createFilegroup(mctx, module, scope, strconv.Itoa(apiver), localPath)
+
+		// find the latest apiver
+		key := module + "." + scope
+		info, ok := m[key]
+		if !ok {
+			m[key] = latestApiInfo{module, scope, apiver, localPath}
+		} else if apiver > info.apiver {
+			info.apiver = apiver
+			info.path = localPath
+		}
+	}
+	// create filegroups for the latest version of (<module>, <scope>) pairs
+	// sort the keys in order to make build.ninja stable
+	keys := make([]string, 0, len(m))
+	for k := range m {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	for _, k := range keys {
+		info := m[k]
+		createFilegroup(mctx, info.module, info.scope, "latest", info.path)
+	}
+}
+
 func prebuiltApisMutator(mctx android.TopDownMutatorContext) {
 	if _, ok := mctx.Module().(*prebuiltApis); ok {
-		mydir := mctx.ModuleDir() + "/"
-		// <apiver>/<scope>/api/<module>.txt
-		files, err := mctx.GlobWithDeps(mydir+"*/*/api/*.txt", nil)
-		if err != nil {
-			mctx.ModuleErrorf("failed to glob api txt files under %q: %s", mydir, err)
-		}
-		if len(files) == 0 {
-			mctx.ModuleErrorf("no api file found under %q", mydir)
-		}
-
-		// construct a map to find out the latest api file path
-		// for each (<module>, <scope>) pair.
-		type latestApiInfo struct {
-			module string
-			scope  string
-			apiver int
-			path   string
-		}
-		m := make(map[string]latestApiInfo)
-
-		for _, f := range files {
-			// create a filegroup for each api txt file
-			localPath := strings.TrimPrefix(f, mydir)
-			module, apiver, scope := parseApiFilePath(mctx, localPath)
-			createFilegroup(mctx, module, scope, strconv.Itoa(apiver), localPath)
-
-			// find the latest apiver
-			key := module + "." + scope
-			info, ok := m[key]
-			if !ok {
-				m[key] = latestApiInfo{module, scope, apiver, localPath}
-			} else if apiver > info.apiver {
-				info.apiver = apiver
-				info.path = localPath
-			}
-		}
-		// create filegroups for the latest version of (<module>, <scope>) pairs
-		// sort the keys in order to make build.ninja stable
-		keys := make([]string, 0, len(m))
-		for k := range m {
-			keys = append(keys, k)
-		}
-		sort.Strings(keys)
-		for _, k := range keys {
-			info := m[k]
-			createFilegroup(mctx, info.module, info.scope, "latest", info.path)
-		}
+		prebuiltApiFiles(mctx)
+		prebuiltSdkStubs(mctx)
 	}
 }
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index abd2dc2..aee528f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -106,6 +106,11 @@
 	// list of package names that must be hidden from the API
 	Hidden_api_packages []string
 
+	Errorprone struct {
+		// List of javac flags that should only be used when running errorprone.
+		Javacflags []string
+	}
+
 	// TODO: determines whether to create HTML doc or not
 	//Html_doc *bool
 }
@@ -445,6 +450,9 @@
 		Device_specific  *bool
 		Product_specific *bool
 		Required         []string
+		Errorprone       struct {
+			Javacflags []string
+		}
 	}{}
 
 	props.Name = proptools.StringPtr(module.implName())
@@ -453,6 +461,7 @@
 	props.Static_libs = module.properties.Static_libs
 	// XML file is installed along with the impl lib
 	props.Required = []string{module.xmlFileName()}
+	props.Errorprone.Javacflags = module.properties.Errorprone.Javacflags
 
 	if module.SocSpecific() {
 		props.Soc_specific = proptools.BoolPtr(true)
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
new file mode 100755
index 0000000..f34f6c3
--- /dev/null
+++ b/scripts/manifest_fixer.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# 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.
+#
+"""A tool for inserting values from the build system into a manifest."""
+
+from __future__ import print_function
+import argparse
+import sys
+from xml.dom import minidom
+
+
+android_ns = 'http://schemas.android.com/apk/res/android'
+
+
+def get_children_with_tag(parent, tag_name):
+  children = []
+  for child in  parent.childNodes:
+    if child.nodeType == minidom.Node.ELEMENT_NODE and \
+       child.tagName == tag_name:
+      children.append(child)
+  return children
+
+
+def parse_args():
+  """Parse commandline arguments."""
+
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--minSdkVersion', default='', dest='min_sdk_version',
+                      help='specify minSdkVersion used by the build system')
+  parser.add_argument('input', help='input AndroidManifest.xml file')
+  parser.add_argument('output', help='input AndroidManifest.xml file')
+  return parser.parse_args()
+
+
+def parse_manifest(doc):
+  """Get the manifest element."""
+
+  manifest = doc.documentElement
+  if manifest.tagName != 'manifest':
+    raise RuntimeError('expected manifest tag at root')
+  return manifest
+
+
+def ensure_manifest_android_ns(doc):
+  """Make sure the manifest tag defines the android namespace."""
+
+  manifest = parse_manifest(doc)
+
+  ns = manifest.getAttributeNodeNS(minidom.XMLNS_NAMESPACE, 'android')
+  if ns is None:
+    attr = doc.createAttributeNS(minidom.XMLNS_NAMESPACE, 'xmlns:android')
+    attr.value = android_ns
+    manifest.setAttributeNode(attr)
+  elif ns.value != android_ns:
+    raise RuntimeError('manifest tag has incorrect android namespace ' +
+                       ns.value)
+
+
+def as_int(s):
+  try:
+    i = int(s)
+  except ValueError:
+    return s, False
+  return i, True
+
+
+def compare_version_gt(a, b):
+  """Compare two SDK versions.
+
+  Compares a and b, treating codenames like 'Q' as higher
+  than numerical versions like '28'.
+
+  Returns True if a > b
+
+  Args:
+    a: value to compare
+    b: value to compare
+  Returns:
+    True if a is a higher version than b
+  """
+
+  a, a_is_int = as_int(a.upper())
+  b, b_is_int = as_int(b.upper())
+
+  if a_is_int == b_is_int:
+    # Both are codenames or both are versions, compare directly
+    return a > b
+  else:
+    # One is a codename, the other is not.  Return true if
+    # b is an integer version
+    return b_is_int
+
+
+def raise_min_sdk_version(doc, requested):
+  """Ensure the manifest contains a <uses-sdk> tag with a minSdkVersion.
+
+  Args:
+    doc: The XML document.  May be modified by this function.
+    requested: The requested minSdkVersion attribute.
+  Raises:
+    RuntimeError: invalid manifest
+  """
+
+  manifest = parse_manifest(doc)
+
+  # Get or insert the uses-sdk element
+  uses_sdk = get_children_with_tag(manifest, 'uses-sdk')
+  if len(uses_sdk) > 1:
+    raise RuntimeError('found multiple uses-sdk elements')
+  elif len(uses_sdk) == 1:
+    element = uses_sdk[0]
+  else:
+    element = doc.createElement('uses-sdk')
+    indent = ''
+    first = manifest.firstChild
+    if first is not None and first.nodeType == minidom.Node.TEXT_NODE:
+      text = first.nodeValue
+      indent = text[:len(text)-len(text.lstrip())]
+    if not indent or indent == '\n':
+      indent = '\n    '
+
+    manifest.insertBefore(element, manifest.firstChild)
+
+    # Insert an indent before uses-sdk to line it up with the indentation of the
+    # other children of the <manifest> tag.
+    manifest.insertBefore(doc.createTextNode(indent), manifest.firstChild)
+
+  # Get or insert the minSdkVersion attribute
+  min_attr = element.getAttributeNodeNS(android_ns, 'minSdkVersion')
+  if min_attr is None:
+    min_attr = doc.createAttributeNS(android_ns, 'android:minSdkVersion')
+    min_attr.value = '1'
+    element.setAttributeNode(min_attr)
+
+  # Update the value of the minSdkVersion attribute if necessary
+  if compare_version_gt(requested, min_attr.value):
+    min_attr.value = requested
+
+
+def write_xml(f, doc):
+  f.write('<?xml version="1.0" encoding="utf-8"?>\n')
+  for node in doc.childNodes:
+    f.write(node.toxml(encoding='utf-8') + '\n')
+
+
+def main():
+  """Program entry point."""
+  try:
+    args = parse_args()
+
+    doc = minidom.parse(args.input)
+
+    ensure_manifest_android_ns(doc)
+
+    if args.min_sdk_version:
+      raise_min_sdk_version(doc, args.min_sdk_version)
+
+    with open(args.output, 'wb') as f:
+      write_xml(f, doc)
+
+  # pylint: disable=broad-except
+  except Exception as err:
+    print('error: ' + str(err), file=sys.stderr)
+    sys.exit(-1)
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
new file mode 100755
index 0000000..ccfa8fb
--- /dev/null
+++ b/scripts/manifest_fixer_test.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# 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.
+#
+"""Unit tests for manifest_fixer_test.py."""
+
+import StringIO
+import sys
+import unittest
+from xml.dom import minidom
+
+import manifest_fixer
+
+sys.dont_write_bytecode = True
+
+
+class CompareVersionGtTest(unittest.TestCase):
+  """Unit tests for compare_version_gt function."""
+
+  def test_sdk(self):
+    """Test comparing sdk versions."""
+    self.assertTrue(manifest_fixer.compare_version_gt('28', '27'))
+    self.assertFalse(manifest_fixer.compare_version_gt('27', '28'))
+    self.assertFalse(manifest_fixer.compare_version_gt('28', '28'))
+
+  def test_codename(self):
+    """Test comparing codenames."""
+    self.assertTrue(manifest_fixer.compare_version_gt('Q', 'P'))
+    self.assertFalse(manifest_fixer.compare_version_gt('P', 'Q'))
+    self.assertFalse(manifest_fixer.compare_version_gt('Q', 'Q'))
+
+  def test_sdk_codename(self):
+    """Test comparing sdk versions with codenames."""
+    self.assertTrue(manifest_fixer.compare_version_gt('Q', '28'))
+    self.assertFalse(manifest_fixer.compare_version_gt('28', 'Q'))
+
+  def test_compare_numeric(self):
+    """Test that numbers are compared in numeric and not lexicographic order."""
+    self.assertTrue(manifest_fixer.compare_version_gt('18', '8'))
+
+
+class RaiseMinSdkVersionTest(unittest.TestCase):
+  """Unit tests for raise_min_sdk_version function."""
+
+  def raise_min_sdk_version_test(self, input_manifest, min_sdk_version):
+    doc = minidom.parseString(input_manifest)
+    manifest_fixer.raise_min_sdk_version(doc, min_sdk_version)
+    output = StringIO.StringIO()
+    manifest_fixer.write_xml(output, doc)
+    return output.getvalue()
+
+  manifest_tmpl = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+      '%s'
+      '</manifest>\n')
+
+  def uses_sdk(self, v, extra=''):
+    if extra:
+      extra = ' ' + extra
+    return '    <uses-sdk android:minSdkVersion="%s"%s/>\n' % (v, extra)
+
+  def test_no_uses_sdk(self):
+    """Tests inserting a uses-sdk element into a manifest."""
+
+    manifest_input = self.manifest_tmpl % ''
+    expected = self.manifest_tmpl % self.uses_sdk('28')
+    output = self.raise_min_sdk_version_test(manifest_input, '28')
+    self.assertEqual(output, expected)
+
+  def test_no_min(self):
+    """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
+
+    manifest_input = self.manifest_tmpl % '    <uses-sdk extra="foo"/>\n'
+    expected = self.manifest_tmpl % self.uses_sdk('28', 'extra="foo"')
+    output = self.raise_min_sdk_version_test(manifest_input, '28')
+    self.assertEqual(output, expected)
+
+  def test_raise_min(self):
+    """Tests inserting a minSdkVersion attribute into a uses-sdk element."""
+
+    manifest_input = self.manifest_tmpl % self.uses_sdk('27')
+    expected = self.manifest_tmpl % self.uses_sdk('28')
+    output = self.raise_min_sdk_version_test(manifest_input, '28')
+    self.assertEqual(output, expected)
+
+  def test_raise(self):
+    """Tests raising a minSdkVersion attribute."""
+
+    manifest_input = self.manifest_tmpl % self.uses_sdk('27')
+    expected = self.manifest_tmpl % self.uses_sdk('28')
+    output = self.raise_min_sdk_version_test(manifest_input, '28')
+    self.assertEqual(output, expected)
+
+  def test_no_raise_min(self):
+    """Tests a minSdkVersion that doesn't need raising."""
+
+    manifest_input = self.manifest_tmpl % self.uses_sdk('28')
+    expected = manifest_input
+    output = self.raise_min_sdk_version_test(manifest_input, '27')
+    self.assertEqual(output, expected)
+
+  def test_raise_codename(self):
+    """Tests raising a minSdkVersion attribute to a codename."""
+
+    manifest_input = self.manifest_tmpl % self.uses_sdk('28')
+    expected = self.manifest_tmpl % self.uses_sdk('P')
+    output = self.raise_min_sdk_version_test(manifest_input, 'P')
+    self.assertEqual(output, expected)
+
+  def test_no_raise_codename(self):
+    """Tests a minSdkVersion codename that doesn't need raising."""
+
+    manifest_input = self.manifest_tmpl % self.uses_sdk('P')
+    expected = manifest_input
+    output = self.raise_min_sdk_version_test(manifest_input, '28')
+    self.assertEqual(output, expected)
+
+  def test_extra(self):
+    """Tests that extra attributes and elements are maintained."""
+
+    manifest_input = self.manifest_tmpl % (
+        '    <!-- comment -->\n'
+        '    <uses-sdk android:minSdkVersion="27" extra="foo"/>\n'
+        '    <application/>\n')
+
+    expected = self.manifest_tmpl % (
+        '    <!-- comment -->\n'
+        '    <uses-sdk android:minSdkVersion="28" extra="foo"/>\n'
+        '    <application/>\n')
+
+    output = self.raise_min_sdk_version_test(manifest_input, '28')
+
+    self.assertEqual(output, expected)
+
+  def test_indent(self):
+    """Tests that an inserted element copies the existing indentation."""
+
+    manifest_input = self.manifest_tmpl % '  <!-- comment -->\n'
+
+    expected = self.manifest_tmpl % (
+        '  <uses-sdk android:minSdkVersion="28"/>\n'
+        '  <!-- comment -->\n')
+
+    output = self.raise_min_sdk_version_test(manifest_input, '28')
+
+    self.assertEqual(output, expected)
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 81edd32..743da4a 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -77,6 +77,8 @@
 		"--color_warnings",
 		"--gen_all_targets",
 		"--werror_find_emulator",
+		"--no_builtin_rules",
+		"--werror_suffix_rules",
 		"--kati_stats",
 		"-f", "build/make/core/main.mk",
 	}