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 json
18import logging
19
20from vts.runners.host import const
21from vts.runners.host import errors
22from vts.runners.host import keys
23from vts.utils.python.file import target_file_utils
24from vts.utils.python.hal import hal_service_name_utils
25
26
27def CanRunHidlHalTest(test_instance,
28                      dut,
29                      shell=None,
30                      run_as_compliance_test=False):
31    """Checks HAL precondition of a test instance.
32
33    Args:
34        test_instance: the test instance which inherits BaseTestClass.
35        dut: the AndroidDevice under test.
36        shell: the ShellMirrorObject to execute command on the device.
37               If not specified, the function creates one from dut.
38        run_as_compliance_test: boolean, whether it is a compliance test.
39
40    Returns:
41        True if the precondition is satisfied; False otherwise.
42    """
43    if shell is None:
44        dut.shell.InvokeTerminal("check_hal_preconditions")
45        shell = dut.shell.check_hal_preconditions
46
47    opt_params = [
48        keys.ConfigKeys.IKEY_ABI_BITNESS,
49        keys.ConfigKeys.IKEY_PRECONDITION_HWBINDER_SERVICE,
50        keys.ConfigKeys.IKEY_PRECONDITION_FILE_PATH_PREFIX,
51        keys.ConfigKeys.IKEY_PRECONDITION_LSHAL,
52    ]
53    test_instance.getUserParams(opt_param_names=opt_params)
54
55    bitness = str(getattr(test_instance, keys.ConfigKeys.IKEY_ABI_BITNESS, ""))
56
57    hwbinder_service_name = str(
58        getattr(test_instance,
59                keys.ConfigKeys.IKEY_PRECONDITION_HWBINDER_SERVICE, ""))
60    if hwbinder_service_name:
61        if not hwbinder_service_name.startswith("android.hardware."):
62            logging.error("The given hwbinder service name %s is invalid.",
63                          hwbinder_service_name)
64        else:
65            cmd_results = shell.Execute("ps -A")
66            hwbinder_service_name += "@"
67            if (any(cmd_results[const.EXIT_CODE]) or
68                    hwbinder_service_name not in cmd_results[const.STDOUT][0]):
69                logging.warn("The required hwbinder service %s not found.",
70                             hwbinder_service_name)
71                return False
72
73    file_path_prefix = getattr(test_instance, "file_path_prefix", "")
74    if file_path_prefix and bitness:
75        logging.debug("FILE_PATH_PREFIX: %s", file_path_prefix)
76        logging.debug("Test bitness: %s", bitness)
77        tag = "_" + bitness + "bit"
78        if tag in file_path_prefix:
79            for path_prefix in file_path_prefix[tag]:
80                if not target_file_utils.Exists(path_prefix, shell):
81                    msg = (
82                        "The required file (prefix: {}) for {}-bit testcase "
83                        "not found.").format(path_prefix, bitness)
84                    logging.warn(msg)
85                    return False
86
87    hal = str(
88        getattr(test_instance, keys.ConfigKeys.IKEY_PRECONDITION_LSHAL, ""))
89    if hal:
90        testable, _ = hal_service_name_utils.GetHalServiceName(
91            shell, hal, bitness, run_as_compliance_test)
92        return testable
93
94    logging.debug("Precondition check pass.")
95    return True
96
97def CheckFeaturePrecondition(test_instance, dut, shell=None):
98    """Checks feature precondition of a test instance.
99
100    Args:
101        test_instance: the test instance which inherits BaseTestClass.
102        dut: the AndroidDevice under test.
103        shell: the ShellMirrorObject to execute command on the device.
104               If not specified, the function creates one from dut.
105
106    Returns:
107        True if the devise has the required feature; False otherwise.
108    """
109    opt_params = [
110        keys.ConfigKeys.IKEY_PRECONDITION_FEATURE,
111    ]
112    test_instance.getUserParams(opt_param_names=opt_params)
113
114    feature = str(
115        getattr(test_instance, keys.ConfigKeys.IKEY_PRECONDITION_FEATURE, ""))
116    if feature:
117        # If system is not running, needs to start the framework first.
118        if not dut.isFrameworkRunning():
119            if not dut.start():
120                logging.warn("Failed to start Android framework.")
121                return False
122
123        if shell is None:
124            dut.shell.InvokeTerminal("check_feature_precondition")
125            shell = dut.shell.check_feature_precondition
126
127        cmd_results = shell.Execute("LD_LIBRARY_PATH= pm list features")
128        if (any(cmd_results[const.EXIT_CODE])
129                or feature not in cmd_results[const.STDOUT][0]):
130            logging.warn("The required feature %s not found.", feature)
131            return False
132    logging.debug("Feature precondition check pass.")
133    return True
134
135def MeetFirstApiLevelPrecondition(test_instance, dut=None):
136    """Checks first API level precondition of a test instance.
137
138    If the device's ro.product.first_api_level is 0, this function checks
139    ro.build.version.sdk.
140
141    Args:
142        test_instance: the test instance which inherits BaseTestClass.
143        dut: the AndroidDevice under test.
144
145    Returns:
146        True if the device's first API level is greater than or equal to the
147        value of the precondition; False otherwise.
148    """
149    opt_params = [keys.ConfigKeys.IKEY_PRECONDITION_FIRST_API_LEVEL]
150    test_instance.getUserParams(opt_param_names=opt_params)
151    if not hasattr(test_instance,
152                   keys.ConfigKeys.IKEY_PRECONDITION_FIRST_API_LEVEL):
153        return True
154
155    precond_level_attr = getattr(
156        test_instance, keys.ConfigKeys.IKEY_PRECONDITION_FIRST_API_LEVEL, 0)
157    try:
158        precond_level = int(precond_level_attr)
159    except ValueError:
160        logging.error("Cannot parse first API level precondition: %s",
161                      precond_level_attr)
162        return True
163
164    if not dut:
165        logging.debug("Read first API level from the first device.")
166        dut = test_instance.android_devices[0]
167    device_level = dut.getLaunchApiLevel(strict=False)
168    if not device_level:
169        logging.error("Cannot read first API level from device. "
170                      "Assume it meets the precondition.")
171        return True
172
173    logging.debug("Device's first API level=%d; precondition=%d", device_level,
174                  precond_level)
175    return device_level >= precond_level
176
177
178def CheckSysPropPrecondition(test_instance, dut, shell=None):
179    """Checks sysprop precondition of a test instance.
180
181    Args:
182        test_instance: the test instance which inherits BaseTestClass.
183        dut: the AndroidDevice under test.
184        shell: the ShellMirrorObject to execute command on the device.
185               If not specified, the function creates one from dut.
186
187    Returns:
188        False if precondition is not met (i.e., to skip tests),
189        True otherwise (e.g., when no sysprop precondition is set;
190        the precondition is satisfied;
191        there is an error in retrieving the target sysprop; or
192        the specified sysprop is undefined)
193    """
194    if not hasattr(test_instance, keys.ConfigKeys.IKEY_PRECONDITION_SYSPROP):
195        return True
196
197    precond_sysprop = str(
198        getattr(test_instance, keys.ConfigKeys.IKEY_PRECONDITION_SYSPROP, ''))
199    if "=" not in precond_sysprop:
200        logging.error("precondition-sysprop value is invalid.")
201        return True
202
203    if shell is None:
204        dut.shell.InvokeTerminal("check_sysprop_precondition")
205        shell = dut.shell.check_sysprop_precondition
206
207    sysprop_key, sysprop_value = precond_sysprop.split('=')
208    cmd_results = shell.Execute('getprop %s' % sysprop_key)
209    if any(cmd_results[const.EXIT_CODE]):
210        logging.error('Failed to read sysprop:\n%s', sysprop_key)
211        return True
212    else:
213        value = cmd_results[const.STDOUT][0].strip()
214        if len(value) == 0:
215            return True
216        elif value != sysprop_value:
217            return False
218    return True
219