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 @@ ...@@ -27,9 +27,11 @@
['android_webview_build==0', { ['android_webview_build==0', {
'zipalign_path%': ['<!@(find <(android_sdk_root) -name zipalign)'], 'zipalign_path%': ['<!@(find <(android_sdk_root) -name zipalign)'],
'rezip_path%': '<(PRODUCT_DIR)/rezip', 'rezip_path%': '<(PRODUCT_DIR)/rezip',
'rezip_apk_jar_path%': '<(PRODUCT_DIR)/lib.java/rezip_apk.jar'
}, { }, {
'zipalign_path%': "", 'zipalign_path%': "",
'rezip_path%': "", 'rezip_path%': "",
'rezip_apk_jar_path%': "",
}], }],
], ],
}, },
...@@ -52,5 +54,6 @@ ...@@ -52,5 +54,6 @@
'--key-passwd=<(keystore_password)', '--key-passwd=<(keystore_password)',
'--load-library-from-zip-file=<(load_library_from_zip_file)', '--load-library-from-zip-file=<(load_library_from_zip_file)',
'--rezip-path=<(rezip_path)', '--rezip-path=<(rezip_path)',
'--rezip-apk-jar-path=<(rezip_apk_jar_path)',
], ],
} }
...@@ -14,17 +14,33 @@ import tempfile ...@@ -14,17 +14,33 @@ import tempfile
from util import build_utils from util import build_utils
def RenameLibInApk(rezip_path, in_zip_file, out_zip_file): def AddPageAlignment(rezip_apk_jar_path, in_zip_file, out_zip_file):
rename_cmd = [ rezip_apk_cmd = [
rezip_path, 'java',
'rename', '-classpath',
rezip_apk_jar_path,
'RezipApk',
'addalignment',
in_zip_file, in_zip_file,
out_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) shutil.copy(unsigned_path, signed_path)
sign_cmd = [ sign_cmd = [
'jarsigner', 'jarsigner',
...@@ -48,20 +64,10 @@ def AlignApk(zipalign_path, unaligned_path, final_path): ...@@ -48,20 +64,10 @@ def AlignApk(zipalign_path, unaligned_path, final_path):
build_utils.CheckOutput(align_cmd) 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 = [ rename_cmd = [
rezip_path, rezip_path,
'inflatealign', 'renameinflate',
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',
in_zip_file, in_zip_file,
out_zip_file, out_zip_file,
] ]
...@@ -72,6 +78,8 @@ def main(): ...@@ -72,6 +78,8 @@ def main():
parser = optparse.OptionParser() parser = optparse.OptionParser()
build_utils.AddDepfileOption(parser) 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('--zipalign-path', help='Path to the zipalign tool.')
parser.add_option('--rezip-path', help='Path to the rezip executable.') parser.add_option('--rezip-path', help='Path to the rezip executable.')
parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.') parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.')
...@@ -90,41 +98,38 @@ def main(): ...@@ -90,41 +98,38 @@ def main():
with tempfile.NamedTemporaryFile() as signed_apk_path_tmp, \ with tempfile.NamedTemporaryFile() as signed_apk_path_tmp, \
tempfile.NamedTemporaryFile() as apk_to_sign_tmp, \ tempfile.NamedTemporaryFile() as apk_to_sign_tmp, \
tempfile.NamedTemporaryFile() as apk_without_descriptors_tmp, \ tempfile.NamedTemporaryFile() as uncompress_lib_apk_tmp:
tempfile.NamedTemporaryFile() as aligned_apk_tmp:
if options.load_library_from_zip_file: if options.load_library_from_zip_file:
# We alter the name of the library so that the Android Package Manager # 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 # 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 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: else:
apk_to_sign = options.unsigned_apk_path apk_to_sign = options.unsigned_apk_path
signed_apk_path = signed_apk_path_tmp.name signed_apk_path = signed_apk_path_tmp.name
SignApk(options.key_path, options.key_name, options.key_passwd, JarSigner(options.key_path, options.key_name, options.key_passwd,
apk_to_sign, signed_apk_path) apk_to_sign, signed_apk_path)
if options.load_library_from_zip_file: if options.load_library_from_zip_file:
# Signing adds data descriptors to the APK. These are redundant # Reorder the contents of the APK. This re-establishes the canonical
# information. We remove them as otherwise they can cause a # order which means the library will be back at its page aligned location.
# miscalculation in the page alignment. # This step also aligns uncompressed items to 4 bytes.
apk_to_align = apk_without_descriptors_tmp.name ReorderAndAlignApk(
DropDataDescriptorsInApk( options.rezip_apk_jar_path, signed_apk_path, options.final_apk_path)
options.rezip_path, signed_apk_path, apk_to_align)
aligned_apk = aligned_apk_tmp.name
else: else:
apk_to_align = signed_apk_path # Align uncompressed items to 4 bytes
aligned_apk = options.final_apk_path AlignApk(options.zipalign_path, signed_apk_path, 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)
if options.depfile: if options.depfile:
build_utils.WriteDepfile( build_utils.WriteDepfile(
......
...@@ -18,6 +18,41 @@ ...@@ -18,6 +18,41 @@
'sources': [ 'sources': [
'rezip/rezip.cc', '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[]) { ...@@ -490,6 +490,8 @@ int main(int argc, const char* argv[]) {
LOG(ERROR) << " renames files of the form lib/*/lib*.so to " LOG(ERROR) << " renames files of the form lib/*/lib*.so to "
"lib/*/crazy.lib*.so. Note libchromium_android_linker.so is " "lib/*/crazy.lib*.so. Note libchromium_android_linker.so is "
"not renamed as the crazy linker can not load itself."; "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); exit(1);
} }
...@@ -501,12 +503,17 @@ int main(int argc, const char* argv[]) { ...@@ -501,12 +503,17 @@ int main(int argc, const char* argv[]) {
AlignFun align_fun = NULL; AlignFun align_fun = NULL;
RenameFun rename_fun = NULL; RenameFun rename_fun = NULL;
bool check_page_align = false; 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) { if (strcmp("inflatealign", action) == 0) {
inflate_predicate_fun = &IsCrazyLibraryFilename; inflate_predicate_fun = &IsCrazyLibraryFilename;
align_fun = &PageAlignCrazyLibrary; align_fun = &PageAlignCrazyLibrary;
check_page_align = true; check_page_align = true;
} else if (strcmp("rename", action) == 0) { } else if (strcmp("rename", action) == 0) {
rename_fun = &RenameLibraryForCrazyLinker; rename_fun = &RenameLibraryForCrazyLinker;
} else if (strcmp("renameinflate", action) == 0) {
rename_fun = &RenameLibraryForCrazyLinker;
inflate_predicate_fun = &IsLibraryFilename;
} else if (strcmp("dropdescriptors", action) == 0) { } else if (strcmp("dropdescriptors", action) == 0) {
// Minizip does not know about data descriptors, so the default // Minizip does not know about data descriptors, so the default
// copying action will drop the descriptors. This should be fine // copying action will drop the descriptors. This should be fine
......
...@@ -512,6 +512,7 @@ ...@@ -512,6 +512,7 @@
], ],
'dependencies': [ 'dependencies': [
'<(DEPTH)/build/android/rezip.gyp:rezip#host', '<(DEPTH)/build/android/rezip.gyp:rezip#host',
'<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
], ],
}], }],
['gyp_managed_install == 1', { ['gyp_managed_install == 1', {
...@@ -547,6 +548,7 @@ ...@@ -547,6 +548,7 @@
], ],
'dependencies': [ 'dependencies': [
'<(DEPTH)/build/android/rezip.gyp:rezip#host', '<(DEPTH)/build/android/rezip.gyp:rezip#host',
'<(DEPTH)/build/android/rezip.gyp:rezip_apk_jar',
], ],
}], }],
['is_test_apk == 1', { ['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