• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import traceback
12 
13 from 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 
26 def 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 
45 class 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