diff options
Diffstat (limited to 'utils.py')
-rw-r--r-- | utils.py | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..8e6cc52 --- /dev/null +++ b/utils.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python +# +# Copyright (C) 2020 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# TODO(b/147454897): Keep the logic in sync with +# test/vts/utils/python/controllers/android_device.py until +# it is removed. +import logging +import subprocess + +class AndroidDevice(object): + """This class controls the device via adb commands.""" + + def _ExecuteCommand(self, *cmd): + """Executes a command. + + Args: + args: Strings, the arguments. + + Returns: + Stdout as a string, stderr as a string, and return code as an + integer. + """ + proc = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = proc.communicate() + # Compatible with python2 and python3 + if not isinstance(out, str): + out = out.decode("utf-8") + if not isinstance(err, str): + err = err.decode("utf-8") + return out, err, proc.returncode + + def _GetProp(self, name): + """Gets an Android system property. + + Args: + name: A string, the property name. + + Returns: + A string, the value of the property. + + Raises: + IOError if the command fails. + """ + out, err, return_code = self._ExecuteCommand("getprop", name) + if err.strip() or return_code != 0: + raise IOError("`getprop %s` stdout: %s\nstderr: %s" % + (name, out, err)) + return out.strip() + + def GetCpuAbiList(self, bitness=""): + """Gets the list of supported ABIs from property. + + Args: + bitness: 32 or 64. If the argument is not specified, this method + returns both 32 and 64-bit ABIs. + + Returns: + A list of strings, the supported ABIs. + """ + out = self._GetProp("ro.product.cpu.abilist" + str(bitness)) + return out.lower().split(",") if out else [] + + def GetLaunchApiLevel(self): + """Gets the API level that the device was initially launched with. + + This method reads ro.product.first_api_level from the device. If the + value is 0, it then reads ro.build.version.sdk. + + Returns: + An integer, the API level. + """ + level_str = self._GetProp("ro.product.first_api_level") + level = int(level_str) + if level != 0: + return level + + level_str = self._GetProp("ro.build.version.sdk") + return int(level_str) + + def getLaunchApiLevel(self, strict=True): + """Gets the API level that the device was initially launched with. + + This method is compatible with vndk_utils in vts package. + + Args: + strict: A boolean, whether to raise an error if the property is + not an integer or not defined. + + Returns: + An integer, the API level. + 0 if the value is undefined and strict is False. + + Raises: + ValueError: if the value is undefined and strict is True. + """ + try: + return self.GetLaunchApiLevel() + except ValueError as e: + if strict: + raise + logging.exception(e) + return 0 + + @property + def vndk_lite(self): + """Checks whether the vendor partition requests lite VNDK enforcement. + + This method is compatible with vndk_utils in vts package. + + Returns: + A boolean, True for lite vndk enforcement. + """ + return self._GetProp("ro.vndk.lite").lower() == "true" + + def GetVndkVersion(self): + """Gets the VNDK version that the vendor partition requests.""" + return self._GetProp("ro.vndk.version") + + def IsRoot(self): + """Returns whether adb has root privilege on the device.""" + out, err, return_code = self._ExecuteCommand("id") + if err.strip() or return_code != 0: + raise IOError("`id` stdout: %s\nstderr: %s \n" % (out, err)) + return "uid=0(root)" in out.strip() + + def _Test(self, *args): + """Tests file types and status.""" + out, err, return_code = self._ExecuteCommand("sh", "-c", + "test " + " ".join(args)) + if out.strip() or err.strip(): + raise IOError("`test` args: %s\nstdout: %s\nstderr: %s" % + (args, out, err)) + return return_code == 0 + + def IsDirectory(self, path): + """Returns whether a path on the device is a directory.""" + return self._Test("-d", path) + + def _Stat(self, fmt, path): + """Executes stat command.""" + out, err, return_code = self._ExecuteCommand("stat", "--format", fmt, + path) + if return_code != 0 or err.strip(): + raise IOError("`stat --format %s %s` stdout: %s\nstderr: %s" % + (fmt, path, out, err)) + return out.strip() + + def IsExecutable(self, path): + """Returns if execute permission is granted to a path on the device.""" + return "x" in self._Stat("%A", path) |