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
7These can be exposed via a xmlrpci server running on the DUT.
8"""
9
10import functools, os, tempfile
11
12from 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
25def 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
44class 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