| #!/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. |
| # |
| |
| import logging |
| import subprocess |
| import time |
| |
| from threading import Timer |
| |
| from vts.testcases.vndk import utils |
| |
| SYSPROP_DEV_BOOTCOMPLETE = "dev.bootcomplete" |
| SYSPROP_SYS_BOOT_COMPLETED = "sys.boot_completed" |
| |
| |
| class Shell(object): |
| """This class to wrap adb shell command.""" |
| |
| def __init__(self, serial_number): |
| self._serial_number = serial_number |
| |
| def Execute(self, *args): |
| """Executes a command. |
| |
| Args: |
| args: Strings, the arguments. |
| |
| Returns: |
| Stdout as a string, stderr as a string, and return code as an |
| integer. |
| """ |
| cmd = ["adb", "-s", self._serial_number, "shell"] |
| cmd.extend(args) |
| return RunCommand(cmd) |
| |
| |
| class ADB(object): |
| """This class to wrap adb command.""" |
| |
| def __init__(self, serial_number): |
| self._serial_number = serial_number |
| |
| def Execute(self, cmd_list, timeout=None): |
| """Executes a command. |
| |
| Args: |
| args: Strings, the arguments. |
| |
| Returns: |
| Stdout as a string, stderr as a string, and return code as an |
| integer. |
| """ |
| cmd = ["adb", "-s", self._serial_number] |
| cmd.extend(cmd_list) |
| return RunCommand(cmd, timeout) |
| |
| class AndroidDevice(utils.AndroidDevice): |
| """This class controls the device via adb commands.""" |
| |
| def __init__(self, serial_number): |
| super(AndroidDevice, self).__init__(serial_number) |
| self._serial_number = serial_number |
| self.shell = Shell(serial_number) |
| self.adb = ADB(serial_number) |
| |
| def GetPermission(self, filepath): |
| """Get file permission.""" |
| out, err, r_code = self.shell.Execute('stat -c %%a %s' % filepath) |
| if r_code != 0 or err.strip(): |
| raise IOError("`stat -c %%a '%s'` stdout: %s\nstderr: %s" % |
| (filepath, out, err)) |
| return out.strip() |
| |
| def WaitForBootCompletion(self, timeout=None): |
| """Get file permission.""" |
| start = time.time() |
| cmd = ['wait-for-device'] |
| self.adb.Execute(cmd, timeout) |
| while not self.isBootCompleted(): |
| if time.time() - start >= timeout: |
| logging.error("Timeout while waiting for boot completion.") |
| return False |
| time.sleep(1) |
| return True |
| |
| def isBootCompleted(self): |
| """Checks whether the device has booted. |
| |
| Returns: |
| True if booted, False otherwise. |
| """ |
| try: |
| if (self._GetProp(SYSPROP_SYS_BOOT_COMPLETED) == '1' and |
| self._GetProp(SYSPROP_DEV_BOOTCOMPLETE) == '1'): |
| return True |
| except Exception as e: |
| # adb shell calls may fail during certain period of booting |
| # process, which is normal. Ignoring these errors. |
| pass |
| return False |
| |
| def IsShutdown(self, timeout=0): |
| """Checks whether the device has booted. |
| |
| Returns: |
| True if booted, False otherwise. |
| """ |
| start = time.time() |
| while (time.time() - start) <= timeout: |
| if not self.isBootCompleted(): |
| return True |
| time.sleep(1) |
| return self.isBootCompleted() |
| |
| def Root(self): |
| try: |
| self.adb.Execute(["root"]) |
| RETRIES = 3 |
| for i in range(RETRIES): |
| self.adb.Execute(["wait-for-device"]) |
| # Verify that we haven't raced with the exit of the old, |
| # non-root adbd |
| out, err, r_code = self.shell.Execute("id -un") |
| if r_code == 0 and not err.strip() and out.strip() == "root": |
| return True |
| time.sleep(1) |
| except subprocess.CalledProcessError as e: |
| logging.exception(e) |
| return False |
| |
| def ReadFileContent(self, filepath): |
| """Read the content of a file and perform assertions. |
| |
| Args: |
| filepath: string, path to file |
| |
| Returns: |
| string, content of file |
| """ |
| cmd = "cat %s" % filepath |
| out, err, r_code = self.shell.Execute(cmd) |
| |
| # checks the exit code |
| if r_code != 0 or err.strip(): |
| raise IOError("%s: Error happened while reading the file due to %s." |
| % (filepath, err)) |
| return out |
| |
| |
| def RunCommand(cmd, timeout=None): |
| kill = lambda process:process.kill() |
| proc = subprocess.Popen(args=cmd, |
| stderr=subprocess.PIPE, |
| stdout=subprocess.PIPE) |
| _timer = Timer(timeout, kill, [proc]) |
| try: |
| _timer.start() |
| (out, err) = proc.communicate() |
| finally: |
| _timer.cancel() |
| |
| try: |
| return out.decode('UTF-8'), err.decode('UTF-8'), proc.returncode |
| except UnicodeDecodeError: |
| # ProcUidCpuPowerTimeInStateTest, ProcUidCpuPowerConcurrentActiveTimeTest, |
| # and ProcUidCpuPowerConcurrentPolicyTimeTest output could not be decode |
| # to UTF-8. |
| return out.decode('ISO-8859-1'), err.decode('ISO-8859-1'), proc.returncode |