• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
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
18import shutil
19
20import common
21import test_utils
22from merge_target_files import (
23    validate_config_lists, DEFAULT_FRAMEWORK_ITEM_LIST,
24    DEFAULT_VENDOR_ITEM_LIST, DEFAULT_FRAMEWORK_MISC_INFO_KEYS, copy_items,
25    item_list_to_partition_set, process_apex_keys_apk_certs_common,
26    compile_split_sepolicy, validate_merged_apex_info)
27
28
29class MergeTargetFilesTest(test_utils.ReleaseToolsTestCase):
30
31  def setUp(self):
32    self.testdata_dir = test_utils.get_testdata_dir()
33
34  def test_copy_items_CopiesItemsMatchingPatterns(self):
35
36    def createEmptyFile(path):
37      if not os.path.exists(os.path.dirname(path)):
38        os.makedirs(os.path.dirname(path))
39      open(path, 'a').close()
40      return path
41
42    def createSymLink(source, dest):
43      os.symlink(source, dest)
44      return dest
45
46    def getRelPaths(start, filepaths):
47      return set(
48          os.path.relpath(path=filepath, start=start) for filepath in filepaths)
49
50    input_dir = common.MakeTempDir()
51    output_dir = common.MakeTempDir()
52    expected_copied_items = []
53    actual_copied_items = []
54    patterns = ['*.cpp', 'subdir/*.txt']
55
56    # Create various files that we expect to get copied because they
57    # match one of the patterns.
58    expected_copied_items.extend([
59        createEmptyFile(os.path.join(input_dir, 'a.cpp')),
60        createEmptyFile(os.path.join(input_dir, 'b.cpp')),
61        createEmptyFile(os.path.join(input_dir, 'subdir', 'c.txt')),
62        createEmptyFile(os.path.join(input_dir, 'subdir', 'd.txt')),
63        createEmptyFile(
64            os.path.join(input_dir, 'subdir', 'subsubdir', 'e.txt')),
65        createSymLink('a.cpp', os.path.join(input_dir, 'a_link.cpp')),
66    ])
67    # Create some more files that we expect to not get copied.
68    createEmptyFile(os.path.join(input_dir, 'a.h'))
69    createEmptyFile(os.path.join(input_dir, 'b.h'))
70    createEmptyFile(os.path.join(input_dir, 'subdir', 'subsubdir', 'f.gif'))
71    createSymLink('a.h', os.path.join(input_dir, 'a_link.h'))
72
73    # Copy items.
74    copy_items(input_dir, output_dir, patterns)
75
76    # Assert the actual copied items match the ones we expected.
77    for dirpath, _, filenames in os.walk(output_dir):
78      actual_copied_items.extend(
79          os.path.join(dirpath, filename) for filename in filenames)
80    self.assertEqual(
81        getRelPaths(output_dir, actual_copied_items),
82        getRelPaths(input_dir, expected_copied_items))
83    self.assertEqual(
84        os.readlink(os.path.join(output_dir, 'a_link.cpp')), 'a.cpp')
85
86  def test_validate_config_lists_ReturnsFalseIfMissingDefaultItem(self):
87    framework_item_list = list(DEFAULT_FRAMEWORK_ITEM_LIST)
88    framework_item_list.remove('SYSTEM/*')
89    self.assertFalse(
90        validate_config_lists(framework_item_list,
91                              DEFAULT_FRAMEWORK_MISC_INFO_KEYS,
92                              DEFAULT_VENDOR_ITEM_LIST))
93
94  def test_validate_config_lists_ReturnsTrueIfDefaultItemInDifferentList(self):
95    framework_item_list = list(DEFAULT_FRAMEWORK_ITEM_LIST)
96    framework_item_list.remove('ROOT/*')
97    vendor_item_list = list(DEFAULT_VENDOR_ITEM_LIST)
98    vendor_item_list.append('ROOT/*')
99    self.assertTrue(
100        validate_config_lists(framework_item_list,
101                              DEFAULT_FRAMEWORK_MISC_INFO_KEYS,
102                              vendor_item_list))
103
104  def test_validate_config_lists_ReturnsTrueIfExtraItem(self):
105    framework_item_list = list(DEFAULT_FRAMEWORK_ITEM_LIST)
106    framework_item_list.append('MY_NEW_PARTITION/*')
107    self.assertTrue(
108        validate_config_lists(framework_item_list,
109                              DEFAULT_FRAMEWORK_MISC_INFO_KEYS,
110                              DEFAULT_VENDOR_ITEM_LIST))
111
112  def test_validate_config_lists_ReturnsFalseIfSharedExtractedPartition(self):
113    vendor_item_list = list(DEFAULT_VENDOR_ITEM_LIST)
114    vendor_item_list.append('SYSTEM/my_system_file')
115    self.assertFalse(
116        validate_config_lists(DEFAULT_FRAMEWORK_ITEM_LIST,
117                              DEFAULT_FRAMEWORK_MISC_INFO_KEYS,
118                              vendor_item_list))
119
120  def test_validate_config_lists_ReturnsFalseIfSharedExtractedPartitionImage(
121      self):
122    vendor_item_list = list(DEFAULT_VENDOR_ITEM_LIST)
123    vendor_item_list.append('IMAGES/system.img')
124    self.assertFalse(
125        validate_config_lists(DEFAULT_FRAMEWORK_ITEM_LIST,
126                              DEFAULT_FRAMEWORK_MISC_INFO_KEYS,
127                              vendor_item_list))
128
129  def test_validate_config_lists_ReturnsFalseIfBadSystemMiscInfoKeys(self):
130    for bad_key in ['dynamic_partition_list', 'super_partition_groups']:
131      framework_misc_info_keys = list(DEFAULT_FRAMEWORK_MISC_INFO_KEYS)
132      framework_misc_info_keys.append(bad_key)
133      self.assertFalse(
134          validate_config_lists(DEFAULT_FRAMEWORK_ITEM_LIST,
135                                framework_misc_info_keys,
136                                DEFAULT_VENDOR_ITEM_LIST))
137
138  def test_process_apex_keys_apk_certs_ReturnsTrueIfNoConflicts(self):
139    output_dir = common.MakeTempDir()
140    os.makedirs(os.path.join(output_dir, 'META'))
141
142    framework_dir = common.MakeTempDir()
143    os.makedirs(os.path.join(framework_dir, 'META'))
144    os.symlink(
145        os.path.join(self.testdata_dir, 'apexkeys_framework.txt'),
146        os.path.join(framework_dir, 'META', 'apexkeys.txt'))
147
148    vendor_dir = common.MakeTempDir()
149    os.makedirs(os.path.join(vendor_dir, 'META'))
150    os.symlink(
151        os.path.join(self.testdata_dir, 'apexkeys_vendor.txt'),
152        os.path.join(vendor_dir, 'META', 'apexkeys.txt'))
153
154    process_apex_keys_apk_certs_common(framework_dir, vendor_dir, output_dir,
155                                       set(['product', 'system', 'system_ext']),
156                                       set(['odm', 'vendor']), 'apexkeys.txt')
157
158    merged_entries = []
159    merged_path = os.path.join(self.testdata_dir, 'apexkeys_merge.txt')
160
161    with open(merged_path) as f:
162      merged_entries = f.read().split('\n')
163
164    output_entries = []
165    output_path = os.path.join(output_dir, 'META', 'apexkeys.txt')
166
167    with open(output_path) as f:
168      output_entries = f.read().split('\n')
169
170    return self.assertEqual(merged_entries, output_entries)
171
172  def test_process_apex_keys_apk_certs_ReturnsFalseIfConflictsPresent(self):
173    output_dir = common.MakeTempDir()
174    os.makedirs(os.path.join(output_dir, 'META'))
175
176    framework_dir = common.MakeTempDir()
177    os.makedirs(os.path.join(framework_dir, 'META'))
178    os.symlink(
179        os.path.join(self.testdata_dir, 'apexkeys_framework.txt'),
180        os.path.join(framework_dir, 'META', 'apexkeys.txt'))
181
182    conflict_dir = common.MakeTempDir()
183    os.makedirs(os.path.join(conflict_dir, 'META'))
184    os.symlink(
185        os.path.join(self.testdata_dir, 'apexkeys_framework_conflict.txt'),
186        os.path.join(conflict_dir, 'META', 'apexkeys.txt'))
187
188    self.assertRaises(ValueError, process_apex_keys_apk_certs_common,
189                      framework_dir, conflict_dir, output_dir,
190                      set(['product', 'system', 'system_ext']),
191                      set(['odm', 'vendor']), 'apexkeys.txt')
192
193  def test_process_apex_keys_apk_certs_HandlesApkCertsSyntax(self):
194    output_dir = common.MakeTempDir()
195    os.makedirs(os.path.join(output_dir, 'META'))
196
197    framework_dir = common.MakeTempDir()
198    os.makedirs(os.path.join(framework_dir, 'META'))
199    os.symlink(
200        os.path.join(self.testdata_dir, 'apkcerts_framework.txt'),
201        os.path.join(framework_dir, 'META', 'apkcerts.txt'))
202
203    vendor_dir = common.MakeTempDir()
204    os.makedirs(os.path.join(vendor_dir, 'META'))
205    os.symlink(
206        os.path.join(self.testdata_dir, 'apkcerts_vendor.txt'),
207        os.path.join(vendor_dir, 'META', 'apkcerts.txt'))
208
209    process_apex_keys_apk_certs_common(framework_dir, vendor_dir, output_dir,
210                                       set(['product', 'system', 'system_ext']),
211                                       set(['odm', 'vendor']), 'apkcerts.txt')
212
213    merged_entries = []
214    merged_path = os.path.join(self.testdata_dir, 'apkcerts_merge.txt')
215
216    with open(merged_path) as f:
217      merged_entries = f.read().split('\n')
218
219    output_entries = []
220    output_path = os.path.join(output_dir, 'META', 'apkcerts.txt')
221
222    with open(output_path) as f:
223      output_entries = f.read().split('\n')
224
225    return self.assertEqual(merged_entries, output_entries)
226
227  def test_item_list_to_partition_set(self):
228    item_list = [
229        'META/apexkeys.txt',
230        'META/apkcerts.txt',
231        'META/filesystem_config.txt',
232        'PRODUCT/*',
233        'SYSTEM/*',
234        'SYSTEM_EXT/*',
235    ]
236    partition_set = item_list_to_partition_set(item_list)
237    self.assertEqual(set(['product', 'system', 'system_ext']), partition_set)
238
239  def test_compile_split_sepolicy(self):
240    product_out_dir = common.MakeTempDir()
241
242    def write_temp_file(path, data=''):
243      full_path = os.path.join(product_out_dir, path)
244      if not os.path.exists(os.path.dirname(full_path)):
245        os.makedirs(os.path.dirname(full_path))
246      with open(full_path, 'w') as f:
247        f.write(data)
248
249    write_temp_file(
250        'system/etc/vintf/compatibility_matrix.device.xml', """
251      <compatibility-matrix>
252        <sepolicy>
253          <kernel-sepolicy-version>30</kernel-sepolicy-version>
254        </sepolicy>
255      </compatibility-matrix>""")
256    write_temp_file('vendor/etc/selinux/plat_sepolicy_vers.txt', '30.0')
257
258    write_temp_file('system/etc/selinux/plat_sepolicy.cil')
259    write_temp_file('system/etc/selinux/mapping/30.0.cil')
260    write_temp_file('product/etc/selinux/mapping/30.0.cil')
261    write_temp_file('vendor/etc/selinux/vendor_sepolicy.cil')
262    write_temp_file('vendor/etc/selinux/plat_pub_versioned.cil')
263
264    cmd = compile_split_sepolicy(product_out_dir, {
265        'system': 'system',
266        'product': 'product',
267        'vendor': 'vendor',
268    }, os.path.join(product_out_dir, 'policy'))
269    self.assertEqual(' '.join(cmd),
270                     ('secilc -m -M true -G -N -c 30 '
271                      '-o {OTP}/policy -f /dev/null '
272                      '{OTP}/system/etc/selinux/plat_sepolicy.cil '
273                      '{OTP}/system/etc/selinux/mapping/30.0.cil '
274                      '{OTP}/vendor/etc/selinux/vendor_sepolicy.cil '
275                      '{OTP}/vendor/etc/selinux/plat_pub_versioned.cil '
276                      '{OTP}/product/etc/selinux/mapping/30.0.cil').format(
277                          OTP=product_out_dir))
278
279  def _copy_apex(self, source, output_dir, partition):
280    shutil.copy(
281        source,
282        os.path.join(output_dir, partition, 'apex', os.path.basename(source)))
283
284  @test_utils.SkipIfExternalToolsUnavailable()
285  def test_validate_merged_apex_info(self):
286    output_dir = common.MakeTempDir()
287    os.makedirs(os.path.join(output_dir, 'SYSTEM/apex'))
288    os.makedirs(os.path.join(output_dir, 'VENDOR/apex'))
289
290    self._copy_apex(
291        os.path.join(self.testdata_dir, 'has_apk.apex'), output_dir, 'SYSTEM')
292    self._copy_apex(
293        os.path.join(test_utils.get_current_dir(),
294                     'com.android.apex.compressed.v1.capex'), output_dir,
295        'VENDOR')
296    validate_merged_apex_info(output_dir, ('system', 'vendor'))
297
298  @test_utils.SkipIfExternalToolsUnavailable()
299  def test_validate_merged_apex_info_RaisesOnPackageInMultiplePartitions(self):
300    output_dir = common.MakeTempDir()
301    os.makedirs(os.path.join(output_dir, 'SYSTEM/apex'))
302    os.makedirs(os.path.join(output_dir, 'VENDOR/apex'))
303
304    same_apex_package = os.path.join(self.testdata_dir, 'has_apk.apex')
305    self._copy_apex(same_apex_package, output_dir, 'SYSTEM')
306    self._copy_apex(same_apex_package, output_dir, 'VENDOR')
307    self.assertRaisesRegexp(
308        common.ExternalError,
309        'Duplicate APEX packages found in multiple partitions: com.android.wifi',
310        validate_merged_apex_info, output_dir, ('system', 'vendor'))
311