1#
2# Copyright (C) 2019 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 check_target_files_vintf import CheckVintf
23
24# A skeleton target files directory structure. This is VINTF compatible.
25SKELETON_TARGET_FILE_STRUCTURE = {
26    # Empty files
27    'PRODUCT/build.prop': '',
28    'PRODUCT/etc/build.prop': '',
29    'VENDOR/etc/build.prop': '',
30    'ODM/build.prop': '',
31    'ODM/etc/build.prop': '',
32    'RECOVERY/RAMDISK/etc/recovery.fstab': '',
33    'SYSTEM/build.prop': '',
34    'SYSTEM/etc/build.prop': '',
35    'SYSTEM_EXT/build.prop': '',
36    'SYSTEM_EXT/etc/build.prop': '',
37
38    # Non-empty files
39    'SYSTEM/etc/vintf/compatibility_matrix.1.xml':"""
40        <compatibility-matrix version="1.0" level="1" type="framework">
41            <sepolicy>
42                <sepolicy-version>0.0</sepolicy-version>
43                <kernel-sepolicy-version>0</kernel-sepolicy-version>
44            </sepolicy>
45        </compatibility-matrix>""",
46    'SYSTEM/manifest.xml':
47        '<manifest version="1.0" type="framework"/>',
48    'VENDOR/build.prop': 'ro.product.first_api_level=29\n',
49    'VENDOR/compatibility_matrix.xml':
50        '<compatibility-matrix version="1.0" type="device" />',
51    'VENDOR/etc/vintf/manifest.xml':
52        '<manifest version="1.0" target-level="1" type="device"/>',
53    'META/misc_info.txt':
54        'recovery_api_version=3\nfstab_version=2\nvintf_enforce=true\n',
55}
56
57
58def write_string_to_file(content, path, mode='w'):
59  if not os.path.isdir(os.path.dirname(path)):
60    os.makedirs(os.path.dirname(path))
61  with open(path, mode=mode) as f:
62    f.write(content)
63
64
65class CheckTargetFilesVintfTest(test_utils.ReleaseToolsTestCase):
66
67  def setUp(self):
68    self.testdata_dir = test_utils.get_testdata_dir()
69
70  def prepare_test_dir(self, test_delta_rel_path):
71    test_delta_dir = os.path.join(self.testdata_dir, test_delta_rel_path)
72    test_dir = common.MakeTempDir(prefix='check_target_files_vintf')
73
74    # Create a skeleton directory structure of target files
75    for rel_path, content in SKELETON_TARGET_FILE_STRUCTURE.items():
76      write_string_to_file(content, os.path.join(test_dir, rel_path))
77
78    # Overwrite with files from test_delta_rel_path
79    for root, _, files in os.walk(test_delta_dir):
80      rel_root = os.path.relpath(root, test_delta_dir)
81      for f in files:
82        if not f.endswith('.xml'):
83          continue
84        output_file = os.path.join(test_dir, rel_root, f)
85        with open(os.path.join(root, f)) as inp:
86          write_string_to_file(inp.read(), output_file)
87
88    return test_dir
89
90  # Prepare test dir with required HAL for APEX testing
91  def prepare_apex_test_dir(self, test_delta_rel_path):
92    test_dir = self.prepare_test_dir(test_delta_rel_path)
93    write_string_to_file(
94        """<compatibility-matrix version="1.0" level="1" type="framework">
95            <hal format="aidl" optional="false" updatable-via-apex="true">
96                <name>android.apex.foo</name>
97                <version>1</version>
98                <interface>
99                    <name>IApex</name>
100                    <instance>default</instance>
101                </interface>
102            </hal>
103            <sepolicy>
104                <sepolicy-version>0.0</sepolicy-version>
105                <kernel-sepolicy-version>0</kernel-sepolicy-version>
106            </sepolicy>
107        </compatibility-matrix>""",
108        os.path.join(test_dir, 'SYSTEM/etc/vintf/compatibility_matrix.1.xml'))
109
110    return test_dir
111
112  @test_utils.SkipIfExternalToolsUnavailable()
113  def test_CheckVintf_skeleton(self):
114    msg = 'vintf check with skeleton target files failed.'
115    test_dir = self.prepare_test_dir('does-not-exist')
116    self.assertTrue(CheckVintf(test_dir), msg=msg)
117
118  @test_utils.SkipIfExternalToolsUnavailable()
119  def test_CheckVintf_matrix_incompat(self):
120    msg = 'vintf/matrix_incompat should be incompatible because sepolicy ' \
121          'version fails to match'
122    test_dir = self.prepare_test_dir('vintf/matrix_incompat')
123    self.assertFalse(CheckVintf(test_dir), msg=msg)
124
125  @test_utils.SkipIfExternalToolsUnavailable()
126  def test_CheckVintf_kernel_compat(self):
127    msg = 'vintf/kernel with 4.14.1 kernel version should be compatible'
128    test_dir = self.prepare_test_dir('vintf/kernel')
129    write_string_to_file('', os.path.join(test_dir, 'META/kernel_configs.txt'))
130    write_string_to_file('4.14.1',
131                         os.path.join(test_dir, 'META/kernel_version.txt'))
132    self.assertTrue(CheckVintf(test_dir), msg=msg)
133
134  @test_utils.SkipIfExternalToolsUnavailable()
135  def test_CheckVintf_kernel_incompat(self):
136    msg = 'vintf/kernel with 4.14.0 kernel version should be incompatible ' \
137          'because 4.14.1 kernel version is required'
138    test_dir = self.prepare_test_dir('vintf/kernel')
139    write_string_to_file('', os.path.join(test_dir, 'META/kernel_configs.txt'))
140    write_string_to_file('4.14.0',
141                         os.path.join(test_dir, 'META/kernel_version.txt'))
142    self.assertFalse(CheckVintf(test_dir), msg=msg)
143
144  @test_utils.SkipIfExternalToolsUnavailable()
145  def test_CheckVintf_sku_compat(self):
146    msg = 'vintf/sku_compat should be compatible because ' \
147          'ODM/etc/vintf/manifest_sku.xml has the required HALs'
148    test_dir = self.prepare_test_dir('vintf/sku_compat')
149    write_string_to_file('vintf_odm_manifest_skus=sku',
150                         os.path.join(test_dir, 'META/misc_info.txt'), mode='a')
151    self.assertTrue(CheckVintf(test_dir), msg=msg)
152
153  @test_utils.SkipIfExternalToolsUnavailable()
154  def test_CheckVintf_sku_incompat(self):
155    msg = 'vintf/sku_compat should be compatible because ' \
156          'ODM/etc/vintf/manifest_sku.xml does not have the required HALs'
157    test_dir = self.prepare_test_dir('vintf/sku_incompat')
158    write_string_to_file('vintf_odm_manifest_skus=sku',
159                         os.path.join(test_dir, 'META/misc_info.txt'), mode='a')
160    self.assertFalse(CheckVintf(test_dir), msg=msg)
161
162  @test_utils.SkipIfExternalToolsUnavailable()
163  def test_CheckVintf_bad_xml(self):
164    test_dir = self.prepare_test_dir('does-not-exist')
165    write_string_to_file('not an XML',
166                         os.path.join(test_dir, 'VENDOR/etc/vintf/manifest.xml'))
167    # Should raise an error because a file has invalid format.
168    self.assertRaises(common.ExternalError, CheckVintf, test_dir)
169
170  @test_utils.SkipIfExternalToolsUnavailable()
171  def test_CheckVintf_apex_compat(self):
172    apex_file_name = 'com.android.apex.vendor.foo.with_vintf.apex'
173    msg = 'vintf/apex_compat should be compatible because ' \
174          'APEX %s has the required HALs' % (apex_file_name)
175    test_dir = self.prepare_apex_test_dir('vintf/apex_compat')
176    # Copy APEX under VENDOR/apex
177    apex_file = os.path.join(test_utils.get_current_dir(), apex_file_name)
178    apex_dir = os.path.join(test_dir, 'VENDOR/apex')
179    os.makedirs(apex_dir)
180    shutil.copy(apex_file, apex_dir)
181    # Should find required HAL via APEX
182    self.assertTrue(CheckVintf(test_dir), msg=msg)
183
184  @test_utils.SkipIfExternalToolsUnavailable()
185  def test_CheckVintf_apex_incompat(self):
186    msg = 'vintf/apex_incompat should be incompatible because ' \
187          'no APEX data'
188    test_dir = self.prepare_apex_test_dir('vintf/apex_incompat')
189    # Should not find required HAL
190    self.assertFalse(CheckVintf(test_dir), msg=msg)
191