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