Merge "Allow //visibility:public to override other visibility rules."
diff --git a/README.md b/README.md
index 2658e0d..8fdce4b 100644
--- a/README.md
+++ b/README.md
@@ -81,6 +81,8 @@
Maps may values of any type, including nested maps. Lists and maps may have
trailing commas after the last value.
+Strings can contain double quotes using `\"`, for example `"cat \"a b\""`.
+
### Operators
Strings, lists of strings, and maps can be appended using the `+` operator.
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index a23879f..cb71725 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -123,6 +123,7 @@
"LOCAL_SYSTEM_SHARED_LIBRARIES": "system_shared_libs",
"LOCAL_ASFLAGS": "asflags",
"LOCAL_CLANG_ASFLAGS": "clang_asflags",
+ "LOCAL_COMPATIBILITY_SUPPORT_FILES": "data",
"LOCAL_CONLYFLAGS": "conlyflags",
"LOCAL_CPPFLAGS": "cppflags",
"LOCAL_REQUIRED_MODULES": "required",
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index b3b1ce0..2eab0cc 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -809,6 +809,7 @@
LOCAL_PACKAGE_NAME := FooTest
LOCAL_COMPATIBILITY_SUITE := cts
LOCAL_CTS_TEST_PACKAGE := foo.bar
+LOCAL_COMPATIBILITY_SUPPORT_FILES := file1
include $(BUILD_CTS_PACKAGE)
`,
expected: `
@@ -817,6 +818,7 @@
defaults: ["cts_defaults"],
test_suites: ["cts"],
+ data: ["file1"],
}
`,
},
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ae34e3d..32ccf4c 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -90,6 +90,9 @@
fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
if c.useVndk() {
fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+ if c.isVndk() && !c.static() {
+ fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.vndkVersion())
+ }
}
},
},
diff --git a/cc/cc.go b/cc/cc.go
index 2e551e1..4600a15 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -534,6 +534,13 @@
return false
}
+func (c *Module) vndkVersion() string {
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.Properties.Vndk.Version
+ }
+ return ""
+}
+
func (c *Module) isPgoCompile() bool {
if pgo := c.pgo; pgo != nil {
return pgo.Properties.PgoCompile
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 94a8257..47b60e7 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -108,6 +108,9 @@
// Help catch common 32/64-bit errors.
"-Werror=int-conversion",
+ // Enable the new pass manager.
+ "-fexperimental-new-pass-manager",
+
// Disable overly aggressive warning for macros defined with a leading underscore
// This happens in AndroidConfig.h, which is included nearly everywhere.
// TODO: can we remove this now?
diff --git a/cc/vndk.go b/cc/vndk.go
index a1d67af..60a3d78 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -49,6 +49,10 @@
// Extending another module
Extends *string
+
+ // for vndk_prebuilt_shared, this is set by "version" property.
+ // Otherwise, this is set as PLATFORM_VNDK_VERSION.
+ Version string `blueprint:"mutated"`
}
}
@@ -325,6 +329,14 @@
return
}
+ if m.isVndk() {
+ if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+ m.vndkdep.Properties.Vndk.Version = lib.version()
+ } else {
+ m.vndkdep.Properties.Vndk.Version = mctx.DeviceConfig().PlatformVndkVersion()
+ }
+ }
+
if _, ok := m.linker.(*llndkStubDecorator); ok {
processLlndkLibrary(mctx, m)
return
diff --git a/java/aar.go b/java/aar.go
index 7332e76..65a7c2a 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -84,6 +84,7 @@
useEmbeddedNativeLibs bool
useEmbeddedDex bool
usesNonSdkApis bool
+ sdkLibraries []string
splitNames []string
splits []split
@@ -194,13 +195,15 @@
}
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
- transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext)
+
+ transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+ aaptLibs(ctx, sdkContext)
// App manifest file
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
- manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext,
+ manifestPath := manifestFixer(ctx, manifestSrcPath, sdkContext, sdkLibraries,
a.isLibrary, a.useEmbeddedNativeLibs, a.usesNonSdkApis, a.useEmbeddedDex)
a.transitiveManifestPaths = append(android.Paths{manifestPath}, transitiveStaticLibManifests...)
@@ -303,7 +306,7 @@
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
- staticRRODirs []rroDir, deps android.Paths, flags []string) {
+ staticRRODirs []rroDir, deps android.Paths, flags []string, sdkLibraries []string) {
var sharedLibs android.Paths
@@ -322,7 +325,16 @@
switch ctx.OtherModuleDependencyTag(module) {
case instrumentationForTag:
// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
- case libTag, frameworkResTag:
+ case libTag:
+ if exportPackage != nil {
+ sharedLibs = append(sharedLibs, exportPackage)
+ }
+
+ if _, ok := module.(SdkLibraryDependency); ok {
+ sdkLibraries = append(sdkLibraries, ctx.OtherModuleName(module))
+ }
+
+ case frameworkResTag:
if exportPackage != nil {
sharedLibs = append(sharedLibs, exportPackage)
}
@@ -331,6 +343,7 @@
transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
+ sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...)
outer:
for _, d := range aarDep.ExportedRRODirs() {
@@ -358,8 +371,9 @@
transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
+ sdkLibraries = android.FirstUniqueStrings(sdkLibraries)
- return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags
+ return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, deps, flags, sdkLibraries
}
type AndroidLibrary struct {
@@ -393,6 +407,7 @@
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.isLibrary = true
+ a.aapt.sdkLibraries = a.exportedSdkLibs
a.aapt.buildActions(ctx, sdkContext(a))
ctx.CheckbuildFile(a.proguardOptionsFile)
@@ -603,10 +618,12 @@
linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
linkDeps = append(linkDeps, a.manifest)
- transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext(a))
+ transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags, sdkLibraries :=
+ aaptLibs(ctx, sdkContext(a))
_ = staticLibManifests
_ = staticRRODirs
+ _ = sdkLibraries
linkDeps = append(linkDeps, libDeps...)
linkFlags = append(linkFlags, libFlags...)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 5d3cfa5..b5921be 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -41,8 +41,18 @@
},
"args", "libs")
+// These two libs are added as optional dependencies (<uses-library> with
+// android:required set to false). This is because they haven't existed in pre-P
+// devices, but classes in them were in bootclasspath jars, etc. So making them
+// hard dependencies (android:required=true) would prevent apps from being
+// installed to such legacy devices.
+var optionalUsesLibs = []string{
+ "android.test.base",
+ "android.test.mock",
+}
+
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
-func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
+func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex bool) android.Path {
var args []string
@@ -69,6 +79,14 @@
args = append(args, "--use-embedded-dex")
}
+ for _, usesLib := range sdkLibraries {
+ if inList(usesLib, optionalUsesLibs) {
+ args = append(args, "--optional-uses-library", usesLib)
+ } else {
+ args = append(args, "--uses-library", usesLib)
+ }
+ }
+
var deps android.Paths
targetSdkVersion := sdkVersionOrDefault(ctx, sdkContext.targetSdkVersion())
if targetSdkVersion == ctx.Config().PlatformSdkCodename() &&
diff --git a/java/config/config.go b/java/config/config.go
index 46cd361..f9552d5 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -142,7 +142,8 @@
hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilts/sdk/tools", "aapt2")
- pctx.SourcePathVariable("ManifestFixerCmd", "build/soong/scripts/manifest_fixer.py")
+ pctx.HostBinToolVariable("ManifestCheckCmd", "manifest_check")
+ pctx.HostBinToolVariable("ManifestFixerCmd", "manifest_fixer")
pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger")
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 6881caf..9c78511 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -73,6 +73,7 @@
ctx.Strict("EXTRACT_JAR_PACKAGES", "${ExtractJarPackagesCmd}")
+ ctx.Strict("MANIFEST_CHECK", "${ManifestCheckCmd}")
ctx.Strict("MANIFEST_FIXER", "${ManifestFixerCmd}")
ctx.Strict("ANDROID_MANIFEST_MERGER", "${ManifestMergerCmd}")
diff --git a/java/droiddoc.go b/java/droiddoc.go
index fd7e2a4..57da6b6 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -211,6 +211,7 @@
// Available variables for substitution:
//
// $(location <label>): the path to the arg_files with name <label>
+ // $$: a literal $
Args *string
// names of the output files used in args that will be generated
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 9627dc6..b1ddab4 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -61,7 +61,7 @@
stubFlagsRule(ctx)
// These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them.
- if ctx.Config().FrameworksBaseDirExists(ctx) {
+ if ctx.Config().FrameworksBaseDirExists(ctx) && !ctx.Config().UnbundledBuild() {
h.flags = flagsRule(ctx)
h.metadata = metadataRule(ctx)
} else {
diff --git a/java/java.go b/java/java.go
index 4483083..8dbdfb6 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1301,9 +1301,11 @@
return
}
- // Hidden API CSV generation and dex encoding
- dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
- j.deviceProperties.UncompressDex)
+ if !ctx.Config().UnbundledBuild() {
+ // Hidden API CSV generation and dex encoding
+ dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
+ j.deviceProperties.UncompressDex)
+ }
// merge dex jar with resources if necessary
if j.resourceJar != nil {
diff --git a/java/system_modules.go b/java/system_modules.go
index 9ee0307..8005360 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -87,11 +87,13 @@
module := &SystemModules{}
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+ android.InitDefaultableModule(module)
return module
}
type SystemModules struct {
android.ModuleBase
+ android.DefaultableModuleBase
properties SystemModulesProperties
diff --git a/scripts/Android.bp b/scripts/Android.bp
new file mode 100644
index 0000000..31f5922
--- /dev/null
+++ b/scripts/Android.bp
@@ -0,0 +1,71 @@
+python_binary_host {
+ name: "manifest_fixer",
+ main: "manifest_fixer.py",
+ srcs: [
+ "manifest_fixer.py",
+ "manifest.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+}
+
+python_test_host {
+ name: "manifest_fixer_test",
+ main: "manifest_fixer_test.py",
+ srcs: [
+ "manifest_fixer_test.py",
+ "manifest_fixer.py",
+ "manifest.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+ test_suites: ["general-tests"],
+}
+
+python_binary_host {
+ name: "manifest_check",
+ main: "manifest_check.py",
+ srcs: [
+ "manifest_check.py",
+ "manifest.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+}
+
+python_test_host {
+ name: "manifest_check_test",
+ main: "manifest_check_test.py",
+ srcs: [
+ "manifest_check_test.py",
+ "manifest_check.py",
+ "manifest.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+ test_suites: ["general-tests"],
+}
diff --git a/scripts/TEST_MAPPING b/scripts/TEST_MAPPING
new file mode 100644
index 0000000..1b0a229
--- /dev/null
+++ b/scripts/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit" : [
+ {
+ "name": "manifest_check_test",
+ "host": true
+ },
+ {
+ "name": "manifest_fixer_test",
+ "host": true
+ }
+ ]
+}
diff --git a/scripts/build_broken_logs.go b/scripts/build_broken_logs.go
index 4f3e0de..8021e55 100644
--- a/scripts/build_broken_logs.go
+++ b/scripts/build_broken_logs.go
@@ -65,18 +65,6 @@
warnings: []string{"overriding commands for target"},
},
{
- name: "BUILD_BROKEN_ANDROIDMK_EXPORTS",
- behavior: DefaultDeprecated,
- warnings: []string{"export_keyword"},
- },
- {
- name: "BUILD_BROKEN_ENG_DEBUG_TAGS",
- behavior: DefaultDeprecated,
- warnings: []string{
- "Changes.md#LOCAL_MODULE_TAGS",
- },
- },
- {
name: "BUILD_BROKEN_USES_NETWORK",
behavior: DefaultDeprecated,
},
diff --git a/scripts/manifest.py b/scripts/manifest.py
new file mode 100755
index 0000000..4c75f8b
--- /dev/null
+++ b/scripts/manifest.py
@@ -0,0 +1,117 @@
+#!/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
+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 find_child_with_attribute(element, tag_name, namespace_uri,
+ attr_name, value):
+ for child in get_children_with_tag(element, tag_name):
+ attr = child.getAttributeNodeNS(namespace_uri, attr_name)
+ if attr is not None and attr.value == value:
+ return child
+ return None
+
+
+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 get_indent(element, default_level):
+ indent = ''
+ if element is not None and element.nodeType == minidom.Node.TEXT_NODE:
+ text = element.nodeValue
+ indent = text[:len(text)-len(text.lstrip())]
+ if not indent or indent == '\n':
+ # 1 indent = 4 space
+ indent = '\n' + (' ' * default_level * 4)
+ return indent
+
+
+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')
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
new file mode 100755
index 0000000..9122da1
--- /dev/null
+++ b/scripts/manifest_check.py
@@ -0,0 +1,215 @@
+#!/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 checking that a manifest agrees with the build system."""
+
+from __future__ import print_function
+
+import argparse
+import sys
+from xml.dom import minidom
+
+
+from manifest import android_ns
+from manifest import get_children_with_tag
+from manifest import parse_manifest
+from manifest import write_xml
+
+
+class ManifestMismatchError(Exception):
+ pass
+
+
+def parse_args():
+ """Parse commandline arguments."""
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--uses-library', dest='uses_libraries',
+ action='append',
+ help='specify uses-library entries known to the build system')
+ parser.add_argument('--optional-uses-library',
+ dest='optional_uses_libraries',
+ action='append',
+ help='specify uses-library entries known to the build system with required:false')
+ parser.add_argument('--enforce-uses-libraries',
+ dest='enforce_uses_libraries',
+ action='store_true',
+ help='check the uses-library entries known to the build system against the manifest')
+ parser.add_argument('--extract-target-sdk-version',
+ dest='extract_target_sdk_version',
+ action='store_true',
+ help='print the targetSdkVersion from the manifest')
+ parser.add_argument('--output', '-o', dest='output', help='output AndroidManifest.xml file')
+ parser.add_argument('input', help='input AndroidManifest.xml file')
+ return parser.parse_args()
+
+
+def enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries):
+ """Verify that the <uses-library> tags in the manifest match those provided by the build system.
+
+ Args:
+ doc: The XML document.
+ uses_libraries: The names of <uses-library> tags known to the build system
+ optional_uses_libraries: The names of <uses-library> tags with required:fals
+ known to the build system
+ Raises:
+ RuntimeError: Invalid manifest
+ ManifestMismatchError: Manifest does not match
+ """
+
+ manifest = parse_manifest(doc)
+ elems = get_children_with_tag(manifest, 'application')
+ application = elems[0] if len(elems) == 1 else None
+ if len(elems) > 1:
+ raise RuntimeError('found multiple <application> tags')
+ elif not elems:
+ if uses_libraries or optional_uses_libraries:
+ raise ManifestMismatchError('no <application> tag found')
+ return
+
+ verify_uses_library(application, uses_libraries, optional_uses_libraries)
+
+
+def verify_uses_library(application, uses_libraries, optional_uses_libraries):
+ """Verify that the uses-library values known to the build system match the manifest.
+
+ Args:
+ application: the <application> tag in the manifest.
+ uses_libraries: the names of expected <uses-library> tags.
+ optional_uses_libraries: the names of expected <uses-library> tags with required="false".
+ Raises:
+ ManifestMismatchError: Manifest does not match
+ """
+
+ if uses_libraries is None:
+ uses_libraries = []
+
+ if optional_uses_libraries is None:
+ optional_uses_libraries = []
+
+ manifest_uses_libraries, manifest_optional_uses_libraries = parse_uses_library(application)
+
+ err = []
+ if manifest_uses_libraries != uses_libraries:
+ err.append('Expected required <uses-library> tags "%s", got "%s"' %
+ (', '.join(uses_libraries), ', '.join(manifest_uses_libraries)))
+
+ if manifest_optional_uses_libraries != optional_uses_libraries:
+ err.append('Expected optional <uses-library> tags "%s", got "%s"' %
+ (', '.join(optional_uses_libraries), ', '.join(manifest_optional_uses_libraries)))
+
+ if err:
+ raise ManifestMismatchError('\n'.join(err))
+
+
+def parse_uses_library(application):
+ """Extract uses-library tags from the manifest.
+
+ Args:
+ application: the <application> tag in the manifest.
+ """
+
+ libs = get_children_with_tag(application, 'uses-library')
+
+ uses_libraries = [uses_library_name(x) for x in libs if uses_library_required(x)]
+ optional_uses_libraries = [uses_library_name(x) for x in libs if not uses_library_required(x)]
+
+ return first_unique_elements(uses_libraries), first_unique_elements(optional_uses_libraries)
+
+
+def first_unique_elements(l):
+ result = []
+ [result.append(x) for x in l if x not in result]
+ return result
+
+
+def uses_library_name(lib):
+ """Extract the name attribute of a uses-library tag.
+
+ Args:
+ lib: a <uses-library> tag.
+ """
+ name = lib.getAttributeNodeNS(android_ns, 'name')
+ return name.value if name is not None else ""
+
+
+def uses_library_required(lib):
+ """Extract the required attribute of a uses-library tag.
+
+ Args:
+ lib: a <uses-library> tag.
+ """
+ required = lib.getAttributeNodeNS(android_ns, 'required')
+ return (required.value == 'true') if required is not None else True
+
+
+def extract_target_sdk_version(doc):
+ """Returns the targetSdkVersion from the manifest.
+
+ Args:
+ doc: The XML document.
+ 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) == 0:
+ raise RuntimeError('missing uses-sdk element')
+
+ uses_sdk = uses_sdk[0]
+
+ min_attr = uses_sdk.getAttributeNodeNS(android_ns, 'minSdkVersion')
+ if min_attr is None:
+ raise RuntimeError('minSdkVersion is not specified')
+
+ target_attr = uses_sdk.getAttributeNodeNS(android_ns, 'targetSdkVersion')
+ if target_attr is None:
+ target_attr = min_attr
+
+ return target_attr.value
+
+
+def main():
+ """Program entry point."""
+ try:
+ args = parse_args()
+
+ doc = minidom.parse(args.input)
+
+ if args.enforce_uses_libraries:
+ enforce_uses_libraries(doc,
+ args.uses_libraries,
+ args.optional_uses_libraries)
+
+ if args.extract_target_sdk_version:
+ print(extract_target_sdk_version(doc))
+
+ if args.output:
+ 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_check_test.py b/scripts/manifest_check_test.py
new file mode 100755
index 0000000..7baad5d
--- /dev/null
+++ b/scripts/manifest_check_test.py
@@ -0,0 +1,166 @@
+#!/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.py."""
+
+import sys
+import unittest
+from xml.dom import minidom
+
+import manifest_check
+
+sys.dont_write_bytecode = True
+
+
+def uses_library(name, attr=''):
+ return '<uses-library android:name="%s"%s />' % (name, attr)
+
+
+def required(value):
+ return ' android:required="%s"' % ('true' if value else 'false')
+
+
+class EnforceUsesLibrariesTest(unittest.TestCase):
+ """Unit tests for add_extract_native_libs function."""
+
+ 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)
+ return True
+ except manifest_check.ManifestMismatchError:
+ return False
+
+ manifest_tmpl = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ ' <application>\n'
+ ' %s\n'
+ ' </application>\n'
+ '</manifest>\n')
+
+ def test_uses_library(self):
+ manifest_input = self.manifest_tmpl % (uses_library('foo'))
+ matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ self.assertTrue(matches)
+
+ def test_uses_library_required(self):
+ manifest_input = self.manifest_tmpl % (uses_library('foo', required(True)))
+ matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ self.assertTrue(matches)
+
+ def test_optional_uses_library(self):
+ manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+ matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+ self.assertTrue(matches)
+
+ def test_expected_uses_library(self):
+ manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+ matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ self.assertFalse(matches)
+
+ def test_expected_optional_uses_library(self):
+ manifest_input = self.manifest_tmpl % (uses_library('foo'))
+ matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+ self.assertFalse(matches)
+
+ def test_missing_uses_library(self):
+ manifest_input = self.manifest_tmpl % ('')
+ matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ self.assertFalse(matches)
+
+ def test_missing_optional_uses_library(self):
+ manifest_input = self.manifest_tmpl % ('')
+ matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+ self.assertFalse(matches)
+
+ def test_extra_uses_library(self):
+ manifest_input = self.manifest_tmpl % (uses_library('foo'))
+ matches = self.run_test(manifest_input)
+ self.assertFalse(matches)
+
+ def test_extra_optional_uses_library(self):
+ manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
+ matches = self.run_test(manifest_input)
+ self.assertFalse(matches)
+
+ def test_multiple_uses_library(self):
+ manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+ uses_library('bar')]))
+ matches = self.run_test(manifest_input, uses_libraries=['foo', 'bar'])
+ self.assertTrue(matches)
+
+ def test_multiple_optional_uses_library(self):
+ manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+ uses_library('bar', required(False))]))
+ matches = self.run_test(manifest_input, optional_uses_libraries=['foo', 'bar'])
+ self.assertTrue(matches)
+
+ def test_order_uses_library(self):
+ manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+ uses_library('bar')]))
+ matches = self.run_test(manifest_input, uses_libraries=['bar', 'foo'])
+ self.assertFalse(matches)
+
+ def test_order_optional_uses_library(self):
+ manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+ uses_library('bar', required(False))]))
+ matches = self.run_test(manifest_input, optional_uses_libraries=['bar', 'foo'])
+ self.assertFalse(matches)
+
+ def test_duplicate_uses_library(self):
+ manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+ uses_library('foo')]))
+ matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ self.assertTrue(matches)
+
+ def test_duplicate_optional_uses_library(self):
+ manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
+ uses_library('foo', required(False))]))
+ matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+ self.assertTrue(matches)
+
+ def test_mixed(self):
+ manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
+ uses_library('bar', required(False))]))
+ matches = self.run_test(manifest_input, uses_libraries=['foo'],
+ optional_uses_libraries=['bar'])
+ self.assertTrue(matches)
+
+
+class ExtractTargetSdkVersionTest(unittest.TestCase):
+ def test_target_sdk_version(self):
+ manifest = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" />\n'
+ '</manifest>\n')
+ doc = minidom.parseString(manifest)
+ target_sdk_version = manifest_check.extract_target_sdk_version(doc)
+ self.assertEqual(target_sdk_version, '29')
+
+ def test_min_sdk_version(self):
+ manifest = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ ' <uses-sdk android:minSdkVersion="28" />\n'
+ '</manifest>\n')
+ doc = minidom.parseString(manifest)
+ target_sdk_version = manifest_check.extract_target_sdk_version(doc)
+ self.assertEqual(target_sdk_version, '28')
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 83868e6..bb14851 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -17,30 +17,20 @@
"""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 find_child_with_attribute(element, tag_name, namespace_uri,
- attr_name, value):
- for child in get_children_with_tag(element, tag_name):
- attr = child.getAttributeNodeNS(namespace_uri, attr_name)
- if attr is not None and attr.value == value:
- return child
- return None
+from manifest import android_ns
+from manifest import compare_version_gt
+from manifest import ensure_manifest_android_ns
+from manifest import find_child_with_attribute
+from manifest import get_children_with_tag
+from manifest import get_indent
+from manifest import parse_manifest
+from manifest import write_xml
def parse_args():
@@ -74,76 +64,6 @@
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 get_indent(element, default_level):
- indent = ''
- if element is not None and element.nodeType == minidom.Node.TEXT_NODE:
- text = element.nodeValue
- indent = text[:len(text)-len(text.lstrip())]
- if not indent or indent == '\n':
- # 1 indent = 4 space
- indent = '\n' + (' ' * default_level * 4)
- return indent
-
-
def raise_min_sdk_version(doc, min_sdk_version, target_sdk_version, library):
"""Ensure the manifest contains a <uses-sdk> tag with a minSdkVersion.
@@ -151,6 +71,7 @@
doc: The XML document. May be modified by this function.
min_sdk_version: The requested minSdkVersion attribute.
target_sdk_version: The requested targetSdkVersion attribute.
+ library: True if the manifest is for a library.
Raises:
RuntimeError: invalid manifest
"""
@@ -249,6 +170,7 @@
indent = get_indent(application.previousSibling, 1)
application.appendChild(doc.createTextNode(indent))
+
def add_uses_non_sdk_api(doc):
"""Add android:usesNonSdkApi=true attribute to <application>.
@@ -323,12 +245,6 @@
(attr.value, value))
-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:
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 7ec8999..2035421 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-"""Unit tests for manifest_fixer_test.py."""
+"""Unit tests for manifest_fixer.py."""
import StringIO
import sys
@@ -393,10 +393,10 @@
return output.getvalue()
manifest_tmpl = (
- '<?xml version="1.0" encoding="utf-8"?>\n'
- '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
- ' <application%s/>\n'
- '</manifest>\n')
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ ' <application%s/>\n'
+ '</manifest>\n')
def extract_native_libs(self, value):
return ' android:extractNativeLibs="%s"' % value
@@ -425,4 +425,4 @@
if __name__ == '__main__':
- unittest.main()
+ unittest.main(verbosity=2)
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index c6e5ddc..4335667 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -205,8 +205,6 @@
// Not used, but useful to be in the soong.log
"BOARD_VNDK_VERSION",
- "BUILD_BROKEN_ANDROIDMK_EXPORTS",
- "BUILD_BROKEN_ENG_DEBUG_TAGS",
"DEFAULT_WARNING_BUILD_MODULE_TYPES",
"DEFAULT_ERROR_BUILD_MODULE_TYPES",
diff --git a/ui/build/proc_sync.go b/ui/build/proc_sync.go
index 857786d..0cfe798 100644
--- a/ui/build/proc_sync.go
+++ b/ui/build/proc_sync.go
@@ -34,6 +34,14 @@
if err != nil {
ctx.Logger.Fatal(err)
}
+ lockfilePollDuration := time.Second
+ lockfileTimeout := time.Second * 10
+ if envTimeout := os.Getenv("SOONG_LOCK_TIMEOUT"); envTimeout != "" {
+ lockfileTimeout, err = time.ParseDuration(envTimeout)
+ if err != nil {
+ ctx.Logger.Fatalf("failure parsing SOONG_LOCK_TIMEOUT %q: %s", envTimeout, err)
+ }
+ }
err = lockSynchronous(*lockingInfo, newSleepWaiter(lockfilePollDuration, lockfileTimeout), ctx.Logger)
if err != nil {
ctx.Logger.Fatal(err)
@@ -41,9 +49,6 @@
return lockingInfo
}
-var lockfileTimeout = time.Second * 10
-var lockfilePollDuration = time.Second
-
type lockable interface {
tryLock() error
Unlock() error
@@ -80,15 +85,18 @@
return nil
}
- waited = true
-
done, description := waiter.checkDeadline()
+ if !waited {
+ logger.Printf("Waiting up to %s to lock %v to ensure no other Soong process is running in the same output directory\n", description, lock.description())
+ }
+
+ waited = true
+
if done {
return fmt.Errorf("Tried to lock %s, but timed out %s . Make sure no other Soong process is using it",
lock.description(), waiter.summarize())
} else {
- logger.Printf("Waiting up to %s to lock %v to ensure no other Soong process is running in the same output directory\n", description, lock.description())
waiter.wait()
}
}