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