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 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