Build the payload image only during apk-in-apex signing
When doing apk-in-apex signing, the package name is not reserved during the apex repacking. As a result, the name accidentally reverts to 'com.android.wifi' from 'com.google.android.wifi'. This cl changes the behavior to call 'apexer' by passing the '--payload_only' argument. So we don't build the apex file from scratch and the old AndroidManifest.xml will be reused. Test: 152084536 Bug: unit tests pass Change-Id: I8332b2ee84832fb196f2e1c4309abac5ab92e153
This commit is contained in:
@@ -27,6 +27,8 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
OPTIONS = common.OPTIONS
|
OPTIONS = common.OPTIONS
|
||||||
|
|
||||||
|
APEX_PAYLOAD_IMAGE = 'apex_payload.img'
|
||||||
|
|
||||||
|
|
||||||
class ApexInfoError(Exception):
|
class ApexInfoError(Exception):
|
||||||
"""An Exception raised during Apex Information command."""
|
"""An Exception raised during Apex Information command."""
|
||||||
@@ -50,15 +52,11 @@ class ApexApkSigner(object):
|
|||||||
self.key_passwords = key_passwords
|
self.key_passwords = key_passwords
|
||||||
self.codename_to_api_level_map = codename_to_api_level_map
|
self.codename_to_api_level_map = codename_to_api_level_map
|
||||||
|
|
||||||
def ProcessApexFile(self, apk_keys, payload_key, payload_public_key,
|
def ProcessApexFile(self, apk_keys, payload_key):
|
||||||
signing_args=None):
|
|
||||||
"""Scans and signs the apk files and repack the apex
|
"""Scans and signs the apk files and repack the apex
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
apk_keys: A dict that holds the signing keys for apk files.
|
apk_keys: A dict that holds the signing keys for apk files.
|
||||||
payload_key: The path to the apex payload signing key.
|
|
||||||
payload_public_key: The path to the public key corresponding to the
|
|
||||||
payload signing key.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The repacked apex file containing the signed apk files.
|
The repacked apex file containing the signed apk files.
|
||||||
@@ -89,8 +87,7 @@ class ApexApkSigner(object):
|
|||||||
logger.info('No apk file has been signed in %s', self.apex_path)
|
logger.info('No apk file has been signed in %s', self.apex_path)
|
||||||
return self.apex_path
|
return self.apex_path
|
||||||
|
|
||||||
return self.RepackApexPayload(payload_dir, payload_key, payload_public_key,
|
return self.RepackApexPayload(payload_dir, payload_key)
|
||||||
signing_args)
|
|
||||||
|
|
||||||
def ExtractApexPayloadAndSignApks(self, apk_entries, apk_keys):
|
def ExtractApexPayloadAndSignApks(self, apk_entries, apk_keys):
|
||||||
"""Extracts the payload image and signs the containing apk files."""
|
"""Extracts the payload image and signs the containing apk files."""
|
||||||
@@ -118,27 +115,15 @@ class ApexApkSigner(object):
|
|||||||
has_signed_apk = True
|
has_signed_apk = True
|
||||||
return payload_dir, has_signed_apk
|
return payload_dir, has_signed_apk
|
||||||
|
|
||||||
def RepackApexPayload(self, payload_dir, payload_key, payload_public_key,
|
def RepackApexPayload(self, payload_dir, payload_key):
|
||||||
signing_args=None):
|
|
||||||
"""Rebuilds the apex file with the updated payload directory."""
|
"""Rebuilds the apex file with the updated payload directory."""
|
||||||
apex_dir = common.MakeTempDir()
|
apex_dir = common.MakeTempDir()
|
||||||
# Extract the apex file and reuse its meta files as repack parameters.
|
# Extract the apex file and reuse its meta files as repack parameters.
|
||||||
common.UnzipToDir(self.apex_path, apex_dir)
|
common.UnzipToDir(self.apex_path, apex_dir)
|
||||||
|
|
||||||
android_jar_path = common.OPTIONS.android_jar_path
|
|
||||||
if not android_jar_path:
|
|
||||||
android_jar_path = os.path.join(os.environ.get('ANDROID_BUILD_TOP', ''),
|
|
||||||
'prebuilts', 'sdk', 'current', 'public',
|
|
||||||
'android.jar')
|
|
||||||
logger.warning('android_jar_path not found in options, falling back to'
|
|
||||||
' use %s', android_jar_path)
|
|
||||||
|
|
||||||
arguments_dict = {
|
arguments_dict = {
|
||||||
'manifest': os.path.join(apex_dir, 'apex_manifest.pb'),
|
'manifest': os.path.join(apex_dir, 'apex_manifest.pb'),
|
||||||
'build_info': os.path.join(apex_dir, 'apex_build_info.pb'),
|
'build_info': os.path.join(apex_dir, 'apex_build_info.pb'),
|
||||||
'android_jar_path': android_jar_path,
|
|
||||||
'key': payload_key,
|
'key': payload_key,
|
||||||
'pubkey': payload_public_key,
|
|
||||||
}
|
}
|
||||||
for filename in arguments_dict.values():
|
for filename in arguments_dict.values():
|
||||||
assert os.path.exists(filename), 'file {} not found'.format(filename)
|
assert os.path.exists(filename), 'file {} not found'.format(filename)
|
||||||
@@ -151,29 +136,30 @@ class ApexApkSigner(object):
|
|||||||
elif os.path.isdir(path):
|
elif os.path.isdir(path):
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
|
|
||||||
repacked_apex = common.MakeTempFile(suffix='.apex')
|
# TODO(xunchang) the signing process can be improved by using
|
||||||
repack_cmd = ['apexer', '--force', '--include_build_info',
|
# '--unsigned_payload_only'. But we need to parse the vbmeta earlier for
|
||||||
'--do_not_check_keyname', '--apexer_tool_path',
|
# the signing arguments, e.g. algorithm, salt, etc.
|
||||||
os.getenv('PATH')]
|
payload_img = os.path.join(apex_dir, APEX_PAYLOAD_IMAGE)
|
||||||
|
generate_image_cmd = ['apexer', '--force', '--payload_only',
|
||||||
|
'--do_not_check_keyname', '--apexer_tool_path',
|
||||||
|
os.getenv('PATH')]
|
||||||
for key, val in arguments_dict.items():
|
for key, val in arguments_dict.items():
|
||||||
repack_cmd.extend(['--' + key, val])
|
generate_image_cmd.extend(['--' + key, val])
|
||||||
# Add quote to the signing_args as we will pass
|
|
||||||
# --signing_args "--signing_helper_with_files=%path" to apexer
|
|
||||||
if signing_args:
|
|
||||||
repack_cmd.extend(['--signing_args', '"{}"'.format(signing_args)])
|
|
||||||
# optional arguments for apex repacking
|
# optional arguments for apex repacking
|
||||||
manifest_json = os.path.join(apex_dir, 'apex_manifest.json')
|
manifest_json = os.path.join(apex_dir, 'apex_manifest.json')
|
||||||
if os.path.exists(manifest_json):
|
if os.path.exists(manifest_json):
|
||||||
repack_cmd.extend(['--manifest_json', manifest_json])
|
generate_image_cmd.extend(['--manifest_json', manifest_json])
|
||||||
assets_dir = os.path.join(apex_dir, 'assets')
|
generate_image_cmd.extend([payload_dir, payload_img])
|
||||||
if os.path.isdir(assets_dir):
|
|
||||||
repack_cmd.extend(['--assets_dir', assets_dir])
|
|
||||||
repack_cmd.extend([payload_dir, repacked_apex])
|
|
||||||
if OPTIONS.verbose:
|
if OPTIONS.verbose:
|
||||||
repack_cmd.append('-v')
|
generate_image_cmd.append('-v')
|
||||||
common.RunAndCheckOutput(repack_cmd)
|
common.RunAndCheckOutput(generate_image_cmd)
|
||||||
|
|
||||||
return repacked_apex
|
# Add the payload image back to the apex file.
|
||||||
|
common.ZipDelete(self.apex_path, APEX_PAYLOAD_IMAGE)
|
||||||
|
with zipfile.ZipFile(self.apex_path, 'a') as output_apex:
|
||||||
|
common.ZipWrite(output_apex, payload_img, APEX_PAYLOAD_IMAGE,
|
||||||
|
compress_type=zipfile.ZIP_STORED)
|
||||||
|
return self.apex_path
|
||||||
|
|
||||||
|
|
||||||
def SignApexPayload(avbtool, payload_file, payload_key_path, payload_key_name,
|
def SignApexPayload(avbtool, payload_file, payload_key_path, payload_key_name,
|
||||||
@@ -311,16 +297,13 @@ def SignApex(avbtool, apex_data, payload_key, container_key, container_pw,
|
|||||||
with open(apex_file, 'wb') as apex_fp:
|
with open(apex_file, 'wb') as apex_fp:
|
||||||
apex_fp.write(apex_data)
|
apex_fp.write(apex_data)
|
||||||
|
|
||||||
APEX_PAYLOAD_IMAGE = 'apex_payload.img'
|
|
||||||
APEX_PUBKEY = 'apex_pubkey'
|
APEX_PUBKEY = 'apex_pubkey'
|
||||||
|
|
||||||
# 1. Extract the apex payload image and sign the containing apk files. Repack
|
# 1. Extract the apex payload image and sign the containing apk files. Repack
|
||||||
# the apex file after signing.
|
# the apex file after signing.
|
||||||
payload_public_key = common.ExtractAvbPublicKey(avbtool, payload_key)
|
|
||||||
apk_signer = ApexApkSigner(apex_file, container_pw,
|
apk_signer = ApexApkSigner(apex_file, container_pw,
|
||||||
codename_to_api_level_map)
|
codename_to_api_level_map)
|
||||||
apex_file = apk_signer.ProcessApexFile(apk_keys, payload_key,
|
apex_file = apk_signer.ProcessApexFile(apk_keys, payload_key)
|
||||||
payload_public_key, signing_args)
|
|
||||||
|
|
||||||
# 2a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
|
# 2a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
|
||||||
# payload_key.
|
# payload_key.
|
||||||
@@ -341,7 +324,7 @@ def SignApex(avbtool, apex_data, payload_key, container_key, container_pw,
|
|||||||
signing_args)
|
signing_args)
|
||||||
|
|
||||||
# 2b. Update the embedded payload public key.
|
# 2b. Update the embedded payload public key.
|
||||||
|
payload_public_key = common.ExtractAvbPublicKey(avbtool, payload_key)
|
||||||
common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
|
common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
|
||||||
if APEX_PUBKEY in zip_items:
|
if APEX_PUBKEY in zip_items:
|
||||||
common.ZipDelete(apex_file, APEX_PUBKEY)
|
common.ZipDelete(apex_file, APEX_PUBKEY)
|
||||||
|
@@ -14,8 +14,10 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import re
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
import shutil
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
import apex_utils
|
import apex_utils
|
||||||
@@ -32,6 +34,7 @@ class ApexUtilsTest(test_utils.ReleaseToolsTestCase):
|
|||||||
self.testdata_dir = test_utils.get_testdata_dir()
|
self.testdata_dir = test_utils.get_testdata_dir()
|
||||||
# The default payload signing key.
|
# The default payload signing key.
|
||||||
self.payload_key = os.path.join(self.testdata_dir, 'testkey.key')
|
self.payload_key = os.path.join(self.testdata_dir, 'testkey.key')
|
||||||
|
self.apex_with_apk = os.path.join(self.testdata_dir, 'has_apk.apex')
|
||||||
|
|
||||||
common.OPTIONS.search_path = test_utils.get_search_path()
|
common.OPTIONS.search_path = test_utils.get_search_path()
|
||||||
|
|
||||||
@@ -134,35 +137,43 @@ class ApexUtilsTest(test_utils.ReleaseToolsTestCase):
|
|||||||
def test_ApexApkSigner_noApkPresent(self):
|
def test_ApexApkSigner_noApkPresent(self):
|
||||||
apex_path = os.path.join(self.testdata_dir, 'foo.apex')
|
apex_path = os.path.join(self.testdata_dir, 'foo.apex')
|
||||||
signer = apex_utils.ApexApkSigner(apex_path, None, None)
|
signer = apex_utils.ApexApkSigner(apex_path, None, None)
|
||||||
processed_apex = signer.ProcessApexFile({}, self.payload_key,
|
processed_apex = signer.ProcessApexFile({}, self.payload_key)
|
||||||
None)
|
|
||||||
self.assertEqual(apex_path, processed_apex)
|
self.assertEqual(apex_path, processed_apex)
|
||||||
|
|
||||||
@test_utils.SkipIfExternalToolsUnavailable()
|
@test_utils.SkipIfExternalToolsUnavailable()
|
||||||
def test_ApexApkSigner_apkKeyNotPresent(self):
|
def test_ApexApkSigner_apkKeyNotPresent(self):
|
||||||
apex_path = os.path.join(self.testdata_dir, 'has_apk.apex')
|
apex_path = common.MakeTempFile(suffix='.apex')
|
||||||
|
shutil.copy(self.apex_with_apk, apex_path)
|
||||||
signer = apex_utils.ApexApkSigner(apex_path, None, None)
|
signer = apex_utils.ApexApkSigner(apex_path, None, None)
|
||||||
self.assertRaises(apex_utils.ApexSigningError, signer.ProcessApexFile, {},
|
self.assertRaises(apex_utils.ApexSigningError, signer.ProcessApexFile,
|
||||||
self.payload_key, None)
|
{}, self.payload_key)
|
||||||
|
|
||||||
@test_utils.SkipIfExternalToolsUnavailable()
|
@test_utils.SkipIfExternalToolsUnavailable()
|
||||||
def test_ApexApkSigner_signApk(self):
|
def test_ApexApkSigner_signApk(self):
|
||||||
apex_path = os.path.join(self.testdata_dir, 'has_apk.apex')
|
apex_path = common.MakeTempFile(suffix='.apex')
|
||||||
|
shutil.copy(self.apex_with_apk, apex_path)
|
||||||
signer = apex_utils.ApexApkSigner(apex_path, None, None)
|
signer = apex_utils.ApexApkSigner(apex_path, None, None)
|
||||||
apk_keys = {'wifi-service-resources.apk': os.path.join(
|
apk_keys = {'wifi-service-resources.apk': os.path.join(
|
||||||
self.testdata_dir, 'testkey')}
|
self.testdata_dir, 'testkey')}
|
||||||
|
|
||||||
self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
|
self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
|
||||||
payload_pubkey = common.ExtractAvbPublicKey('avbtool',
|
apex_file = signer.ProcessApexFile(apk_keys, self.payload_key)
|
||||||
self.payload_key)
|
package_name_extract_cmd = ['aapt', 'dump', 'badging', apex_file]
|
||||||
signer.ProcessApexFile(apk_keys, self.payload_key, payload_pubkey)
|
output = common.RunAndCheckOutput(package_name_extract_cmd)
|
||||||
|
for line in output.splitlines():
|
||||||
|
# Sample output from aapt: "package: name='com.google.android.wifi'
|
||||||
|
# versionCode='1' versionName='' platformBuildVersionName='R'
|
||||||
|
# compileSdkVersion='29' compileSdkVersionCodename='R'"
|
||||||
|
match = re.search(r"^package:.* name='([\w|\.]+)'", line, re.IGNORECASE)
|
||||||
|
if match:
|
||||||
|
package_name = match.group(1)
|
||||||
|
self.assertEquals('com.google.android.wifi', package_name)
|
||||||
|
|
||||||
@test_utils.SkipIfExternalToolsUnavailable()
|
@test_utils.SkipIfExternalToolsUnavailable()
|
||||||
def test_ApexApkSigner_noAssetDir(self):
|
def test_ApexApkSigner_noAssetDir(self):
|
||||||
apex_path = os.path.join(self.testdata_dir, 'has_apk.apex')
|
|
||||||
no_asset = common.MakeTempFile(suffix='.apex')
|
no_asset = common.MakeTempFile(suffix='.apex')
|
||||||
with zipfile.ZipFile(no_asset, 'w') as output_zip:
|
with zipfile.ZipFile(no_asset, 'w') as output_zip:
|
||||||
with zipfile.ZipFile(apex_path, 'r') as input_zip:
|
with zipfile.ZipFile(self.apex_with_apk, 'r') as input_zip:
|
||||||
name_list = input_zip.namelist()
|
name_list = input_zip.namelist()
|
||||||
for name in name_list:
|
for name in name_list:
|
||||||
if not name.startswith('assets'):
|
if not name.startswith('assets'):
|
||||||
@@ -173,23 +184,4 @@ class ApexUtilsTest(test_utils.ReleaseToolsTestCase):
|
|||||||
self.testdata_dir, 'testkey')}
|
self.testdata_dir, 'testkey')}
|
||||||
|
|
||||||
self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
|
self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
|
||||||
payload_pubkey = common.ExtractAvbPublicKey('avbtool',
|
signer.ProcessApexFile(apk_keys, self.payload_key)
|
||||||
self.payload_key)
|
|
||||||
signer.ProcessApexFile(apk_keys, self.payload_key, payload_pubkey)
|
|
||||||
|
|
||||||
@test_utils.SkipIfExternalToolsUnavailable()
|
|
||||||
def test_ApexApkSigner_withSignerHelper(self):
|
|
||||||
apex_path = os.path.join(self.testdata_dir, 'has_apk.apex')
|
|
||||||
signer = apex_utils.ApexApkSigner(apex_path, None, None)
|
|
||||||
apk_keys = {'wifi-service-resources.apk': os.path.join(
|
|
||||||
self.testdata_dir, 'testkey')}
|
|
||||||
|
|
||||||
self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key')
|
|
||||||
payload_pubkey = common.ExtractAvbPublicKey('avbtool', self.payload_key)
|
|
||||||
|
|
||||||
signing_helper = os.path.join(self.testdata_dir, 'signing_helper.sh')
|
|
||||||
os.chmod(signing_helper, 0o700)
|
|
||||||
payload_signer_args = '--signing_helper_with_files={}'.format(
|
|
||||||
signing_helper)
|
|
||||||
signer.ProcessApexFile(apk_keys, self.payload_key, payload_pubkey,
|
|
||||||
payload_signer_args)
|
|
||||||
|
Reference in New Issue
Block a user