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