blob: 088ebeea0c741dc6dbce1e26d55ab3510b538c6f [file] [log] [blame]
Daniel Norman6d82fa32019-03-22 17:53:04 -07001#
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
17import os.path
Daniel Normane9af70a2021-04-15 16:39:22 -070018import shutil
Daniel Norman6d82fa32019-03-22 17:53:04 -070019
Daniel Normanfdb38812019-04-15 09:47:24 -070020import common
Daniel Norman03747412022-02-25 10:38:37 -080021import merge_target_files
Daniel Norman6d82fa32019-03-22 17:53:04 -070022import test_utils
Daniel Norman48603ff2021-02-22 15:15:24 -080023from merge_target_files import (
24 validate_config_lists, DEFAULT_FRAMEWORK_ITEM_LIST,
25 DEFAULT_VENDOR_ITEM_LIST, DEFAULT_FRAMEWORK_MISC_INFO_KEYS, copy_items,
Daniel Norman03747412022-02-25 10:38:37 -080026 item_list_to_partition_set, merge_package_keys_txt, compile_split_sepolicy,
27 validate_merged_apex_info)
Daniel Norman6d82fa32019-03-22 17:53:04 -070028
29
30class MergeTargetFilesTest(test_utils.ReleaseToolsTestCase):
31
32 def setUp(self):
33 self.testdata_dir = test_utils.get_testdata_dir()
Daniel Norman03747412022-02-25 10:38:37 -080034 self.OPTIONS = merge_target_files.OPTIONS
35 self.OPTIONS.framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
36 self.OPTIONS.framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
37 self.OPTIONS.vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
38 self.OPTIONS.framework_partition_set = set(
39 ['product', 'system', 'system_ext'])
40 self.OPTIONS.vendor_partition_set = set(['odm', 'vendor'])
Daniel Norman6d82fa32019-03-22 17:53:04 -070041
Daniel Normanfdb38812019-04-15 09:47:24 -070042 def test_copy_items_CopiesItemsMatchingPatterns(self):
43
44 def createEmptyFile(path):
45 if not os.path.exists(os.path.dirname(path)):
46 os.makedirs(os.path.dirname(path))
47 open(path, 'a').close()
48 return path
49
50 def createSymLink(source, dest):
51 os.symlink(source, dest)
52 return dest
53
54 def getRelPaths(start, filepaths):
55 return set(
56 os.path.relpath(path=filepath, start=start) for filepath in filepaths)
57
58 input_dir = common.MakeTempDir()
59 output_dir = common.MakeTempDir()
60 expected_copied_items = []
61 actual_copied_items = []
62 patterns = ['*.cpp', 'subdir/*.txt']
63
64 # Create various files that we expect to get copied because they
65 # match one of the patterns.
66 expected_copied_items.extend([
67 createEmptyFile(os.path.join(input_dir, 'a.cpp')),
68 createEmptyFile(os.path.join(input_dir, 'b.cpp')),
69 createEmptyFile(os.path.join(input_dir, 'subdir', 'c.txt')),
70 createEmptyFile(os.path.join(input_dir, 'subdir', 'd.txt')),
71 createEmptyFile(
72 os.path.join(input_dir, 'subdir', 'subsubdir', 'e.txt')),
73 createSymLink('a.cpp', os.path.join(input_dir, 'a_link.cpp')),
74 ])
75 # Create some more files that we expect to not get copied.
76 createEmptyFile(os.path.join(input_dir, 'a.h'))
77 createEmptyFile(os.path.join(input_dir, 'b.h'))
78 createEmptyFile(os.path.join(input_dir, 'subdir', 'subsubdir', 'f.gif'))
79 createSymLink('a.h', os.path.join(input_dir, 'a_link.h'))
80
81 # Copy items.
82 copy_items(input_dir, output_dir, patterns)
83
84 # Assert the actual copied items match the ones we expected.
85 for dirpath, _, filenames in os.walk(output_dir):
86 actual_copied_items.extend(
87 os.path.join(dirpath, filename) for filename in filenames)
88 self.assertEqual(
89 getRelPaths(output_dir, actual_copied_items),
90 getRelPaths(input_dir, expected_copied_items))
91 self.assertEqual(
92 os.readlink(os.path.join(output_dir, 'a_link.cpp')), 'a.cpp')
93
Daniel Norman6d82fa32019-03-22 17:53:04 -070094 def test_validate_config_lists_ReturnsFalseIfMissingDefaultItem(self):
Daniel Norman03747412022-02-25 10:38:37 -080095 self.OPTIONS.framework_item_list = list(DEFAULT_FRAMEWORK_ITEM_LIST)
96 self.OPTIONS.framework_item_list.remove('SYSTEM/*')
97 self.assertFalse(validate_config_lists())
Daniel Norman6d82fa32019-03-22 17:53:04 -070098
99 def test_validate_config_lists_ReturnsTrueIfDefaultItemInDifferentList(self):
Daniel Norman03747412022-02-25 10:38:37 -0800100 self.OPTIONS.framework_item_list = list(DEFAULT_FRAMEWORK_ITEM_LIST)
101 self.OPTIONS.framework_item_list.remove('ROOT/*')
102 self.OPTIONS.vendor_item_list = list(DEFAULT_VENDOR_ITEM_LIST)
103 self.OPTIONS.vendor_item_list.append('ROOT/*')
104 self.assertTrue(validate_config_lists())
Daniel Norman6d82fa32019-03-22 17:53:04 -0700105
106 def test_validate_config_lists_ReturnsTrueIfExtraItem(self):
Daniel Norman03747412022-02-25 10:38:37 -0800107 self.OPTIONS.framework_item_list = list(DEFAULT_FRAMEWORK_ITEM_LIST)
108 self.OPTIONS.framework_item_list.append('MY_NEW_PARTITION/*')
109 self.assertTrue(validate_config_lists())
Daniel Normanedf12472019-05-22 10:47:08 -0700110
111 def test_validate_config_lists_ReturnsFalseIfSharedExtractedPartition(self):
Daniel Norman03747412022-02-25 10:38:37 -0800112 self.OPTIONS.vendor_item_list = list(DEFAULT_VENDOR_ITEM_LIST)
113 self.OPTIONS.vendor_item_list.append('SYSTEM/my_system_file')
114 self.assertFalse(validate_config_lists())
Daniel Norman6d82fa32019-03-22 17:53:04 -0700115
Daniel Normandbbf5a32020-10-22 16:03:32 -0700116 def test_validate_config_lists_ReturnsFalseIfSharedExtractedPartitionImage(
117 self):
Daniel Norman03747412022-02-25 10:38:37 -0800118 self.OPTIONS.vendor_item_list = list(DEFAULT_VENDOR_ITEM_LIST)
119 self.OPTIONS.vendor_item_list.append('IMAGES/system.img')
120 self.assertFalse(validate_config_lists())
Daniel Normandbbf5a32020-10-22 16:03:32 -0700121
Daniel Norman6d82fa32019-03-22 17:53:04 -0700122 def test_validate_config_lists_ReturnsFalseIfBadSystemMiscInfoKeys(self):
123 for bad_key in ['dynamic_partition_list', 'super_partition_groups']:
Daniel Norman03747412022-02-25 10:38:37 -0800124 self.OPTIONS.framework_misc_info_keys = list(
125 DEFAULT_FRAMEWORK_MISC_INFO_KEYS)
126 self.OPTIONS.framework_misc_info_keys.append(bad_key)
127 self.assertFalse(validate_config_lists())
Daniel Normana61cde02019-05-03 14:19:13 -0700128
Daniel Norman03747412022-02-25 10:38:37 -0800129 def test_merge_package_keys_txt_ReturnsTrueIfNoConflicts(self):
130 output_meta_dir = common.MakeTempDir()
Chris Grossfabf50a2019-05-02 12:42:09 -0700131
Daniel Norman03747412022-02-25 10:38:37 -0800132 framework_meta_dir = common.MakeTempDir()
Chris Grossfabf50a2019-05-02 12:42:09 -0700133 os.symlink(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700134 os.path.join(self.testdata_dir, 'apexkeys_framework.txt'),
Daniel Norman03747412022-02-25 10:38:37 -0800135 os.path.join(framework_meta_dir, 'apexkeys.txt'))
Chris Grossfabf50a2019-05-02 12:42:09 -0700136
Daniel Norman03747412022-02-25 10:38:37 -0800137 vendor_meta_dir = common.MakeTempDir()
Chris Grossfabf50a2019-05-02 12:42:09 -0700138 os.symlink(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700139 os.path.join(self.testdata_dir, 'apexkeys_vendor.txt'),
Daniel Norman03747412022-02-25 10:38:37 -0800140 os.path.join(vendor_meta_dir, 'apexkeys.txt'))
Chris Grossfabf50a2019-05-02 12:42:09 -0700141
Daniel Norman03747412022-02-25 10:38:37 -0800142 merge_package_keys_txt(framework_meta_dir, vendor_meta_dir, output_meta_dir,
143 'apexkeys.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700144
145 merged_entries = []
146 merged_path = os.path.join(self.testdata_dir, 'apexkeys_merge.txt')
147
148 with open(merged_path) as f:
149 merged_entries = f.read().split('\n')
150
151 output_entries = []
Daniel Norman03747412022-02-25 10:38:37 -0800152 output_path = os.path.join(output_meta_dir, 'apexkeys.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700153
154 with open(output_path) as f:
155 output_entries = f.read().split('\n')
156
157 return self.assertEqual(merged_entries, output_entries)
158
159 def test_process_apex_keys_apk_certs_ReturnsFalseIfConflictsPresent(self):
Daniel Norman03747412022-02-25 10:38:37 -0800160 output_meta_dir = common.MakeTempDir()
Chris Grossfabf50a2019-05-02 12:42:09 -0700161
Daniel Norman03747412022-02-25 10:38:37 -0800162 framework_meta_dir = common.MakeTempDir()
Chris Grossfabf50a2019-05-02 12:42:09 -0700163 os.symlink(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700164 os.path.join(self.testdata_dir, 'apexkeys_framework.txt'),
Daniel Norman03747412022-02-25 10:38:37 -0800165 os.path.join(framework_meta_dir, 'apexkeys.txt'))
Chris Grossfabf50a2019-05-02 12:42:09 -0700166
Daniel Norman03747412022-02-25 10:38:37 -0800167 conflict_meta_dir = common.MakeTempDir()
Chris Grossfabf50a2019-05-02 12:42:09 -0700168 os.symlink(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700169 os.path.join(self.testdata_dir, 'apexkeys_framework_conflict.txt'),
Daniel Norman03747412022-02-25 10:38:37 -0800170 os.path.join(conflict_meta_dir, 'apexkeys.txt'))
Chris Grossfabf50a2019-05-02 12:42:09 -0700171
Daniel Norman03747412022-02-25 10:38:37 -0800172 self.assertRaises(ValueError, merge_package_keys_txt, framework_meta_dir,
173 conflict_meta_dir, output_meta_dir, 'apexkeys.txt')
Bill Peckham19c3feb2020-03-20 18:31:43 -0700174
175 def test_process_apex_keys_apk_certs_HandlesApkCertsSyntax(self):
Daniel Norman03747412022-02-25 10:38:37 -0800176 output_meta_dir = common.MakeTempDir()
Bill Peckham19c3feb2020-03-20 18:31:43 -0700177
Daniel Norman03747412022-02-25 10:38:37 -0800178 framework_meta_dir = common.MakeTempDir()
Bill Peckham19c3feb2020-03-20 18:31:43 -0700179 os.symlink(
180 os.path.join(self.testdata_dir, 'apkcerts_framework.txt'),
Daniel Norman03747412022-02-25 10:38:37 -0800181 os.path.join(framework_meta_dir, 'apkcerts.txt'))
Bill Peckham19c3feb2020-03-20 18:31:43 -0700182
Daniel Norman03747412022-02-25 10:38:37 -0800183 vendor_meta_dir = common.MakeTempDir()
Bill Peckham19c3feb2020-03-20 18:31:43 -0700184 os.symlink(
185 os.path.join(self.testdata_dir, 'apkcerts_vendor.txt'),
Daniel Norman03747412022-02-25 10:38:37 -0800186 os.path.join(vendor_meta_dir, 'apkcerts.txt'))
Bill Peckham19c3feb2020-03-20 18:31:43 -0700187
Daniel Norman03747412022-02-25 10:38:37 -0800188 merge_package_keys_txt(framework_meta_dir, vendor_meta_dir, output_meta_dir,
189 'apkcerts.txt')
Bill Peckham19c3feb2020-03-20 18:31:43 -0700190
191 merged_entries = []
192 merged_path = os.path.join(self.testdata_dir, 'apkcerts_merge.txt')
193
194 with open(merged_path) as f:
195 merged_entries = f.read().split('\n')
196
197 output_entries = []
Daniel Norman03747412022-02-25 10:38:37 -0800198 output_path = os.path.join(output_meta_dir, 'apkcerts.txt')
Bill Peckham19c3feb2020-03-20 18:31:43 -0700199
200 with open(output_path) as f:
201 output_entries = f.read().split('\n')
202
203 return self.assertEqual(merged_entries, output_entries)
204
205 def test_item_list_to_partition_set(self):
206 item_list = [
207 'META/apexkeys.txt',
208 'META/apkcerts.txt',
209 'META/filesystem_config.txt',
210 'PRODUCT/*',
211 'SYSTEM/*',
212 'SYSTEM_EXT/*',
213 ]
214 partition_set = item_list_to_partition_set(item_list)
215 self.assertEqual(set(['product', 'system', 'system_ext']), partition_set)
Daniel Norman48603ff2021-02-22 15:15:24 -0800216
217 def test_compile_split_sepolicy(self):
218 product_out_dir = common.MakeTempDir()
219
220 def write_temp_file(path, data=''):
221 full_path = os.path.join(product_out_dir, path)
222 if not os.path.exists(os.path.dirname(full_path)):
223 os.makedirs(os.path.dirname(full_path))
224 with open(full_path, 'w') as f:
225 f.write(data)
226
227 write_temp_file(
228 'system/etc/vintf/compatibility_matrix.device.xml', """
229 <compatibility-matrix>
230 <sepolicy>
231 <kernel-sepolicy-version>30</kernel-sepolicy-version>
232 </sepolicy>
233 </compatibility-matrix>""")
234 write_temp_file('vendor/etc/selinux/plat_sepolicy_vers.txt', '30.0')
235
236 write_temp_file('system/etc/selinux/plat_sepolicy.cil')
237 write_temp_file('system/etc/selinux/mapping/30.0.cil')
238 write_temp_file('product/etc/selinux/mapping/30.0.cil')
239 write_temp_file('vendor/etc/selinux/vendor_sepolicy.cil')
240 write_temp_file('vendor/etc/selinux/plat_pub_versioned.cil')
241
242 cmd = compile_split_sepolicy(product_out_dir, {
243 'system': 'system',
244 'product': 'product',
245 'vendor': 'vendor',
Daniel Norman571e1822021-06-25 17:18:25 -0700246 })
Daniel Norman48603ff2021-02-22 15:15:24 -0800247 self.assertEqual(' '.join(cmd),
248 ('secilc -m -M true -G -N -c 30 '
Daniel Norman571e1822021-06-25 17:18:25 -0700249 '-o {OTP}/META/combined_sepolicy -f /dev/null '
Daniel Norman48603ff2021-02-22 15:15:24 -0800250 '{OTP}/system/etc/selinux/plat_sepolicy.cil '
251 '{OTP}/system/etc/selinux/mapping/30.0.cil '
252 '{OTP}/vendor/etc/selinux/vendor_sepolicy.cil '
253 '{OTP}/vendor/etc/selinux/plat_pub_versioned.cil '
254 '{OTP}/product/etc/selinux/mapping/30.0.cil').format(
255 OTP=product_out_dir))
Daniel Normane9af70a2021-04-15 16:39:22 -0700256
257 def _copy_apex(self, source, output_dir, partition):
258 shutil.copy(
259 source,
260 os.path.join(output_dir, partition, 'apex', os.path.basename(source)))
261
262 @test_utils.SkipIfExternalToolsUnavailable()
263 def test_validate_merged_apex_info(self):
264 output_dir = common.MakeTempDir()
265 os.makedirs(os.path.join(output_dir, 'SYSTEM/apex'))
266 os.makedirs(os.path.join(output_dir, 'VENDOR/apex'))
267
268 self._copy_apex(
269 os.path.join(self.testdata_dir, 'has_apk.apex'), output_dir, 'SYSTEM')
270 self._copy_apex(
271 os.path.join(test_utils.get_current_dir(),
272 'com.android.apex.compressed.v1.capex'), output_dir,
273 'VENDOR')
274 validate_merged_apex_info(output_dir, ('system', 'vendor'))
275
276 @test_utils.SkipIfExternalToolsUnavailable()
277 def test_validate_merged_apex_info_RaisesOnPackageInMultiplePartitions(self):
278 output_dir = common.MakeTempDir()
279 os.makedirs(os.path.join(output_dir, 'SYSTEM/apex'))
280 os.makedirs(os.path.join(output_dir, 'VENDOR/apex'))
281
282 same_apex_package = os.path.join(self.testdata_dir, 'has_apk.apex')
283 self._copy_apex(same_apex_package, output_dir, 'SYSTEM')
284 self._copy_apex(same_apex_package, output_dir, 'VENDOR')
285 self.assertRaisesRegexp(
286 common.ExternalError,
287 'Duplicate APEX packages found in multiple partitions: com.android.wifi',
288 validate_merged_apex_info, output_dir, ('system', 'vendor'))