blob: 9d214296c375c573b4d0bb5d90d3fd5f9883a65e [file] [log] [blame]
Tao Baoa7054ee2017-12-08 14:42:16 -08001#
2# Copyright (C) 2017 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
Tao Bao66472632017-12-04 17:16:36 -080017import base64
Tao Baode1d4792018-02-20 10:05:46 -080018import os.path
Tao Baoe838d142017-12-23 23:44:48 -080019import zipfile
Tao Baoa7054ee2017-12-08 14:42:16 -080020
Tao Baoe838d142017-12-23 23:44:48 -080021import common
Tao Baode1d4792018-02-20 10:05:46 -080022import test_utils
Tao Bao66472632017-12-04 17:16:36 -080023from sign_target_files_apks import (
Tao Baoaa7e9932019-03-15 09:37:01 -070024 CheckApkAndApexKeysAvailable, EditTags, GetApkFileInfo, ReadApexKeysInfo,
25 ReplaceCerts, ReplaceVerityKeyId, RewriteProps)
Tao Baoa7054ee2017-12-08 14:42:16 -080026
27
Tao Bao65b94e92018-10-11 21:57:26 -070028class SignTargetFilesApksTest(test_utils.ReleaseToolsTestCase):
Tao Baoa7054ee2017-12-08 14:42:16 -080029
Tao Bao66472632017-12-04 17:16:36 -080030 MAC_PERMISSIONS_XML = """<?xml version="1.0" encoding="iso-8859-1"?>
31<policy>
32 <signer signature="{}"><seinfo value="platform"/></signer>
33 <signer signature="{}"><seinfo value="media"/></signer>
34</policy>"""
35
Tao Baoaa7e9932019-03-15 09:37:01 -070036 APEX_KEYS_TXT = """name="apex.apexd_test.apex" public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package.avbpubkey" private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem" container_certificate="build/target/product/security/testkey.x509.pem" container_private_key="build/target/product/security/testkey.pk8"
37name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem" container_certificate="build/target/product/security/testkey.x509.pem" container_private_key="build/target/product/security/testkey.pk8"
38"""
39
Tao Baoe838d142017-12-23 23:44:48 -080040 def setUp(self):
Tao Baode1d4792018-02-20 10:05:46 -080041 self.testdata_dir = test_utils.get_testdata_dir()
Tao Baoe838d142017-12-23 23:44:48 -080042
Tao Baoa7054ee2017-12-08 14:42:16 -080043 def test_EditTags(self):
44 self.assertEqual(EditTags('dev-keys'), ('release-keys'))
45 self.assertEqual(EditTags('test-keys'), ('release-keys'))
46
47 # Multiple tags.
48 self.assertEqual(EditTags('abc,dev-keys,xyz'), ('abc,release-keys,xyz'))
49
50 # Tags are sorted.
51 self.assertEqual(EditTags('xyz,abc,dev-keys,xyz'), ('abc,release-keys,xyz'))
52
53 def test_RewriteProps(self):
54 props = (
55 ('', '\n'),
56 ('ro.build.fingerprint=foo/bar/dev-keys',
57 'ro.build.fingerprint=foo/bar/release-keys\n'),
58 ('ro.build.thumbprint=foo/bar/dev-keys',
59 'ro.build.thumbprint=foo/bar/release-keys\n'),
60 ('ro.vendor.build.fingerprint=foo/bar/dev-keys',
61 'ro.vendor.build.fingerprint=foo/bar/release-keys\n'),
62 ('ro.vendor.build.thumbprint=foo/bar/dev-keys',
63 'ro.vendor.build.thumbprint=foo/bar/release-keys\n'),
64 ('# comment line 1', '# comment line 1\n'),
65 ('ro.bootimage.build.fingerprint=foo/bar/dev-keys',
66 'ro.bootimage.build.fingerprint=foo/bar/release-keys\n'),
67 ('ro.build.description='
68 'sailfish-user 8.0.0 OPR6.170623.012 4283428 dev-keys',
69 'ro.build.description='
70 'sailfish-user 8.0.0 OPR6.170623.012 4283428 release-keys\n'),
71 ('ro.build.tags=dev-keys', 'ro.build.tags=release-keys\n'),
72 ('# comment line 2', '# comment line 2\n'),
73 ('ro.build.display.id=OPR6.170623.012 dev-keys',
74 'ro.build.display.id=OPR6.170623.012\n'),
75 ('# comment line 3', '# comment line 3\n'),
76 )
77
78 # Assert the case for each individual line.
Tao Baoe838d142017-12-23 23:44:48 -080079 for prop, output in props:
80 self.assertEqual(RewriteProps(prop), output)
Tao Baoa7054ee2017-12-08 14:42:16 -080081
82 # Concatenate all the input lines.
83 self.assertEqual(RewriteProps('\n'.join([prop[0] for prop in props])),
84 ''.join([prop[1] for prop in props]))
Tao Baoe838d142017-12-23 23:44:48 -080085
86 def test_ReplaceVerityKeyId(self):
87 BOOT_CMDLINE1 = (
88 "console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 "
89 "androidboot.hardware=marlin user_debug=31 ehci-hcd.park=3 "
90 "lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 "
91 "buildvariant=userdebug "
92 "veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f\n")
93
94 BOOT_CMDLINE2 = (
95 "console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 "
96 "androidboot.hardware=marlin user_debug=31 ehci-hcd.park=3 "
97 "lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 "
98 "buildvariant=userdebug "
Tao Baode1d4792018-02-20 10:05:46 -080099 "veritykeyid=id:d24f2590e9abab5cff5f59da4c4f0366e3f43e94\n")
Tao Baoe838d142017-12-23 23:44:48 -0800100
Tao Baode1d4792018-02-20 10:05:46 -0800101 input_file = common.MakeTempFile(suffix='.zip')
102 with zipfile.ZipFile(input_file, 'w') as input_zip:
Tao Baoe838d142017-12-23 23:44:48 -0800103 input_zip.writestr('BOOT/cmdline', BOOT_CMDLINE1)
104
105 # Test with the first certificate.
Tao Baode1d4792018-02-20 10:05:46 -0800106 cert_file = os.path.join(self.testdata_dir, 'verity.x509.pem')
Tao Baoe838d142017-12-23 23:44:48 -0800107
Tao Baode1d4792018-02-20 10:05:46 -0800108 output_file = common.MakeTempFile(suffix='.zip')
109 with zipfile.ZipFile(input_file, 'r') as input_zip, \
110 zipfile.ZipFile(output_file, 'w') as output_zip:
111 ReplaceVerityKeyId(input_zip, output_zip, cert_file)
Tao Baoe838d142017-12-23 23:44:48 -0800112
Tao Baode1d4792018-02-20 10:05:46 -0800113 with zipfile.ZipFile(output_file) as output_zip:
Tao Baoe838d142017-12-23 23:44:48 -0800114 self.assertEqual(BOOT_CMDLINE1, output_zip.read('BOOT/cmdline'))
115
116 # Test with the second certificate.
Tao Baode1d4792018-02-20 10:05:46 -0800117 cert_file = os.path.join(self.testdata_dir, 'testkey.x509.pem')
Tao Baoe838d142017-12-23 23:44:48 -0800118
Tao Baode1d4792018-02-20 10:05:46 -0800119 with zipfile.ZipFile(input_file, 'r') as input_zip, \
120 zipfile.ZipFile(output_file, 'w') as output_zip:
121 ReplaceVerityKeyId(input_zip, output_zip, cert_file)
Tao Baoe838d142017-12-23 23:44:48 -0800122
Tao Baode1d4792018-02-20 10:05:46 -0800123 with zipfile.ZipFile(output_file) as output_zip:
Tao Baoe838d142017-12-23 23:44:48 -0800124 self.assertEqual(BOOT_CMDLINE2, output_zip.read('BOOT/cmdline'))
125
126 def test_ReplaceVerityKeyId_no_veritykeyid(self):
127 BOOT_CMDLINE = (
128 "console=ttyHSL0,115200,n8 androidboot.hardware=bullhead boot_cpus=0-5 "
129 "lpm_levels.sleep_disabled=1 msm_poweroff.download_mode=0 "
130 "loop.max_part=7\n")
131
Tao Baode1d4792018-02-20 10:05:46 -0800132 input_file = common.MakeTempFile(suffix='.zip')
133 with zipfile.ZipFile(input_file, 'w') as input_zip:
Tao Baoe838d142017-12-23 23:44:48 -0800134 input_zip.writestr('BOOT/cmdline', BOOT_CMDLINE)
135
Tao Baode1d4792018-02-20 10:05:46 -0800136 output_file = common.MakeTempFile(suffix='.zip')
137 with zipfile.ZipFile(input_file, 'r') as input_zip, \
138 zipfile.ZipFile(output_file, 'w') as output_zip:
Tao Baoe838d142017-12-23 23:44:48 -0800139 ReplaceVerityKeyId(input_zip, output_zip, None)
140
Tao Baode1d4792018-02-20 10:05:46 -0800141 with zipfile.ZipFile(output_file) as output_zip:
Tao Baoe838d142017-12-23 23:44:48 -0800142 self.assertEqual(BOOT_CMDLINE, output_zip.read('BOOT/cmdline'))
Tao Bao66472632017-12-04 17:16:36 -0800143
144 def test_ReplaceCerts(self):
145 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
146 with open(cert1_path) as cert1_fp:
147 cert1 = cert1_fp.read()
148 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
149 with open(cert2_path) as cert2_fp:
150 cert2 = cert2_fp.read()
151 cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem')
152 with open(cert3_path) as cert3_fp:
153 cert3 = cert3_fp.read()
154
155 # Replace cert1 with cert3.
156 input_xml = self.MAC_PERMISSIONS_XML.format(
157 base64.b16encode(common.ParseCertificate(cert1)).lower(),
158 base64.b16encode(common.ParseCertificate(cert2)).lower())
159
160 output_xml = self.MAC_PERMISSIONS_XML.format(
161 base64.b16encode(common.ParseCertificate(cert3)).lower(),
162 base64.b16encode(common.ParseCertificate(cert2)).lower())
163
164 common.OPTIONS.key_map = {
165 cert1_path[:-9] : cert3_path[:-9],
166 }
167
168 self.assertEqual(output_xml, ReplaceCerts(input_xml))
169
170 def test_ReplaceCerts_duplicateEntries(self):
171 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
172 with open(cert1_path) as cert1_fp:
173 cert1 = cert1_fp.read()
174 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
175 with open(cert2_path) as cert2_fp:
176 cert2 = cert2_fp.read()
177
178 # Replace cert1 with cert2, which leads to duplicate entries.
179 input_xml = self.MAC_PERMISSIONS_XML.format(
180 base64.b16encode(common.ParseCertificate(cert1)).lower(),
181 base64.b16encode(common.ParseCertificate(cert2)).lower())
182
183 common.OPTIONS.key_map = {
184 cert1_path[:-9] : cert2_path[:-9],
185 }
186 self.assertRaises(AssertionError, ReplaceCerts, input_xml)
187
188 def test_ReplaceCerts_skipNonExistentCerts(self):
189 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
190 with open(cert1_path) as cert1_fp:
191 cert1 = cert1_fp.read()
192 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
193 with open(cert2_path) as cert2_fp:
194 cert2 = cert2_fp.read()
195 cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem')
196 with open(cert3_path) as cert3_fp:
197 cert3 = cert3_fp.read()
198
199 input_xml = self.MAC_PERMISSIONS_XML.format(
200 base64.b16encode(common.ParseCertificate(cert1)).lower(),
201 base64.b16encode(common.ParseCertificate(cert2)).lower())
202
203 output_xml = self.MAC_PERMISSIONS_XML.format(
204 base64.b16encode(common.ParseCertificate(cert3)).lower(),
205 base64.b16encode(common.ParseCertificate(cert2)).lower())
206
207 common.OPTIONS.key_map = {
208 cert1_path[:-9] : cert3_path[:-9],
209 'non-existent' : cert3_path[:-9],
210 cert2_path[:-9] : 'non-existent',
211 }
212 self.assertEqual(output_xml, ReplaceCerts(input_xml))
Tao Bao11f955c2018-06-19 12:19:35 -0700213
Tao Baoaa7e9932019-03-15 09:37:01 -0700214 def test_CheckApkAndApexKeysAvailable(self):
Tao Bao11f955c2018-06-19 12:19:35 -0700215 input_file = common.MakeTempFile(suffix='.zip')
216 with zipfile.ZipFile(input_file, 'w') as input_zip:
217 input_zip.writestr('SYSTEM/app/App1.apk', "App1-content")
218 input_zip.writestr('SYSTEM/app/App2.apk.gz', "App2-content")
219
220 apk_key_map = {
221 'App1.apk' : 'key1',
222 'App2.apk' : 'key2',
223 'App3.apk' : 'key3',
224 }
225 with zipfile.ZipFile(input_file) as input_zip:
Tao Baoaa7e9932019-03-15 09:37:01 -0700226 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None)
227 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, '.gz')
Tao Bao11f955c2018-06-19 12:19:35 -0700228
229 # 'App2.apk.gz' won't be considered as an APK.
Tao Baoaa7e9932019-03-15 09:37:01 -0700230 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None)
231 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, '.xz')
Tao Bao11f955c2018-06-19 12:19:35 -0700232
233 del apk_key_map['App2.apk']
234 self.assertRaises(
Tao Baoaa7e9932019-03-15 09:37:01 -0700235 AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map,
236 '.gz')
Tao Bao11f955c2018-06-19 12:19:35 -0700237
238 def test_GetApkFileInfo(self):
Tao Bao93c2a012018-06-19 12:19:35 -0700239 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
240 "PRODUCT/apps/Chats.apk", None, [])
Tao Bao11f955c2018-06-19 12:19:35 -0700241 self.assertTrue(is_apk)
242 self.assertFalse(is_compressed)
Tao Bao93c2a012018-06-19 12:19:35 -0700243 self.assertFalse(should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700244
Tao Bao93c2a012018-06-19 12:19:35 -0700245 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
246 "PRODUCT/apps/Chats.apk", None, [])
247 self.assertTrue(is_apk)
248 self.assertFalse(is_compressed)
249 self.assertFalse(should_be_skipped)
250
251 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
252 "PRODUCT/apps/Chats.dat", None, [])
Tao Bao11f955c2018-06-19 12:19:35 -0700253 self.assertFalse(is_apk)
254 self.assertFalse(is_compressed)
Tao Bao93c2a012018-06-19 12:19:35 -0700255 self.assertFalse(should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700256
257 def test_GetApkFileInfo_withCompressedApks(self):
Tao Bao93c2a012018-06-19 12:19:35 -0700258 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
259 "PRODUCT/apps/Chats.apk.gz", ".gz", [])
Tao Bao11f955c2018-06-19 12:19:35 -0700260 self.assertTrue(is_apk)
261 self.assertTrue(is_compressed)
Tao Bao93c2a012018-06-19 12:19:35 -0700262 self.assertFalse(should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700263
Tao Bao93c2a012018-06-19 12:19:35 -0700264 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
265 "PRODUCT/apps/Chats.apk.gz", ".xz", [])
Tao Bao11f955c2018-06-19 12:19:35 -0700266 self.assertFalse(is_apk)
267 self.assertFalse(is_compressed)
Tao Bao93c2a012018-06-19 12:19:35 -0700268 self.assertFalse(should_be_skipped)
Tao Bao11f955c2018-06-19 12:19:35 -0700269
270 self.assertRaises(
Tao Bao93c2a012018-06-19 12:19:35 -0700271 AssertionError, GetApkFileInfo, "PRODUCT/apps/Chats.apk", "", [])
Tao Bao11f955c2018-06-19 12:19:35 -0700272
273 self.assertRaises(
Tao Bao93c2a012018-06-19 12:19:35 -0700274 AssertionError, GetApkFileInfo, "PRODUCT/apps/Chats.apk", "apk", [])
275
276 def test_GetApkFileInfo_withSkippedPrefixes(self):
277 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
278 "PRODUCT/preloads/apps/Chats.apk", None, set())
279 self.assertTrue(is_apk)
280 self.assertFalse(is_compressed)
281 self.assertFalse(should_be_skipped)
282
283 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
284 "PRODUCT/preloads/apps/Chats.apk",
285 None,
286 set(["PRODUCT/preloads/"]))
287 self.assertTrue(is_apk)
288 self.assertFalse(is_compressed)
289 self.assertTrue(should_be_skipped)
290
291 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
292 "SYSTEM_OTHER/preloads/apps/Chats.apk",
293 None,
294 set(["SYSTEM/preloads/", "SYSTEM_OTHER/preloads/"]))
295 self.assertTrue(is_apk)
296 self.assertFalse(is_compressed)
297 self.assertTrue(should_be_skipped)
298
299 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
300 "SYSTEM_OTHER/preloads/apps/Chats.apk.gz",
301 ".gz",
302 set(["PRODUCT/prebuilts/", "SYSTEM_OTHER/preloads/"]))
303 self.assertTrue(is_apk)
304 self.assertTrue(is_compressed)
305 self.assertTrue(should_be_skipped)
306
307 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
308 "SYSTEM_OTHER/preloads/apps/Chats.dat",
309 None,
310 set(["SYSTEM_OTHER/preloads/"]))
311 self.assertFalse(is_apk)
312 self.assertFalse(is_compressed)
313 self.assertFalse(should_be_skipped)
314
315 def test_GetApkFileInfo_checkSkippedPrefixesInput(self):
316 # set
317 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
318 "SYSTEM_OTHER/preloads/apps/Chats.apk",
319 None,
320 set(["SYSTEM_OTHER/preloads/"]))
321 self.assertTrue(is_apk)
322 self.assertFalse(is_compressed)
323 self.assertTrue(should_be_skipped)
324
325 # tuple
326 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
327 "SYSTEM_OTHER/preloads/apps/Chats.apk",
328 None,
329 ("SYSTEM_OTHER/preloads/",))
330 self.assertTrue(is_apk)
331 self.assertFalse(is_compressed)
332 self.assertTrue(should_be_skipped)
333
334 # list
335 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
336 "SYSTEM_OTHER/preloads/apps/Chats.apk",
337 None,
338 ["SYSTEM_OTHER/preloads/"])
339 self.assertTrue(is_apk)
340 self.assertFalse(is_compressed)
341 self.assertTrue(should_be_skipped)
342
343 # str is invalid.
344 self.assertRaises(
345 AssertionError, GetApkFileInfo, "SYSTEM_OTHER/preloads/apps/Chats.apk",
346 None, "SYSTEM_OTHER/preloads/")
347
348 # None is invalid.
349 self.assertRaises(
350 AssertionError, GetApkFileInfo, "SYSTEM_OTHER/preloads/apps/Chats.apk",
351 None, None)
Tao Baoaa7e9932019-03-15 09:37:01 -0700352
353 def test_ReadApexKeysInfo(self):
354 target_files = common.MakeTempFile(suffix='.zip')
355 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
356 target_files_zip.writestr('META/apexkeys.txt', self.APEX_KEYS_TXT)
357
358 with zipfile.ZipFile(target_files) as target_files_zip:
359 keys_info = ReadApexKeysInfo(target_files_zip)
360
361 self.assertEqual(
362 {
363 'apex.apexd_test.apex': (
364 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
365 'build/target/product/security/testkey'),
366 'apex.apexd_test_different_app.apex': (
367 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
368 'build/target/product/security/testkey'),
369 },
370 keys_info)
371
372 def test_ReadApexKeysInfo_mismatchingKeys(self):
373 # Mismatching payload public / private keys.
374 apex_keys = self.APEX_KEYS_TXT + (
375 'name="apex.apexd_test_different_app2.apex" '
376 'public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" '
377 'private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_3.pem" '
378 'container_certificate="build/target/product/security/testkey.x509.pem" '
379 'container_private_key="build/target/product/security/testkey.pk8"')
380 target_files = common.MakeTempFile(suffix='.zip')
381 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
382 target_files_zip.writestr('META/apexkeys.txt', apex_keys)
383
384 with zipfile.ZipFile(target_files) as target_files_zip:
385 self.assertRaises(ValueError, ReadApexKeysInfo, target_files_zip)
386
387 def test_ReadApexKeysInfo_missingPrivateKey(self):
388 # Invalid lines will be skipped.
389 apex_keys = self.APEX_KEYS_TXT + (
390 'name="apex.apexd_test_different_app2.apex" '
391 'public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" '
392 'container_certificate="build/target/product/security/testkey.x509.pem" '
393 'container_private_key="build/target/product/security/testkey.pk8"')
394 target_files = common.MakeTempFile(suffix='.zip')
395 with zipfile.ZipFile(target_files, 'w') as target_files_zip:
396 target_files_zip.writestr('META/apexkeys.txt', apex_keys)
397
398 with zipfile.ZipFile(target_files) as target_files_zip:
399 keys_info = ReadApexKeysInfo(target_files_zip)
400
401 self.assertEqual(
402 {
403 'apex.apexd_test.apex': (
404 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
405 'build/target/product/security/testkey'),
406 'apex.apexd_test_different_app.apex': (
407 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
408 'build/target/product/security/testkey'),
409 },
410 keys_info)