1c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# Use of this source code is governed by a BSD-style license that can be 3c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam# found in the LICENSE file. 4c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 5ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam"""A module to provide interface to OS services.""" 6c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 76dc580a3b2ef48db27509a023fdfd64334aa946edanny chanimport datetime 8c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport os 9c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport re 10c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamimport struct 1138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 1238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tamimport shell_wrapper 1338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 14c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 15ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tamclass OSInterfaceError(Exception): 16ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam """OS interface specific exception.""" 17c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam pass 18c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 19c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tamclass Crossystem(object): 20be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """A wrapper for the crossystem utility.""" 21c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 22c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam # Code dedicated for user triggering recovery mode through crossystem. 23c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam USER_RECOVERY_REQUEST_CODE = '193' 24c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 25ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam def init(self, os_if): 26be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Init the instance. If running on Mario - adjust the map.""" 27ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam self.os_if = os_if 28c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 29c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def __getattr__(self, name): 30be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 31c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam Retrieve a crosssystem attribute. 32c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 33c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam Attempt to access crossystemobject.name will invoke `crossystem name' 34c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam and return the stdout as the value. 35be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 36ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam return self.os_if.run_shell_command_get_output( 37c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 'crossystem %s' % name)[0] 38c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 39c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def __setattr__(self, name, value): 40ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam if name in ('os_if',): 41c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam self.__dict__[name] = value 42c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam else: 43ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam self.os_if.run_shell_command('crossystem "%s=%s"' % (name, value)) 44c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 45c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def request_recovery(self): 46be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Request recovery mode next time the target reboots.""" 47c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 48c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam self.__setattr__('recovery_request', self.USER_RECOVERY_REQUEST_CODE) 49c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 50c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 51ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tamclass OSInterface(object): 52be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """An object to encapsulate OS services functions.""" 53c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 54a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam ANDROID_TESTER_FILE = '/mnt/stateful_partition/.android_faft_tester' 55a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam 56ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam def __init__(self): 57ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam """Object construction time initialization.""" 58c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam self.state_dir = None 596dc580a3b2ef48db27509a023fdfd64334aa946edanny chan self.log_file = None 60c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam self.cs = Crossystem() 61a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam self.is_android = os.path.isfile(self.ANDROID_TESTER_FILE) 62a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam if self.is_android: 63a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam self.shell = shell_wrapper.AdbShell() 644a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam self.host_shell = shell_wrapper.LocalShell() 65a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam else: 66a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam self.shell = shell_wrapper.LocalShell() 674a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam self.host_shell = None 68a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam 69c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 706dc580a3b2ef48db27509a023fdfd64334aa946edanny chan def init(self, state_dir=None, log_file=None): 71ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam """Initialize the OS interface object. 7238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 73c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam Args: 74c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam state_dir - a string, the name of the directory (as defined by the 75c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam caller). The contents of this directory persist over 76c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam system restarts and power cycles. 776dc580a3b2ef48db27509a023fdfd64334aa946edanny chan log_file - a string, the name of the log file kept in the state 786dc580a3b2ef48db27509a023fdfd64334aa946edanny chan directory. 79c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 80c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam Default argument values support unit testing. 81be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 82c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam self.cs.init(self) 83c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam self.state_dir = state_dir 84c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 85c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if self.state_dir: 86c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if not os.path.exists(self.state_dir): 87c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam try: 88c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam os.mkdir(self.state_dir) 89c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam except OSError, err: 90ba5e3e52352ba60c43212f17c1d133006ef31ebdTom Wai-Hong Tam raise OSInterfaceError(err) 916dc580a3b2ef48db27509a023fdfd64334aa946edanny chan if log_file: 926dc580a3b2ef48db27509a023fdfd64334aa946edanny chan if log_file[0] == '/': 936dc580a3b2ef48db27509a023fdfd64334aa946edanny chan self.log_file = log_file 946dc580a3b2ef48db27509a023fdfd64334aa946edanny chan else: 956dc580a3b2ef48db27509a023fdfd64334aa946edanny chan self.log_file = os.path.join(state_dir, log_file) 96c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 9738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam # Initialize the shell. Should be after creating the log file. 9838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam self.shell.init(self) 994a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam if self.host_shell: 1004a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam self.host_shell.init(self) 10138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 102c7bdb7579baeeb7957001310cbd4dba63c4c43b3Tom Wai-Hong Tam def has_host(self): 103c7bdb7579baeeb7957001310cbd4dba63c4c43b3Tom Wai-Hong Tam """Return True if a host is connected to DUT.""" 104c7bdb7579baeeb7957001310cbd4dba63c4c43b3Tom Wai-Hong Tam return self.is_android 105c7bdb7579baeeb7957001310cbd4dba63c4c43b3Tom Wai-Hong Tam 10638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def run_shell_command(self, cmd): 10738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Run a shell command.""" 10838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam self.shell.run_command(cmd) 10938aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 11038aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def run_shell_command_get_status(self, cmd): 11138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Run shell command and return its return code.""" 11238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.shell.run_command_get_status(cmd) 11338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 11438aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def run_shell_command_get_output(self, cmd): 11538aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Run shell command and return its console output.""" 11638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.shell.run_command_get_output(cmd) 11738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 11802da40da2f81fda288668ba663c5dee4db672ebbShelley Chen def run_host_shell_command(self, cmd, block=True): 1194a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam """Run a shell command on the host.""" 1204a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam if self.host_shell: 12102da40da2f81fda288668ba663c5dee4db672ebbShelley Chen self.host_shell.run_command(cmd, block) 1224a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam else: 1234a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam raise OSInterfaceError('There is no host for DUT.') 1244a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam 1254a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam def run_host_shell_command_get_status(self, cmd): 1264a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam """Run shell command and return its return code on the host.""" 1274a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam if self.host_shell: 1284a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam return self.host_shell.run_command_get_status(cmd) 1294a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam else: 1304a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam raise OSInterfaceError('There is no host for DUT.') 1314a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam 1324a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam def run_host_shell_command_get_output(self, cmd): 1334a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam """Run shell command and return its console output.""" 1344a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam if self.host_shell: 1354a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam return self.host_shell.run_command_get_output(cmd) 1364a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam else: 1374a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam raise OSInterfaceError('There is no host for DUT.') 1384a1911eb368df8713a41c04adad8e704af01e06dTom Wai-Hong Tam 13938aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def read_file(self, path): 14038aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Read the content of the file.""" 14138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.shell.read_file(path) 14238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 14338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def write_file(self, path, data): 14438aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Write the data to the file.""" 14538aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam self.shell.write_file(path, data) 14638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 14738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def append_file(self, path, data): 14838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Append the data to the file.""" 14938aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam self.shell.append_file(path, data) 15038aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 15138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def path_exists(self, path): 15238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Return True if the path exists on DUT.""" 15338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam cmd = 'test -e %s' % path 15438aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.run_shell_command_get_status(cmd) == 0 15538aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 15638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def is_dir(self, path): 15738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Return True if the path is a directory.""" 15838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam cmd = 'test -d %s' % path 15938aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.run_shell_command_get_status(cmd) == 0 16038aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 16138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def create_dir(self, path): 16238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Create a new directory.""" 16338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam cmd = 'mkdir -p %s' % path 16438aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.run_shell_command(cmd) 16538aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 16638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def create_temp_file(self, prefix): 16738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Create a temporary file with a prefix.""" 168a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam if self.is_android: 169a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam tmp_path = '/data/local/tmp' 170a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam else: 171a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam tmp_path = '/tmp' 172a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam cmd = 'mktemp -p %s %sXXXXXX' % (tmp_path, prefix) 17338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.run_shell_command_get_output(cmd)[0] 17438aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 17538aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def copy_file(self, from_path, to_path): 17638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Copy the file.""" 17738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam cmd = 'cp -f %s %s' % (from_path, to_path) 17838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.run_shell_command(cmd) 17938aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 18038aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def copy_dir(self, from_path, to_path): 18138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Copy the directory.""" 18238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam cmd = 'cp -rf %s %s' % (from_path, to_path) 18338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.run_shell_command(cmd) 18438aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 18538aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def remove_file(self, path): 18638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Remove the file.""" 18738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam cmd = 'rm -f %s' % path 18838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.run_shell_command(cmd) 18938aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 19038aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def remove_dir(self, path): 19138aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Remove the directory.""" 19238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam cmd = 'rm -rf %s' % path 19338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return self.run_shell_command(cmd) 19438aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 19538aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam def get_file_size(self, path): 19638aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam """Get the size of the file.""" 19738aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam cmd = 'stat -c %%s %s' % path 19838aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam return int(self.run_shell_command_get_output(cmd)[0]) 19938aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam 200c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def target_hosted(self): 201a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam """Return True if running on DUT.""" 202a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam if self.is_android: 203a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam return True 204a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam signature = open('/etc/lsb-release', 'r').readlines()[0] 205c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return re.search(r'chrom(ium|e)os', signature, re.IGNORECASE) != None 206c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 207c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def state_dir_file(self, file_name): 208be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Get a full path of a file in the state directory.""" 209c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return os.path.join(self.state_dir, file_name) 210c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 2113dbc70ac3c58465b4c35b5d09ab10d0e28abde7fTom Wai-Hong Tam def wait_for_device(self, timeout): 2123dbc70ac3c58465b4c35b5d09ab10d0e28abde7fTom Wai-Hong Tam """Wait for an Android device to be connected.""" 2133dbc70ac3c58465b4c35b5d09ab10d0e28abde7fTom Wai-Hong Tam return self.shell.wait_for_device(timeout) 2143dbc70ac3c58465b4c35b5d09ab10d0e28abde7fTom Wai-Hong Tam 2153dbc70ac3c58465b4c35b5d09ab10d0e28abde7fTom Wai-Hong Tam def wait_for_no_device(self, timeout): 2163dbc70ac3c58465b4c35b5d09ab10d0e28abde7fTom Wai-Hong Tam """Wait for no Android device to be connected (offline).""" 2173dbc70ac3c58465b4c35b5d09ab10d0e28abde7fTom Wai-Hong Tam return self.shell.wait_for_no_device(timeout) 2183dbc70ac3c58465b4c35b5d09ab10d0e28abde7fTom Wai-Hong Tam 2196dc580a3b2ef48db27509a023fdfd64334aa946edanny chan def log(self, text): 2206dc580a3b2ef48db27509a023fdfd64334aa946edanny chan """Write text to the log file and print it on the screen, if enabled. 2216dc580a3b2ef48db27509a023fdfd64334aa946edanny chan 2226dc580a3b2ef48db27509a023fdfd64334aa946edanny chan The entire log (maintained across reboots) can be found in 2236dc580a3b2ef48db27509a023fdfd64334aa946edanny chan self.log_file. 2246dc580a3b2ef48db27509a023fdfd64334aa946edanny chan """ 2256dc580a3b2ef48db27509a023fdfd64334aa946edanny chan if not self.log_file or not os.path.exists(self.state_dir): 2266dc580a3b2ef48db27509a023fdfd64334aa946edanny chan # Called before environment was initialized, ignore. 2276dc580a3b2ef48db27509a023fdfd64334aa946edanny chan return 2286dc580a3b2ef48db27509a023fdfd64334aa946edanny chan 2296dc580a3b2ef48db27509a023fdfd64334aa946edanny chan timestamp = datetime.datetime.strftime( 2306dc580a3b2ef48db27509a023fdfd64334aa946edanny chan datetime.datetime.now(), '%I:%M:%S %p:') 2316dc580a3b2ef48db27509a023fdfd64334aa946edanny chan 2326dc580a3b2ef48db27509a023fdfd64334aa946edanny chan with open(self.log_file, 'a') as log_f: 2336dc580a3b2ef48db27509a023fdfd64334aa946edanny chan log_f.write('%s %s\n' % (timestamp, text)) 2346dc580a3b2ef48db27509a023fdfd64334aa946edanny chan log_f.flush() 2356dc580a3b2ef48db27509a023fdfd64334aa946edanny chan os.fdatasync(log_f) 2366dc580a3b2ef48db27509a023fdfd64334aa946edanny chan 237c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def is_removable_device(self, device): 238be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Check if a certain storage device is removable. 239c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 240c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam device - a string, file name of a storage device or a device partition 241c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam (as in /dev/sda[0-9] or /dev/mmcblk0p[0-9]). 242c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 243c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam Returns True if the device is removable, False if not. 244be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 245a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam if self.is_android: 246a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam return False 247c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 248c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if not self.target_hosted(): 249c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return False 250c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 251c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam # Drop trailing digit(s) and letter(s) (if any) 252c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam base_dev = self.strip_part(device.split('/')[2]) 25338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam removable = int(self.read_file('/sys/block/%s/removable' % base_dev)) 254c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 255c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return removable == 1 256c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 257c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def get_internal_disk(self, device): 258be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Get the internal disk by given the current disk. 259c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 260c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam If device is removable device, internal disk is decided by which kind 261c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam of divice (arm or x86). Otherwise, return device itself. 262c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 263c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam device - a string, file name of a storage device or a device partition 264c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam (as in /dev/sda[0-9] or /dev/mmcblk0p[0-9]). 265c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 266c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam Return internal kernel disk. 267be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 268c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if self.is_removable_device(device): 269bb61db3fde73d93429fe30e032d86f5178f97bcfDuncan Laurie for p in ('/dev/mmcblk0', '/dev/mmcblk1', '/dev/nvme0n1'): 2707bc9bf3d2e63f3e4bbf9bfeca64728f7c36e69c5Vadim Bendebury if self.path_exists(p): 2717bc9bf3d2e63f3e4bbf9bfeca64728f7c36e69c5Vadim Bendebury return p 2727bc9bf3d2e63f3e4bbf9bfeca64728f7c36e69c5Vadim Bendebury return '/dev/sda' 273c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam else: 274c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return self.strip_part(device) 275c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 276c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def get_root_part(self): 277be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Return a string, the name of root device with partition number""" 278a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam # FIXME(waihong): Android doesn't support dual kernel/root and misses 279a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam # the related tools. Just return something that not break the existing 280a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam # code. 281a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam if self.is_android: 282a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam return '/dev/mmcblk0p3' 283a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam else: 284a0265e39f0133d5e7699a4a675891cf71074aa95Tom Wai-Hong Tam return self.run_shell_command_get_output('rootdev -s')[0] 285c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 286c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def get_root_dev(self): 287be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Return a string, the name of root device without partition number""" 288c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return self.strip_part(self.get_root_part()) 289c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 290c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def join_part(self, dev, part): 291be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Return a concatenated string of device and partition number""" 292427c7b23118bf30175ef14327459a4db0adc381cGwendal Grignou if dev.endswith(tuple(str(i) for i in range(0, 10))): 29357159bdb256fc9a68f940e368613967516e44d6eDuncan Laurie return dev + 'p' + part 294c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam else: 295c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return dev + part 296c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 297c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def strip_part(self, dev_with_part): 298be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Return a stripped string without partition number""" 299c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam dev_name_stripper = re.compile('p?[0-9]+$') 300c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return dev_name_stripper.sub('', dev_with_part) 301c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 302c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def retrieve_body_version(self, blob): 303be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Given a blob, retrieve body version. 304c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 305c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam Currently works for both, firmware and kernel blobs. Returns '-1' in 306c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam case the version can not be retrieved reliably. 307be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 308c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam header_format = '<8s8sQ' 309c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam preamble_format = '<40sQ' 310c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam magic, _, kb_size = struct.unpack_from(header_format, blob) 311c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 312c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if magic != 'CHROMEOS': 313c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return -1 # This could be a corrupted version case. 314c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 315c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam _, version = struct.unpack_from(preamble_format, blob, kb_size) 316c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return version 317c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 318c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def retrieve_datakey_version(self, blob): 319be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Given a blob, retrieve firmware data key version. 320c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 321c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam Currently works for both, firmware and kernel blobs. Returns '-1' in 322c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam case the version can not be retrieved reliably. 323be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 324c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam header_format = '<8s96sQ' 325c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam magic, _, version = struct.unpack_from(header_format, blob) 326c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if magic != 'CHROMEOS': 327c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return -1 # This could be a corrupted version case. 328c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return version 329c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 330c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def retrieve_kernel_subkey_version(self, blob): 331be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Given a blob, retrieve kernel subkey version. 332c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 333c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam It is in firmware vblock's preamble. 334be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 335c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 336c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam header_format = '<8s8sQ' 337c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam preamble_format = '<72sQ' 338c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam magic, _, kb_size = struct.unpack_from(header_format, blob) 339c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 340c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if magic != 'CHROMEOS': 341c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return -1 342c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 343c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam _, version = struct.unpack_from(preamble_format, blob, kb_size) 344c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return version 345c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 346c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def retrieve_preamble_flags(self, blob): 347be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Given a blob, retrieve preamble flags if available. 348c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 349c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam It only works for firmware. If the version of preamble header is less 350c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam than 2.1, no preamble flags supported, just returns 0. 351be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """ 352c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam header_format = '<8s8sQ' 353c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam preamble_format = '<32sII64sI' 354c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam magic, _, kb_size = struct.unpack_from(header_format, blob) 355c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 356c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if magic != 'CHROMEOS': 357c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return -1 # This could be a corrupted version case. 358c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 359c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam _, ver, subver, _, flags = struct.unpack_from(preamble_format, blob, 360c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam kb_size) 361c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 362c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam if ver > 2 or (ver == 2 and subver >= 1): 363c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return flags 364c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam else: 365c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return 0 # Returns 0 if preamble flags not available. 366c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam 367c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam def read_partition(self, partition, size): 368be15328b1bbcf94c43e3435bbb4777a5dab259bbTom Wai-Hong Tam """Read the requested partition, up to size bytes.""" 369c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam tmp_file = self.state_dir_file('part.tmp') 370c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam self.run_shell_command('dd if=%s of=%s bs=1 count=%d' % ( 371c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam partition, tmp_file, size)) 37238aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam data = self.read_file(tmp_file) 37338aa548ceb0f1fdb081deb9389b4c8e99aee485bTom Wai-Hong Tam self.remove_file(tmp_file) 374c0168917ffb61c59c7746cd39fc53c1dd134723bTom Wai-Hong Tam return data 375