1 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 """Code to provide functions for FAFT tests. 6 7 These can be exposed via a xmlrpci server running on the DUT. 8 """ 9 10 import functools, os, tempfile 11 12 import common 13 from autotest_lib.client.cros.faft.utils import (cgpt_handler, 14 os_interface, 15 firmware_check_keys, 16 firmware_updater, 17 flashrom_handler, 18 kernel_handler, 19 rootfs_handler, 20 saft_flashrom_util, 21 tpm_handler, 22 ) 23 24 25 def allow_multiple_section_input(image_operator): 26 """Decorate a method to support multiple sections. 27 28 @param image_operator: Method accepting one section as its argument. 29 """ 30 @functools.wraps(image_operator) 31 def wrapper(self, section): 32 """Wrapper method to support multiple sections. 33 34 @param section: A list of sections of just a section. 35 """ 36 if type(section) in (tuple, list): 37 for sec in section: 38 image_operator(self, sec) 39 else: 40 image_operator(self, section) 41 return wrapper 42 43 44 class LazyInitHandlerProxy: 45 """Proxy of a given handler_class for lazy initialization.""" 46 _loaded = False 47 _obj = None 48 49 def __init__(self, handler_class, *args, **kargs): 50 self._handler_class = handler_class 51 self._args = args 52 self._kargs = kargs 53 54 def _load(self): 55 self._obj = self._handler_class() 56 self._obj.init(*self._args, **self._kargs) 57 self._loaded = True 58 59 def __getattr__(self, name): 60 if not self._loaded: 61 self._load() 62 return getattr(self._obj, name) 63 64 def reload(self): 65 """Reload the FlashromHandler class.""" 66 self._loaded = False 67 68 69 class RPCFunctions(object): 70 """A class which aggregates some useful functions for firmware testing. 71 72 This class can be exposed via a XMLRPC server such that its functions can 73 be accessed remotely. Method naming should fit the naming rule 74 '_[categories]_[method_name]' where categories contains system, ec, bios, 75 kernel, cgpt, tpm, updater, etc. Methods should be called by 76 'FAFTClient.[categories].[method_name]', because _dispatch will rename 77 this name to '_[categories]_[method_name]'. 78 79 Attributes: 80 _os_if: An object to encapsulate OS services functions. 81 _bios_handler: An object to automate BIOS flashrom testing. 82 _ec_handler: An object to automate EC flashrom testing. 83 _kernel_handler: An object to provide kernel related actions. 84 _log_file: Path of the log file. 85 _tpm_handler: An object to control TPM device. 86 _updater: An object to update firmware. 87 _temp_path: Path of a temp directory. 88 _keys_path: Path of a directory, keys/, in temp directory. 89 _work_path: Path of a directory, work/, in temp directory. 90 """ 91 def __init__(self): 92 """Initialize the data attributes of this class.""" 93 # TODO(waihong): Move the explicit object.init() methods to the 94 # objects' constructors (OSInterface, FlashromHandler, 95 # KernelHandler, and TpmHandler). 96 self._os_if = os_interface.OSInterface() 97 # We keep the state of FAFT test in a permanent directory over reboots. 98 state_dir = '/var/tmp/faft' 99 self._log_file = os.path.join(state_dir, 'faft_client.log') 100 self._os_if.init(state_dir, log_file=self._log_file) 101 os.chdir(state_dir) 102 103 self._bios_handler = LazyInitHandlerProxy( 104 flashrom_handler.FlashromHandler, 105 saft_flashrom_util, 106 self._os_if, 107 None, 108 '/usr/share/vboot/devkeys', 109 'bios') 110 111 self._ec_handler = None 112 if self._os_if.run_shell_command_get_status('mosys ec info') == 0: 113 self._ec_handler = LazyInitHandlerProxy( 114 flashrom_handler.FlashromHandler, 115 saft_flashrom_util, 116 self._os_if, 117 'ec_root_key.vpubk', 118 '/usr/share/vboot/devkeys', 119 'ec') 120 else: 121 self._os_if.log('No EC is reported by mosys.') 122 123 self._kernel_handler = kernel_handler.KernelHandler() 124 self._kernel_handler.init(self._os_if, 125 dev_key_path='/usr/share/vboot/devkeys', 126 internal_disk=True) 127 128 self._tpm_handler = LazyInitHandlerProxy( 129 tpm_handler.TpmHandler, 130 self._os_if) 131 132 self._cgpt_handler = cgpt_handler.CgptHandler(self._os_if) 133 134 self._rootfs_handler = rootfs_handler.RootfsHandler() 135 self._rootfs_handler.init(self._os_if) 136 137 self._updater = firmware_updater.FirmwareUpdater(self._os_if) 138 self._check_keys = firmware_check_keys.firmwareCheckKeys() 139 140 # Initialize temporary directory path 141 self._temp_path = '/var/tmp/faft/autest' 142 self._keys_path = os.path.join(self._temp_path, 'keys') 143 self._work_path = os.path.join(self._temp_path, 'work') 144 145 def _dispatch(self, method, params): 146 """This _dispatch method handles string conversion especially. 147 148 Since we turn off allow_dotted_names option. So any string conversion, 149 like str(FAFTClient.method), i.e. FAFTClient.method.__str__, failed 150 via XML RPC call. 151 """ 152 is_str = method.endswith('.__str__') 153 if is_str: 154 method = method.rsplit('.', 1)[0] 155 156 categories = ('system', 'host', 'bios', 'ec', 'kernel', 157 'tpm', 'cgpt', 'updater', 'rootfs') 158 try: 159 if method.split('.', 1)[0] in categories: 160 func = getattr(self, '_%s_%s' % (method.split('.', 1)[0], 161 method.split('.', 1)[1])) 162 else: 163 func = getattr(self, method) 164 except AttributeError: 165 raise Exception('method "%s" is not supported' % method) 166 167 if is_str: 168 return str(func) 169 else: 170 self._os_if.log('Dispatching method %s with args %r' % 171 (func.__name__, params)) 172 return func(*params) 173 174 def _system_is_available(self): 175 """Function for polling the RPC server availability. 176 177 @return: Always True. 178 """ 179 return True 180 181 def _system_has_host(self): 182 """Return True if a host is connected to DUT.""" 183 return self._os_if.has_host() 184 185 def _system_wait_for_client(self, timeout): 186 """Wait for the client to come back online. 187 188 @param timeout: Time in seconds to wait for the client SSH daemon to 189 come up. 190 @return: True if succeed; otherwise False. 191 """ 192 return self._os_if.wait_for_device(timeout) 193 194 def _system_wait_for_client_offline(self, timeout): 195 """Wait for the client to come offline. 196 197 @param timeout: Time in seconds to wait the client to come offline. 198 @return: True if succeed; otherwise False. 199 """ 200 return self._os_if.wait_for_no_device(timeout) 201 202 def _system_dump_log(self, remove_log=False): 203 """Dump the log file. 204 205 @param remove_log: Remove the log file after dump. 206 @return: String of the log file content. 207 """ 208 log = open(self._log_file).read() 209 if remove_log: 210 os.remove(self._log_file) 211 return log 212 213 def _system_run_shell_command(self, command): 214 """Run shell command. 215 216 @param command: A shell command to be run. 217 """ 218 self._os_if.run_shell_command(command) 219 220 def _system_run_shell_command_get_output(self, command): 221 """Run shell command and get its console output. 222 223 @param command: A shell command to be run. 224 @return: A list of strings stripped of the newline characters. 225 """ 226 return self._os_if.run_shell_command_get_output(command) 227 228 def _host_run_shell_command(self, command): 229 """Run shell command on the host. 230 231 @param command: A shell command to be run. 232 """ 233 self._os_if.run_host_shell_command(command) 234 235 def _host_run_shell_command_get_output(self, command): 236 """Run shell command and get its console output on the host. 237 238 @param command: A shell command to be run. 239 @return: A list of strings stripped of the newline characters. 240 """ 241 return self._os_if.run_host_shell_command_get_output(command) 242 243 def _host_run_nonblock_shell_command(self, command): 244 """Run non-blocking shell command 245 246 @param command: A shell command to be run. 247 @return: none 248 """ 249 return self._os_if.run_host_shell_command(command, False) 250 251 def _system_software_reboot(self): 252 """Request software reboot.""" 253 self._os_if.run_shell_command('reboot') 254 255 def _system_get_platform_name(self): 256 """Get the platform name of the current system. 257 258 @return: A string of the platform name. 259 """ 260 # 'mosys platform name' sometimes fails. Let's get the verbose output. 261 lines = self._os_if.run_shell_command_get_output( 262 '(mosys -vvv platform name 2>&1) || echo Failed') 263 if lines[-1].strip() == 'Failed': 264 raise Exception('Failed getting platform name: ' + '\n'.join(lines)) 265 return lines[-1] 266 267 def _system_get_crossystem_value(self, key): 268 """Get crossystem value of the requested key. 269 270 @param key: A crossystem key. 271 @return: A string of the requested crossystem value. 272 """ 273 return self._os_if.run_shell_command_get_output( 274 'crossystem %s' % key)[0] 275 276 def _system_get_root_dev(self): 277 """Get the name of root device without partition number. 278 279 @return: A string of the root device without partition number. 280 """ 281 return self._os_if.get_root_dev() 282 283 def _system_get_root_part(self): 284 """Get the name of root device with partition number. 285 286 @return: A string of the root device with partition number. 287 """ 288 return self._os_if.get_root_part() 289 290 def _system_set_try_fw_b(self, count=1): 291 """Set 'Try Frimware B' flag in crossystem. 292 293 @param count: # times to try booting into FW B 294 """ 295 self._os_if.cs.fwb_tries = count 296 297 def _system_set_fw_try_next(self, next, count=0): 298 """Set fw_try_next to A or B 299 300 @param next: Next FW to reboot to (A or B) 301 @param count: # of times to try booting into FW <next> 302 """ 303 self._os_if.cs.fw_try_next = next 304 if count: 305 self._os_if.cs.fw_try_count = count 306 307 def _system_get_fw_vboot2(self): 308 """Get fw_vboot2""" 309 try: 310 return self._os_if.cs.fw_vboot2 == '1' 311 except os_interface.OSInterfaceError: 312 return False 313 314 def _system_request_recovery_boot(self): 315 """Request running in recovery mode on the restart.""" 316 self._os_if.cs.request_recovery() 317 318 def _system_get_dev_boot_usb(self): 319 """Get dev_boot_usb value which controls developer mode boot from USB. 320 321 @return: True if enable, False if disable. 322 """ 323 return self._os_if.cs.dev_boot_usb == '1' 324 325 def _system_set_dev_boot_usb(self, value): 326 """Set dev_boot_usb value which controls developer mode boot from USB. 327 328 @param value: True to enable, False to disable. 329 """ 330 self._os_if.cs.dev_boot_usb = 1 if value else 0 331 332 def _system_is_removable_device_boot(self): 333 """Check the current boot device is removable. 334 335 @return: True: if a removable device boots. 336 False: if a non-removable device boots. 337 """ 338 root_part = self._os_if.get_root_part() 339 return self._os_if.is_removable_device(root_part) 340 341 def _system_create_temp_dir(self, prefix='backup_'): 342 """Create a temporary directory and return the path.""" 343 return tempfile.mkdtemp(prefix=prefix) 344 345 def _bios_reload(self): 346 """Reload the firmware image that may be changed.""" 347 self._bios_handler.reload() 348 349 def _bios_get_gbb_flags(self): 350 """Get the GBB flags. 351 352 @return: An integer of the GBB flags. 353 """ 354 return self._bios_handler.get_gbb_flags() 355 356 def _bios_set_gbb_flags(self, flags): 357 """Set the GBB flags. 358 359 @param flags: An integer of the GBB flags. 360 """ 361 self._bios_handler.set_gbb_flags(flags, write_through=True) 362 363 def _bios_get_preamble_flags(self, section): 364 """Get the preamble flags of a firmware section. 365 366 @param section: A firmware section, either 'a' or 'b'. 367 @return: An integer of the preamble flags. 368 """ 369 return self._bios_handler.get_section_flags(section) 370 371 def _bios_set_preamble_flags(self, section, flags): 372 """Set the preamble flags of a firmware section. 373 374 @param section: A firmware section, either 'a' or 'b'. 375 @param flags: An integer of preamble flags. 376 """ 377 version = self._bios_get_version(section) 378 self._bios_handler.set_section_version(section, version, flags, 379 write_through=True) 380 381 def _bios_get_body_sha(self, section): 382 """Get SHA1 hash of BIOS RW firmware section. 383 384 @param section: A firmware section, either 'a' or 'b'. 385 @param flags: An integer of preamble flags. 386 """ 387 return self._bios_handler.get_section_sha(section) 388 389 def _bios_get_sig_sha(self, section): 390 """Get SHA1 hash of firmware vblock in section.""" 391 return self._bios_handler.get_section_sig_sha(section) 392 393 @allow_multiple_section_input 394 def _bios_corrupt_sig(self, section): 395 """Corrupt the requested firmware section signature. 396 397 @param section: A firmware section, either 'a' or 'b'. 398 """ 399 self._bios_handler.corrupt_firmware(section) 400 401 @allow_multiple_section_input 402 def _bios_restore_sig(self, section): 403 """Restore the previously corrupted firmware section signature. 404 405 @param section: A firmware section, either 'a' or 'b'. 406 """ 407 self._bios_handler.restore_firmware(section) 408 409 @allow_multiple_section_input 410 def _bios_corrupt_body(self, section): 411 """Corrupt the requested firmware section body. 412 413 @param section: A firmware section, either 'a' or 'b'. 414 """ 415 self._bios_handler.corrupt_firmware_body(section) 416 417 @allow_multiple_section_input 418 def _bios_restore_body(self, section): 419 """Restore the previously corrupted firmware section body. 420 421 @param section: A firmware section, either 'a' or 'b'. 422 """ 423 self._bios_handler.restore_firmware_body(section) 424 425 def __bios_modify_version(self, section, delta): 426 """Modify firmware version for the requested section, by adding delta. 427 428 The passed in delta, a positive or a negative number, is added to the 429 original firmware version. 430 """ 431 original_version = self._bios_get_version(section) 432 new_version = original_version + delta 433 flags = self._bios_handler.get_section_flags(section) 434 self._os_if.log( 435 'Setting firmware section %s version from %d to %d' % ( 436 section, original_version, new_version)) 437 self._bios_handler.set_section_version(section, new_version, flags, 438 write_through=True) 439 440 @allow_multiple_section_input 441 def _bios_move_version_backward(self, section): 442 """Decrement firmware version for the requested section.""" 443 self.__bios_modify_version(section, -1) 444 445 @allow_multiple_section_input 446 def _bios_move_version_forward(self, section): 447 """Increase firmware version for the requested section.""" 448 self.__bios_modify_version(section, 1) 449 450 def _bios_get_version(self, section): 451 """Retrieve firmware version of a section.""" 452 return self._bios_handler.get_section_version(section) 453 454 def _bios_get_datakey_version(self, section): 455 """Return firmware data key version.""" 456 return self._bios_handler.get_section_datakey_version(section) 457 458 def _bios_get_kernel_subkey_version(self, section): 459 """Return kernel subkey version.""" 460 return self._bios_handler.get_section_kernel_subkey_version(section) 461 462 def _bios_dump_whole(self, bios_path): 463 """Dump the current BIOS firmware to a file, specified by bios_path. 464 465 @param bios_path: The path of the BIOS image to be written. 466 """ 467 self._bios_handler.dump_whole(bios_path) 468 469 def _bios_write_whole(self, bios_path): 470 """Write the firmware from bios_path to the current system. 471 472 @param bios_path: The path of the source BIOS image. 473 """ 474 self._bios_handler.new_image(bios_path) 475 self._bios_handler.write_whole() 476 477 def _ec_get_version(self): 478 """Get EC version via mosys. 479 480 @return: A string of the EC version. 481 """ 482 return self._os_if.run_shell_command_get_output( 483 'mosys ec info | sed "s/.*| //"')[0] 484 485 def _ec_get_firmware_sha(self): 486 """Get SHA1 hash of EC RW firmware section.""" 487 return self._ec_handler.get_section_sha('rw') 488 489 def _ec_dump_whole(self, ec_path): 490 """Dump the current EC firmware to a file, specified by ec_path. 491 492 @param ec_path: The path of the EC image to be written. 493 """ 494 self._ec_handler.dump_whole(ec_path) 495 496 def _ec_write_whole(self, ec_path): 497 """Write the firmware from ec_path to the current system. 498 499 @param ec_path: The path of the source EC image. 500 """ 501 self._ec_handler.new_image(ec_path) 502 self._ec_handler.write_whole() 503 504 @allow_multiple_section_input 505 def _ec_corrupt_sig(self, section): 506 """Corrupt the requested EC section signature. 507 508 @param section: A EC section, either 'a' or 'b'. 509 """ 510 self._ec_handler.corrupt_firmware(section, corrupt_all=True) 511 512 @allow_multiple_section_input 513 def _ec_restore_sig(self, section): 514 """Restore the previously corrupted EC section signature. 515 516 @param section: An EC section, either 'a' or 'b'. 517 """ 518 self._ec_handler.restore_firmware(section, restore_all=True) 519 520 @allow_multiple_section_input 521 def _ec_corrupt_body(self, section): 522 """Corrupt the requested EC section body. 523 524 @param section: An EC section, either 'a' or 'b'. 525 """ 526 self._ec_handler.corrupt_firmware_body(section, corrupt_all=True) 527 528 @allow_multiple_section_input 529 def _ec_restore_body(self, section): 530 """Restore the previously corrupted EC section body. 531 532 @param section: An EC section, either 'a' or 'b'. 533 """ 534 self._ec_handler.restore_firmware_body(section, restore_all=True) 535 536 def _ec_dump_firmware(self, ec_path): 537 """Dump the current EC firmware to a file, specified by ec_path. 538 539 @param ec_path: The path of the EC image to be written. 540 """ 541 self._ec_handler.dump_whole(ec_path) 542 543 def _ec_set_write_protect(self, enable): 544 """Enable write protect of the EC flash chip. 545 546 @param enable: True if activating EC write protect. Otherwise, False. 547 """ 548 if enable: 549 self._ec_handler.enable_write_protect() 550 else: 551 self._ec_handler.disable_write_protect() 552 553 @allow_multiple_section_input 554 def _kernel_corrupt_sig(self, section): 555 """Corrupt the requested kernel section. 556 557 @param section: A kernel section, either 'a' or 'b'. 558 """ 559 self._kernel_handler.corrupt_kernel(section) 560 561 @allow_multiple_section_input 562 def _kernel_restore_sig(self, section): 563 """Restore the requested kernel section (previously corrupted). 564 565 @param section: A kernel section, either 'a' or 'b'. 566 """ 567 self._kernel_handler.restore_kernel(section) 568 569 def __kernel_modify_version(self, section, delta): 570 """Modify kernel version for the requested section, by adding delta. 571 572 The passed in delta, a positive or a negative number, is added to the 573 original kernel version. 574 """ 575 original_version = self._kernel_handler.get_version(section) 576 new_version = original_version + delta 577 self._os_if.log( 578 'Setting kernel section %s version from %d to %d' % ( 579 section, original_version, new_version)) 580 self._kernel_handler.set_version(section, new_version) 581 582 @allow_multiple_section_input 583 def _kernel_move_version_backward(self, section): 584 """Decrement kernel version for the requested section.""" 585 self.__kernel_modify_version(section, -1) 586 587 @allow_multiple_section_input 588 def _kernel_move_version_forward(self, section): 589 """Increase kernel version for the requested section.""" 590 self.__kernel_modify_version(section, 1) 591 592 def _kernel_get_version(self, section): 593 """Return kernel version.""" 594 return self._kernel_handler.get_version(section) 595 596 def _kernel_get_datakey_version(self, section): 597 """Return kernel datakey version.""" 598 return self._kernel_handler.get_datakey_version(section) 599 600 def _kernel_diff_a_b(self): 601 """Compare kernel A with B. 602 603 @return: True: if kernel A is different with B. 604 False: if kernel A is the same as B. 605 """ 606 rootdev = self._os_if.get_root_dev() 607 kernel_a = self._os_if.join_part(rootdev, '2') 608 kernel_b = self._os_if.join_part(rootdev, '4') 609 610 # The signature (some kind of hash) for the kernel body is stored in 611 # the beginning. So compare the first 64KB (including header, preamble, 612 # and signature) should be enough to check them identical. 613 header_a = self._os_if.read_partition(kernel_a, 0x10000) 614 header_b = self._os_if.read_partition(kernel_b, 0x10000) 615 616 return header_a != header_b 617 618 def _kernel_resign_with_keys(self, section, key_path=None): 619 """Resign kernel with temporary key.""" 620 self._kernel_handler.resign_kernel(section, key_path) 621 622 def _kernel_dump(self, section, kernel_path): 623 """Dump the specified kernel to a file. 624 625 @param section: The kernel to dump. May be A or B. 626 @param kernel_path: The path to the kernel image to be written. 627 """ 628 self._kernel_handler.dump_kernel(section, kernel_path) 629 630 def _kernel_write(self, section, kernel_path): 631 """Write a kernel image to the specified section. 632 633 @param section: The kernel to dump. May be A or B. 634 @param kernel_path: The path to the kernel image. 635 """ 636 self._kernel_handler.write_kernel(section, kernel_path) 637 638 def _kernel_get_sha(self, section): 639 """Return the SHA1 hash of the specified kernel section.""" 640 return self._kernel_handler.get_sha(section) 641 642 def _tpm_get_firmware_version(self): 643 """Retrieve tpm firmware body version.""" 644 return self._tpm_handler.get_fw_version() 645 646 def _tpm_get_firmware_datakey_version(self): 647 """Retrieve tpm firmware data key version.""" 648 return self._tpm_handler.get_fw_key_version() 649 650 def _tpm_get_kernel_version(self): 651 """Retrieve tpm kernel body version.""" 652 return self._tpm_handler.get_kernel_version() 653 654 def _tpm_get_kernel_datakey_version(self): 655 """Retrieve tpm kernel data key version.""" 656 return self._tpm_handler.get_kernel_key_version() 657 658 def _tpm_stop_daemon(self): 659 """Stop tpm related daemon.""" 660 return self._tpm_handler.stop_daemon() 661 662 def _tpm_restart_daemon(self): 663 """Restart tpm related daemon which was stopped by stop_daemon().""" 664 return self._tpm_handler.restart_daemon() 665 666 def _cgpt_get_attributes(self): 667 """Get kernel attributes.""" 668 rootdev = self._system_get_root_dev() 669 self._cgpt_handler.read_device_info(rootdev) 670 return {'A': self._cgpt_handler.get_partition(rootdev, 'KERN-A'), 671 'B': self._cgpt_handler.get_partition(rootdev, 'KERN-B')} 672 673 def _cgpt_set_attributes(self, attributes): 674 """Set kernel attributes.""" 675 rootdev = self._system_get_root_dev() 676 allowed = ['priority', 'tries', 'successful'] 677 for p in ('A', 'B'): 678 if p not in attributes: 679 continue 680 attr = dict() 681 for k in allowed: 682 if k in attributes[p]: 683 attr[k] = attributes[p][k] 684 if attr: 685 self._cgpt_handler.set_partition(rootdev, 'KERN-%s' % p, attr) 686 687 def _updater_cleanup(self): 688 self._updater.cleanup_temp_dir() 689 690 def _updater_get_fwid(self): 691 """Retrieve shellball's fwid. 692 693 @return: Shellball's fwid. 694 """ 695 return self._updater.retrieve_fwid() 696 697 def _updater_resign_firmware(self, version): 698 """Resign firmware with version. 699 700 @param version: new version number. 701 """ 702 self._updater.resign_firmware(version) 703 704 def _updater_extract_shellball(self, append=None): 705 """Extract shellball with the given append suffix. 706 707 @param append: use for the shellball name. 708 """ 709 self._updater.extract_shellball(append) 710 711 def _updater_repack_shellball(self, append=None): 712 """Repack shellball with new fwid. 713 714 @param append: use for new fwid naming. 715 """ 716 self._updater.repack_shellball(append) 717 718 def _updater_run_autoupdate(self, append): 719 """Run chromeos-firmwareupdate with autoupdate mode.""" 720 options = ['--noupdate_ec', '--nocheck_rw_compatible'] 721 self._updater.run_firmwareupdate(mode='autoupdate', 722 updater_append=append, 723 options=options) 724 725 def _updater_run_factory_install(self): 726 """Run chromeos-firmwareupdate with factory_install mode.""" 727 options = ['--noupdate_ec'] 728 self._updater.run_firmwareupdate(mode='factory_install', 729 options=options) 730 731 def _updater_run_bootok(self, append): 732 """Run chromeos-firmwareupdate with bootok mode.""" 733 self._updater.run_firmwareupdate(mode='bootok', 734 updater_append=append) 735 736 def _updater_run_recovery(self): 737 """Run chromeos-firmwareupdate with recovery mode.""" 738 options = ['--noupdate_ec', '--nocheck_rw_compatible'] 739 self._updater.run_firmwareupdate(mode='recovery', 740 options=options) 741 742 def _updater_get_temp_path(self): 743 """Get updater's temp directory path.""" 744 return self._updater.get_temp_path() 745 746 def _updater_get_keys_path(self): 747 """Get updater's keys directory path.""" 748 return self._updater.get_keys_path() 749 750 def _updater_get_work_path(self): 751 """Get updater's work directory path.""" 752 return self._updater.get_work_path() 753 754 def _rootfs_verify_rootfs(self, section): 755 """Verifies the integrity of the root FS. 756 757 @param section: The rootfs to verify. May be A or B. 758 """ 759 return self._rootfs_handler.verify_rootfs(section) 760 761 def _system_check_keys(self, expected_sequence): 762 """Check the keys sequence was as expected. 763 764 @param expected_sequence: A list of expected key sequences. 765 """ 766 return self._check_keys.check_keys(expected_sequence) 767 768 def cleanup(self): 769 """Cleanup for the RPC server. Currently nothing.""" 770 pass 771