Merge Android manifests when assembling apk

Merge all resource dependency manifests using the manifest merger from the
Android SDK, providing the functionality described in
https://developer.android.com/studio/build/manifest-merge.html.

Removing the nontrivial manifest guard in the android_aar_prebuilt() template
will be done in a follow-up change, as well as removing pre-merged manifest
tags, such as "com.google.android.gms.version" meta-data.

Bug: 643967
Change-Id: Ifdf9f3f76f5c80f1a2326dcd47045d032556936f
Reviewed-on: https://chromium-review.googlesource.com/558296
Reviewed-by: Bo Liu <boliu@chromium.org>
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Commit-Queue: Ingemar Ådahl <ingemara@opera.com>
Cr-Original-Commit-Position: refs/heads/master@{#485303}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: f3efbd5b8ec69ef49dbdbf8945f546815039efe3
This commit is contained in:
Ingemar Ådahl 2017-07-10 17:14:01 +00:00 коммит произвёл Commit Bot
Родитель fd574d91e3
Коммит 6ada47bc79
8 изменённых файлов: 176 добавлений и 23 удалений

Просмотреть файл

@ -49,12 +49,14 @@ if (enable_java_templates) {
_data += "android_sdk_build_tools=" +
rebase_path(android_sdk_build_tools, root_build_dir) + CR
_data += "android_sdk_build_tools_version=$android_sdk_build_tools_version$CR"
_data +=
"android_sdk_tools_version_suffix=$android_sdk_tools_version_suffix$CR"
_data +=
"android_sdk_root=" + rebase_path(android_sdk_root, root_build_dir) + CR
_data += "android_sdk_version=$android_sdk_version$CR"
_data += "android_tool_prefix=" +
rebase_path(android_tool_prefix, root_build_dir) + CR
write_file("$root_build_dir/build_vars.txt", _data)
write_file(android_build_vars, _data)
}
# Copy to the lib.unstripped directory so that gdb can easily find it.

Просмотреть файл

@ -364,7 +364,7 @@ class _ProjectContextGenerator(object):
res_dirs.add(
os.path.join(self.EntryOutputDir(root_entry), _RES_SUBDIR))
variables['res_dirs'] = self._Relativize(root_entry, res_dirs)
android_manifest = root_entry.Gradle().get('android_manifest')
android_manifest = root_entry.DepsInfo().get('android_manifest')
if not android_manifest:
android_manifest = self._GenCustomManifest(root_entry)
variables['android_manifest'] = self._Relativize(

100
android/gyp/merge_manifest.py Executable file
Просмотреть файл

@ -0,0 +1,100 @@
#!/usr/bin/env python
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Merges dependency Android manifests into a root manifest."""
import argparse
import contextlib
import os
import sys
import tempfile
import xml.dom.minidom as minidom
from util import build_utils
# Tools library directory - relative to Android SDK root
SDK_TOOLS_LIB_DIR = os.path.join('tools', 'lib')
MANIFEST_MERGER_MAIN_CLASS = 'com.android.manifmerger.Merger'
MANIFEST_MERGER_JARS = [
'common{suffix}.jar',
'manifest-merger{suffix}.jar',
'sdk-common{suffix}.jar',
'sdklib{suffix}.jar',
]
TOOLS_NAMESPACE_PREFIX = 'tools'
TOOLS_NAMESPACE = 'http://schemas.android.com/tools'
@contextlib.contextmanager
def _PatchedManifest(manifest_path):
"""Patches an Android manifest to always include the 'tools' namespace
declaration, as it is not propagated by the manifest merger from the SDK.
See https://issuetracker.google.com/issues/63411481
"""
doc = minidom.parse(manifest_path)
manifests = doc.getElementsByTagName('manifest')
assert len(manifests) == 1
manifest = manifests[0]
manifest.setAttribute('xmlns:%s' % TOOLS_NAMESPACE_PREFIX, TOOLS_NAMESPACE)
tmp_prefix = os.path.basename(manifest_path)
with tempfile.NamedTemporaryFile(prefix=tmp_prefix) as patched_manifest:
doc.writexml(patched_manifest)
patched_manifest.flush()
yield patched_manifest.name
def _BuildManifestMergerClasspath(build_vars):
return ':'.join([
os.path.join(
build_vars['android_sdk_root'],
SDK_TOOLS_LIB_DIR,
jar.format(suffix=build_vars['android_sdk_tools_version_suffix']))
for jar in MANIFEST_MERGER_JARS
])
def main(argv):
argv = build_utils.ExpandFileArgs(argv)
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--build-vars',
help='Path to GN build vars file',
required=True)
parser.add_argument('--root-manifest',
help='Root manifest which to merge into',
required=True)
parser.add_argument('--output', help='Output manifest path', required=True)
parser.add_argument('--extras',
help='GN list of additional manifest to merge')
args = parser.parse_args(argv)
cmd = [
'java',
'-cp',
_BuildManifestMergerClasspath(build_utils.ReadBuildVars(args.build_vars)),
MANIFEST_MERGER_MAIN_CLASS,
'--out', args.output,
]
extras = build_utils.ParseGnList(args.extras)
if extras:
cmd += ['--libs', ':'.join(extras)]
with _PatchedManifest(args.root_manifest) as root_manifest:
cmd += ['--main', root_manifest]
build_utils.CheckOutput(cmd,
# https://issuetracker.google.com/issues/63514300: The merger doesn't set
# a nonzero exit code for failures.
fail_func=lambda returncode, stderr: returncode != 0 or
build_utils.IsTimeStale(args.output, [root_manifest] + extras))
if __name__ == '__main__':
main(sys.argv[1:])

Просмотреть файл

@ -21,6 +21,7 @@ import zipfile
import md5_check # pylint: disable=relative-import
sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
from pylib import constants
from pylib.constants import host_paths
sys.path.append(os.path.join(os.path.dirname(__file__),
@ -81,6 +82,14 @@ def FindInDirectories(directories, filename_filter):
return all_files
def ReadBuildVars(build_vars_path=None):
if not build_vars_path:
build_vars_path = os.path.join(constants.GetOutDirectory(),
"build_vars.txt")
with open(build_vars_path) as f:
return dict(l.rstrip().split('=', 1) for l in f)
def ParseGnList(gn_string):
"""Converts a command-line parameter into a list.

Просмотреть файл

@ -410,7 +410,8 @@ def main(argv):
deps_info['gradle_treat_as_prebuilt'] = options.gradle_treat_as_prebuilt
if options.android_manifest:
gradle['android_manifest'] = options.android_manifest
deps_info['android_manifest'] = options.android_manifest
if options.type in ('java_binary', 'java_library', 'android_apk'):
if options.java_sources_file:
deps_info['java_sources_file'] = options.java_sources_file
@ -706,6 +707,9 @@ def main(argv):
config['uncompressed_locales_java_list'] = (
_CreateLocalePaksAssetJavaList(config['uncompressed_assets']))
config['extra_android_manifests'] = filter(None, (
d.get('android_manifest') for d in all_resources_deps))
# Collect java resources
java_resources_jars = [d['java_resources_jar'] for d in all_library_deps
if 'java_resources_jar' in d]

Просмотреть файл

@ -771,11 +771,6 @@ def _VerifyLibBuildIdsMatch(tools_prefix, *so_files):
'Your output directory is likely stale.')
def _ReadBuildVars(output_dir):
with open(os.path.join(output_dir, 'build_vars.txt')) as f:
return dict(l.replace('//', '').rstrip().split('=', 1) for l in f)
def main():
argparser = argparse.ArgumentParser(description='Print APK size metrics.')
argparser.add_argument('--min-pak-resource-size', type=int, default=20*1024,
@ -814,7 +809,7 @@ def main():
if not args.no_output_dir:
constants.CheckOutputDirectory()
devil_chromium.Initialize()
build_vars = _ReadBuildVars(constants.GetOutDirectory())
build_vars = build_utils.ReadBuildVars()
tools_prefix = os.path.join(constants.GetOutDirectory(),
build_vars['android_tool_prefix'])
else:

Просмотреть файл

@ -45,6 +45,7 @@ if (is_android) {
default_android_sdk_root = "//third_party/android_tools/sdk"
default_android_sdk_version = "26"
default_android_sdk_build_tools_version = "26.0.0"
default_android_sdk_tools_version_suffix = "-25.3.2"
}
if (!defined(default_lint_android_sdk_root)) {
@ -104,6 +105,7 @@ if (is_android) {
android_sdk_root = default_android_sdk_root
android_sdk_version = default_android_sdk_version
android_sdk_build_tools_version = default_android_sdk_build_tools_version
android_sdk_tools_version_suffix = default_android_sdk_tools_version_suffix
lint_android_sdk_root = default_lint_android_sdk_root
lint_android_sdk_version = default_lint_android_sdk_version
@ -194,6 +196,9 @@ if (is_android) {
assert(!(enable_incremental_dx && !is_java_debug))
assert(!(enable_incremental_javac && !is_java_debug))
# Path to where selected build variables are written to.
android_build_vars = "$root_build_dir/build_vars.txt"
# Host stuff -----------------------------------------------------------------
# Defines the name the Android build gives to the current host CPU

Просмотреть файл

@ -1777,11 +1777,11 @@ if (enable_java_templates) {
}
sources = []
}
_android_manifest_deps = []
_android_root_manifest_deps = []
if (defined(invoker.android_manifest_dep)) {
_android_manifest_deps = [ invoker.android_manifest_dep ]
_android_root_manifest_deps = [ invoker.android_manifest_dep ]
}
_android_manifest = invoker.android_manifest
_android_root_manifest = invoker.android_manifest
_rebased_build_config = rebase_path(_build_config, root_build_dir)
_create_abi_split =
@ -1820,13 +1820,13 @@ if (enable_java_templates) {
incremental_install_script_path = _incremental_install_script_path
resources_zip = resources_zip_path
build_config = _build_config
android_manifest = _android_manifest
android_manifest = _android_root_manifest
if (defined(_java_sources_file)) {
java_sources_file = _java_sources_file
}
deps = _android_manifest_deps
deps = _android_root_manifest_deps
if (defined(invoker.deps)) {
possible_config_deps = invoker.deps
@ -1856,6 +1856,34 @@ if (enable_java_templates) {
}
}
_android_manifest =
"$target_gen_dir/${_template_name}_manifest/AndroidManifest.xml"
android_manifest_target = "${_template_name}__merge_manifests"
action(android_manifest_target) {
script = "//build/android/gyp/merge_manifest.py"
sources = [
_android_root_manifest,
]
outputs = [
_android_manifest,
]
args = [
"--build-vars",
rebase_path(android_build_vars, root_build_dir),
"--root-manifest",
rebase_path(_android_root_manifest, root_build_dir),
"--output",
rebase_path(_android_manifest, root_build_dir),
"--extras",
"@FileArg($_rebased_build_config:extra_android_manifests)",
]
deps = _android_root_manifest_deps + [ ":$build_config_target" ]
}
_final_deps = []
if (enable_multidex) {
@ -1886,7 +1914,10 @@ if (enable_java_templates) {
}
build_config = _build_config
deps = _android_manifest_deps + [ ":$build_config_target" ]
deps = [
":$android_manifest_target",
":$build_config_target",
]
if (defined(invoker.deps)) {
deps += invoker.deps
}
@ -1992,7 +2023,10 @@ if (enable_java_templates) {
supports_android = true
requires_android = true
override_build_config = _build_config
deps = _android_manifest_deps + [ ":$build_config_target" ]
deps = [
":$android_manifest_target",
":$build_config_target",
]
android_manifest = _android_manifest
srcjar_deps = _srcjar_deps
@ -2268,17 +2302,19 @@ if (enable_java_templates) {
keystore_password = _keystore_password
# Incremental apk does not use native libs nor final dex.
incremental_deps = deps + _android_manifest_deps + [
incremental_deps = deps + [
":$android_manifest_target",
":$build_config_target",
":$process_resources_target",
]
# This target generates the input file _all_resources_zip_path.
deps += _android_manifest_deps + [
":$build_config_target",
":$process_resources_target",
":$final_dex_target_name",
]
deps += [
":$android_manifest_target",
":$build_config_target",
":$final_dex_target_name",
":$process_resources_target",
]
if ((_native_libs_deps != [] ||
_extra_native_libs_even_when_incremental != []) &&
@ -2311,7 +2347,9 @@ if (enable_java_templates) {
out_manifest =
"$gen_dir/split-manifests/${android_app_abi}/AndroidManifest.xml"
split_name = "abi_${android_app_abi}"
deps = _android_manifest_deps
deps = [
":$android_manifest_target",
]
}
_apk_rule = "${_template_name}__split_apk_abi_${android_app_abi}"