Commit c83a88d3 authored by anton's avatar anton Committed by Commit bot

Re-invent page aligning libraries in APK file.

With this change setting 'load_library_from_zip_file' to 1 will now
construct the APK with a new tool chain. The purpose of this change is
to contruct the APK in such a way that the page alignment is not broken
by the chrome signing process. To achieve this the tool is written in
Java so it shares the same underlying JarOutputStream implementation.
The key things that we depend on are that the filenames are output in
lexographical order with the META_INF files at the end of the file.
That zipalign adds 4 byte alignment to STORED files and this is done by
adding padding to the zip extra field.

BUG=390618

Review URL: https://codereview.chromium.org/595933003

Cr-Commit-Position: refs/heads/master@{#297439}
parent 0a65bf2b
......@@ -27,9 +27,11 @@
['android_webview_build==0', {
'zipalign_path%': ['<!@(find <(android_sdk_root) -name zipalign)'],
'rezip_path%': '<(PRODUCT_DIR)/rezip',
'rezip_apk_jar_path%': '<(PRODUCT_DIR)/lib.java/rezip_apk.jar'
}, {
'zipalign_path%': "",
'rezip_path%': "",
'rezip_apk_jar_path%': "",
}],
],
},
......@@ -52,5 +54,6 @@
'--key-passwd=<(keystore_password)',
'--load-library-from-zip-file=<(load_library_from_zip_file)',
'--rezip-path=<(rezip_path)',
'--rezip-apk-jar-path=<(rezip_apk_jar_path)',
],
}
......@@ -14,17 +14,33 @@ import tempfile
from util import build_utils
def RenameLibInApk(rezip_path, in_zip_file, out_zip_file):
rename_cmd = [
rezip_path,
'rename',
def AddPageAlignment(rezip_apk_jar_path, in_zip_file, out_zip_file):
rezip_apk_cmd = [
'java',
'-classpath',
rezip_apk_jar_path,
'RezipApk',
'addalignment',
in_zip_file,
out_zip_file,
]
build_utils.CheckOutput(rename_cmd)
build_utils.CheckOutput(rezip_apk_cmd)
def ReorderAndAlignApk(rezip_apk_jar_path, in_zip_file, out_zip_file):
rezip_apk_cmd = [
'java',
'-classpath',
rezip_apk_jar_path,
'RezipApk',
'reorder',
in_zip_file,
out_zip_file,
]
build_utils.CheckOutput(rezip_apk_cmd)
def SignApk(key_path, key_name, key_passwd, unsigned_path, signed_path):
def JarSigner(key_path, key_name, key_passwd, unsigned_path, signed_path):
shutil.copy(unsigned_path, signed_path)
sign_cmd = [
'jarsigner',
......@@ -48,20 +64,10 @@ def AlignApk(zipalign_path, unaligned_path, final_path):
build_utils.CheckOutput(align_cmd)
def UncompressLibAndPageAlignInApk(rezip_path, in_zip_file, out_zip_file):
def RenameAndUncompressLibInApk(rezip_path, in_zip_file, out_zip_file):
rename_cmd = [
rezip_path,
'inflatealign',
in_zip_file,
out_zip_file,
]
build_utils.CheckOutput(rename_cmd)
def DropDataDescriptorsInApk(rezip_path, in_zip_file, out_zip_file):
rename_cmd = [
rezip_path,
'dropdescriptors',
'renameinflate',
in_zip_file,
out_zip_file,
]
......@@ -72,6 +78,8 @@ def main():
parser = optparse.OptionParser()
build_utils.AddDepfileOption(parser)
parser.add_option('--rezip-apk-jar-path',
help='Path to the RezipApk jar file.')
parser.add_option('--zipalign-path', help='Path to the zipalign tool.')
parser.add_option('--rezip-path', help='Path to the rezip executable.')
parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.')
......@@ -90,41 +98,38 @@ def main():
with tempfile.NamedTemporaryFile() as signed_apk_path_tmp, \
tempfile.NamedTemporaryFile() as apk_to_sign_tmp, \
tempfile.NamedTemporaryFile() as apk_without_descriptors_tmp, \
tempfile.NamedTemporaryFile() as aligned_apk_tmp:
tempfile.NamedTemporaryFile() as uncompress_lib_apk_tmp:
if options.load_library_from_zip_file:
# We alter the name of the library so that the Android Package Manager
# does not extract it into a separate file. This must be done before
# signing, as the filename is part of the signed manifest.
# signing, as the filename is part of the signed manifest. At the same
# time we uncompress the library, which is necessary so that it can be
# loaded directly from the APK.
uncompress_lib_apk_path = uncompress_lib_apk_tmp.name
RenameAndUncompressLibInApk(
options.rezip_path, options.unsigned_apk_path,
uncompress_lib_apk_path)
apk_to_sign = apk_to_sign_tmp.name
RenameLibInApk(options.rezip_path, options.unsigned_apk_path, apk_to_sign)
# Move the library to a page boundary by adding a page alignment file.
AddPageAlignment(
options.rezip_apk_jar_path, uncompress_lib_apk_path, apk_to_sign)
else:
apk_to_sign = options.unsigned_apk_path
signed_apk_path = signed_apk_path_tmp.name
SignApk(options.key_path, options.key_name, options.key_passwd,
apk_to_sign, signed_apk_path)
JarSigner(options.key_path, options.key_name, options.key_passwd,
apk_to_sign, signed_apk_path)
if options.load_library_from_zip_file:
# Signing adds data descriptors to the APK. These are redundant
# information. We remove them as otherwise they can cause a
# miscalculation in the page alignment.
apk_to_align = apk_without_descriptors_tmp.name
DropDataDescriptorsInApk(
options.rezip_path, signed_apk_path, apk_to_align)
aligned_apk = aligned_apk_tmp.name
# Reorder the contents of the APK. This re-establishes the canonical
# order which means the library will be back at its page aligned location.
# This step also aligns uncompressed items to 4 bytes.
ReorderAndAlignApk(
options.rezip_apk_jar_path, signed_apk_path, options.final_apk_path)
else:
apk_to_align = signed_apk_path
aligned_apk = options.final_apk_path
# Align uncompress items to 4 bytes
AlignApk(options.zipalign_path, apk_to_align, aligned_apk)
if options.load_library_from_zip_file:
# Uncompress the library and make sure that it is page aligned.
UncompressLibAndPageAlignInApk(
options.rezip_path, aligned_apk, options.final_apk_path)
# Align uncompressed items to 4 bytes
AlignApk(options.zipalign_path, signed_apk_path, options.final_apk_path)
if options.depfile:
build_utils.WriteDepfile(
......
......@@ -18,6 +18,41 @@
'sources': [
'rezip/rezip.cc',
],
},
{
'target_name': 'rezip_apk_jar',
'type': 'none',
'variables': {
'java_in_dir': 'rezip',
'compile_stamp': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)/compile.stamp',
'javac_jar_path': '<(PRODUCT_DIR)/lib.java/rezip_apk.jar',
},
'actions': [
{
'action_name': 'javac_<(_target_name)',
'message': 'Compiling <(_target_name) java sources',
'variables': {
'java_sources': ['>!@(find >(java_in_dir) -name "*.java")'],
},
'inputs': [
'<(DEPTH)/build/android/gyp/util/build_utils.py',
'<(DEPTH)/build/android/gyp/javac.py',
'>@(java_sources)',
],
'outputs': [
'<(compile_stamp)',
'<(javac_jar_path)',
],
'action': [
'python', '<(DEPTH)/build/android/gyp/javac.py',
'--classpath=',
'--classes-dir=<(SHARED_INTERMEDIATE_DIR)/<(_target_name)',
'--jar-path=<(javac_jar_path)',
'--stamp=<(compile_stamp)',
'>@(java_sources)',
]
},
],
}
],
}
This diff is collapsed.
......@@ -490,6 +490,8 @@ int main(int argc, const char* argv[]) {
LOG(ERROR) << " renames files of the form lib/*/lib*.so to "
"lib/*/crazy.lib*.so. Note libchromium_android_linker.so is "
"not renamed as the crazy linker can not load itself.";
LOG(ERROR) << " 'renameinflate':";
LOG(ERROR) << " combines rename and inflate steps in a single pass.";
exit(1);
}
......@@ -501,12 +503,17 @@ int main(int argc, const char* argv[]) {
AlignFun align_fun = NULL;
RenameFun rename_fun = NULL;
bool check_page_align = false;
// Note although only "renameinflate" is used in the build process, the
// other steps are used in the LGPL compliance process.
if (strcmp("inflatealign", action) == 0) {
inflate_predicate_fun = &IsCrazyLibraryFilename;
align_fun = &PageAlignCrazyLibrary;
check_page_align = true;
} else if (strcmp("rename", action) == 0) {
rename_fun = &RenameLibraryForCrazyLinker;
} else if (strcmp("renameinflate", action) == 0) {
rename_fun = &RenameLibraryForCrazyLinker;
inflate_predicate_fun = &IsLibraryFilename;
} else if (strcmp("dropdescriptors", action) == 0) {
// Minizip does not know about data descriptors, so the default
// copying action will drop the descriptors. This should be fine
......
......@@ -512,6 +512,7 @@
],
'dependencies': [
'<(DEPTH)/build/android/rezip.gyp:rezip#host',
'<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
],
}],
['gyp_managed_install == 1', {
......@@ -547,6 +548,7 @@
],
'dependencies': [
'<(DEPTH)/build/android/rezip.gyp:rezip#host',
'<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
],
}],
['is_test_apk == 1', {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment