blob: 01fe1193aeba5bec6b820de4ffc18890e59e703b [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Jon Salze60307f2014-08-05 16:20:00 +08002# -*- coding: utf-8 -*-
3# Copyright 2014 The Chromium OS Authors. All rights reserved.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
Jon Salze60307f2014-08-05 16:20:00 +08007# pylint: disable=E1101
8
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08009"""Google Factory Tool.
10
11This tool is indended to be used on factory assembly lines. It
12provides all of the Google required test functionality and must be run
13on each device as part of the assembly process.
14"""
15
Ricky Liang5b4568d2013-04-23 17:15:23 +080016import collections
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080017import logging
18import os
Jon Salz65266432012-07-30 19:02:49 +080019import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080020import re
21import sys
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080022import threading
Hung-Te Lin6bd16472012-06-20 16:26:47 +080023import time
Jon Salza88b83b2013-05-27 20:00:35 +080024import xmlrpclib
Ricky Liang7905f272013-03-16 01:57:10 +080025import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080026
Andy Cheng2582d292012-12-04 17:38:28 +080027from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080028
Tammo Spalinka40293e2012-07-04 14:58:56 +080029import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080030
Joel Kitchingd3bc2662014-12-16 16:03:32 -080031from cros.factory.common import SetupLogging, Shell
Andy Chengc531e2f2012-10-15 19:09:17 +080032from cros.factory.gooftool import Gooftool
Ricky Liang53390232013-03-08 15:37:57 +080033from cros.factory.gooftool import crosfw
Tammo Spalink01e11722012-07-24 10:17:54 -070034from cros.factory.gooftool import report_upload
Andy Cheng8ece7382012-08-22 16:25:42 +080035from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080036from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
henryhsu44d793a2013-07-20 00:07:38 +080037from cros.factory.gooftool.probe import CalculateFirmwareHashes
Jon Salz193d7c62013-03-07 13:40:19 +080038from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080039from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
40from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070041from cros.factory.hwdb import hwid_tool
Hung-Te Linca61e732014-08-27 10:27:25 +080042from cros.factory.hwdb.yaml_datastore import YamlWrite
Ricky Liangeede7922013-06-19 10:18:41 +080043from cros.factory.hwid import common
Ricky Liangc662be32013-12-24 11:50:23 +080044from cros.factory.hwid import hwid_utils
Hung-Te Lin91492a12014-11-25 18:56:30 +080045from cros.factory.test import event_log
Jon Salz40b9f822014-07-25 16:39:55 +080046from cros.factory.test import factory
Jon Salzfe9036f2014-01-16 14:11:23 +080047from cros.factory.test.factory import FACTORY_LOG_PATH, DEVICE_STATEFUL_PATH
Jon Salz40b9f822014-07-25 16:39:55 +080048from cros.factory.utils import file_utils
Jon Salzff88c022012-11-03 12:19:58 +080049from cros.factory.utils.process_utils import Spawn
Joel Kitchingd3bc2662014-12-16 16:03:32 -080050from cros.factory.utils.type_utils import Error
Jon Salz8baad8b2013-03-11 20:01:45 +080051from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080052
Tammo Spalink5c699832012-07-03 17:50:39 +080053
Tammo Spalink5c699832012-07-03 17:50:39 +080054# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
55# treat that specially (as a smoot exit, as opposed to the more
56# verbose output for generic Error).
57
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080058_global_gooftool = None
59_gooftool_lock = threading.Lock()
Tammo Spalink5c699832012-07-03 17:50:39 +080060
Hung-Te Lin56b18402015-01-16 14:52:30 +080061
Ricky Lianga70a1202013-03-15 15:03:17 +080062def GetGooftool(options):
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080063 global _global_gooftool # pylint: disable=W0603
Ricky Lianga70a1202013-03-15 15:03:17 +080064
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080065 if _global_gooftool is None:
66 with _gooftool_lock:
Ricky Liang43b879b2014-02-24 11:36:55 +080067 hwid_version = getattr(options, 'hwid_version', 3)
68 if hwid_version == 2:
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080069 hwdb_path = getattr(options, 'hwdb_path', None)
70 component_db = (
71 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path
72 else None)
73 _global_gooftool = Gooftool(hwid_version=2, component_db=component_db)
Ricky Liang43b879b2014-02-24 11:36:55 +080074 elif hwid_version == 3:
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080075 board = getattr(options, 'board', None)
76 hwdb_path = getattr(options, 'hwdb_path', None)
77 _global_gooftool = Gooftool(hwid_version=3, board=board,
78 hwdb_path=hwdb_path)
79 else:
80 raise Error, 'Invalid HWID version: %r' % options.hwid_version
81
82 return _global_gooftool
Ricky Lianga70a1202013-03-15 15:03:17 +080083
Hung-Te Lin56b18402015-01-16 14:52:30 +080084
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080085@Command('write_hwid',
86 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080087def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080088 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080089
Tammo Spalink95c43732012-07-25 15:57:14 -070090 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080091 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080092 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070093 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080094
95
Ricky Liang53390232013-03-08 15:37:57 +080096_board_cmd_arg = CmdArg(
97 '--board', metavar='BOARD',
98 default=None, help='Board name to test.')
99
Tammo Spalink8fab5312012-05-28 18:33:30 +0800100_hwdb_path_cmd_arg = CmdArg(
101 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +0800102 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +0800103 help='Path to the HWID database.')
104
Tammo Spalink95c43732012-07-25 15:57:14 -0700105_hwid_status_list_cmd_arg = CmdArg(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800106 '--status', nargs='*', default=['supported'],
107 help='allow only HWIDs with these status values')
Tammo Spalink95c43732012-07-25 15:57:14 -0700108
Jon Salzce124fb2012-10-02 17:42:03 +0800109_probe_results_cmd_arg = CmdArg(
110 '--probe_results', metavar='RESULTS.yaml',
Ricky Liangc662be32013-12-24 11:50:23 +0800111 help=('Output from "gooftool probe --include_vpd" (used instead of '
Jon Salzce124fb2012-10-02 17:42:03 +0800112 'probing this system).'))
113
Ricky Liang53390232013-03-08 15:37:57 +0800114_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +0800115 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +0800116 help='A dict of device info to use instead of fetching from shopfllor '
117 'server.')
118
Jon Salzce124fb2012-10-02 17:42:03 +0800119_hwid_cmd_arg = CmdArg(
120 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800121 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800122
Bernie Thompson3c11c872013-07-22 18:22:45 -0700123_rma_mode_cmd_arg = CmdArg(
124 '--rma_mode', action='store_true',
125 help='Enable RMA mode, do not check for deprecated components.')
Tammo Spalink95c43732012-07-25 15:57:14 -0700126
Ricky Liang43b879b2014-02-24 11:36:55 +0800127_hwid_version_cmd_arg = CmdArg(
128 '-i', '--hwid-version', default=3, choices=(2, 3), type=int,
129 help='Version of HWID to operate on. (default: %(default)s)')
130
131
Tammo Spalink95c43732012-07-25 15:57:14 -0700132@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800133 _hwdb_path_cmd_arg,
134 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700135 help='optional BOARD name, needed only if data is present '
136 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800137 CmdArg('--bom', metavar='BOM', help='BOM name'),
138 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800139 CmdArg('--optimistic', action='store_true',
140 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700141 CmdArg('--comps', nargs='*', default=[],
142 help='list of canonical component names'),
143 CmdArg('--missing', nargs='*', default=[],
144 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800145 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700146 help='consider only HWIDs within this list of status values'))
147def BestMatchHwids(options):
Ricky Liangc662be32013-12-24 11:50:23 +0800148 """Determine a list of possible HWIDs using provided args and probing.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800149
150 VOLATILE can always be determined by probing. To get a unique
151 result, VARIANT must be specified for all cases where the matching
152 BOM has more than one associated variant code, otherwise all HWID
153 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700154 alternatively be specified using the --stdin_comps argument, which
155 allows specifying a list of canonical names (one per line) on stdin,
156 one per line. Based on what is known from BOM and stdin_comps,
157 determine a list of components to probe for, and use those probe
158 results to resolve a list of matching HWIDs. If no boms,
159 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800160 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800161
162 Returns (on stdout): A list of HWIDs that match the available probe
163 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700164
165 Example:
166
167 // Three ways to specify a keyboard (assuming it is a variant component)
168 gooftool best_match_hwids --missing keyboard
169 gooftool best_match_hwids --variant A or
170 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800171 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800172
Tammo Spalink5c699832012-07-03 17:50:39 +0800173 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700174 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800175 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800176 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800177 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800178 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800179 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700180 component_spec = hwid_tool.CombineComponentSpecs(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800181 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800182 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800183 device.VariantExists(options.variant)
184 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700185 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700186 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700187 % YamlWrite(sorted(
188 hwid_tool.ComponentSpecClasses(component_spec) &
189 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700190 component_spec = hwid_tool.CombineComponentSpecs(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800191 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700192 if options.comps or options.missing:
193 map(comp_db.CompExists, options.comps)
194 map(comp_db.CompClassExists, options.missing)
195 extra_comp_spec = comp_db.CreateComponentSpec(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800196 components=options.comps,
197 missing=options.missing)
Tammo Spalink95c43732012-07-25 15:57:14 -0700198 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
199 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
200 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700201 % YamlWrite(sorted(
202 hwid_tool.ComponentSpecClasses(component_spec) &
203 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700204 component_spec = hwid_tool.CombineComponentSpecs(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800205 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700206 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700207 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800208 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800209 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
210 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700211 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700212 'as inputs, and cannot be probed for:\n%s'
213 'This problem can often be addressed by specifying all of '
214 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800215 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700216 print 'probing for missing classes:'
217 print YamlWrite(list(missing_classes))
218 probe_results = Probe(target_comp_classes=list(missing_classes),
219 probe_volatile=False, probe_initial_config=False)
220 cooked_components = comp_db.MatchComponentProbeValues(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800221 probe_results.found_probe_value_map)
Tammo Spalink95c43732012-07-25 15:57:14 -0700222 if cooked_components.unmatched:
223 sys.exit('ERROR: some probed components are unrecognized:\n%s'
224 % YamlWrite(cooked_components.unmatched))
225 probed_comp_spec = comp_db.CreateComponentSpec(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800226 components=cooked_components.matched,
227 missing=probe_results.missing_component_classes)
Tammo Spalink95c43732012-07-25 15:57:14 -0700228 component_spec = hwid_tool.CombineComponentSpecs(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800229 component_spec, probed_comp_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700230 print YamlWrite({'component data used for matching': {
Hung-Te Lin56b18402015-01-16 14:52:30 +0800231 'missing component classes': component_spec.classes_missing,
232 'found components': component_spec.components}})
Tammo Spalink95c43732012-07-25 15:57:14 -0700233 component_data = hwid_tool.ComponentData(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800234 extant_components=hwid_tool.ComponentSpecCompClassMap(
235 component_spec).keys(),
236 classes_missing=component_spec.classes_missing)
Tammo Spalink95c43732012-07-25 15:57:14 -0700237 match_tree = device.BuildMatchTree(component_data)
238 if not match_tree:
239 sys.exit('FAILURE: NO matching BOMs found')
240 print 'potential BOMs/VARIANTs:'
241 potential_variants = set()
242 potential_volatiles = set()
243 for bom_name, variant_tree in match_tree.items():
244 print ' BOM: %-8s VARIANTS: %s' % (
Hung-Te Lin56b18402015-01-16 14:52:30 +0800245 bom_name, ', '.join(sorted(variant_tree)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700246 for variant_code in variant_tree:
247 potential_variants.add(variant_code)
248 for volatile_code in device.volatiles:
249 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
250 if status in options.status:
251 potential_volatiles.add(volatile_code)
252 print ''
253 if len(potential_variants) == 0:
254 sys.exit('FAILURE: no matching VARIANTs found')
255 if len(potential_volatiles) == 0:
256 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
257 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700258 if (options.optimistic and
259 len(match_tree) == 1 and
260 len(potential_variants) == 1 and
261 len(potential_volatiles) == 1):
262 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
263 potential_variants.pop(),
264 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800265 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700266 print ('probing VOLATILEs to resolve potential matches: %s\n' %
267 ', '.join(sorted(potential_volatiles)))
268 vol_probe_results = Probe(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800269 target_comp_classes=[],
270 probe_volatile=True,
271 probe_initial_config=False)
Tammo Spalink95c43732012-07-25 15:57:14 -0700272 cooked_volatiles = device.MatchVolatileValues(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800273 vol_probe_results.found_volatile_values)
Tammo Spalink95c43732012-07-25 15:57:14 -0700274 match_tree = device.BuildMatchTree(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800275 component_data, cooked_volatiles.matched_tags)
Tammo Spalink95c43732012-07-25 15:57:14 -0700276 matched_hwids = device.GetMatchTreeHwids(match_tree)
277 if matched_hwids:
278 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800279 if matched_hwids[hwid] in options.status:
280 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700281 return
282 print 'exact HWID matching failed, but the following BOMs match: %s' % (
Hung-Te Lin56b18402015-01-16 14:52:30 +0800283 ', '.join(sorted(match_tree)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700284 if options.optimistic and len(match_tree) == 1:
285 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800286 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700287 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800288 if len(variant_matches) == 1:
289 var_code = set(variant_matches).pop()
290 elif len(bom.variants) == 1:
291 var_code = set(bom.variants).pop()
292 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700293 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
294 'because there were too many variants to choose from for BOM %r'
295 % bom_name)
296 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
297 for vol_code in device.volatiles
298 if device.GetHwidStatus(bom_name, var_code, vol_code)
299 in options.status]
300 for hwid in hwids:
301 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800302 return
303 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700304 print ('optimistic matching not attempted because either it was '
305 'not requested, or because the number of BOMs was <> 1\n')
306 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800307
308
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800309@Command('probe',
310 CmdArg('--comps', nargs='*',
311 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800312 CmdArg('--fast_fw_probe', action='store_true',
313 help='Do a fast probe for EC and main firmware versions only. '
314 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800315 CmdArg('--no_vol', action='store_true',
316 help='Do not probe volatile data.'),
317 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800318 help='Do not probe initial_config data.'),
319 CmdArg('--include_vpd', action='store_true',
320 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800321def RunProbe(options):
322 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800323 print GetGooftool(options).Probe(
324 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800325 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800326 probe_volatile=not options.no_vol,
327 probe_initial_config=not options.no_ic,
328 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800329
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800330
Tammo Spalink214caf42012-05-28 10:45:00 +0800331@Command('verify_components',
332 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800333 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800334def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800335 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800336
Tammo Spalink5c699832012-07-03 17:50:39 +0800337 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800338 that a corresponding match exists in the component_db -- make sure
339 that these components are present, that they have been approved, but
340 do not check against any specific BOM/HWID configurations.
341 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800342
Andy Chengc531e2f2012-10-15 19:09:17 +0800343 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800344 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800345 options.target_comps)
346 except ValueError, e:
347 sys.exit(e)
348
Ricky Liang53390232013-03-08 15:37:57 +0800349 PrintVerifyComponentsResults(result)
350
351
352def PrintVerifyComponentsResults(result):
353 """Prints out the results of VerifyComponents method call.
354
355 Groups the results into two groups: 'matches' and 'errors', and prints out
356 their values.
357 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800358 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800359 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800360 errors = []
361 for result_list in result.values():
362 for component_name, _, error in result_list:
363 if component_name:
364 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800365 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800366 errors.append(error)
367
Andy Cheng228a8c92012-08-27 10:53:57 +0800368 if matches:
369 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800370 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800371 print '\nerrors:\n %s' % '\n '.join(errors)
372 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800373 else:
Hung-Te Lin56b18402015-01-16 14:52:30 +0800374 print '\ncomponent verification SUCCESS'
Tammo Spalink214caf42012-05-28 10:45:00 +0800375
376
Ricky Liang43b879b2014-02-24 11:36:55 +0800377@Command('verify_hwid_v2',
Tammo Spalink95c43732012-07-25 15:57:14 -0700378 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800379 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800380 _probe_results_cmd_arg,
381 _hwid_cmd_arg)
Ricky Liang43b879b2014-02-24 11:36:55 +0800382def VerifyHWIDv2(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800383 """Verify system HWID properties match probed device properties.
384
385 First probe components, volatile and initial_config parameters for
386 the DUT. Then use the available device data to produce a list of
387 candidate HWIDs. Then verify the HWID from the DUT is present in
388 that list. Then verify that the DUT initial config values match
389 those specified for its HWID. Finally, verify that VPD contains all
390 the necessary fields as specified by the board data, and when
391 possible verify that values are legitimate.
392 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800393 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800394 for key in ro_vpd_keys:
395 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800396 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700397 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800398 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800399 if (known_valid_values is not None) and (value not in known_valid_values):
400 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800401 for key in rw_vpd_keys:
402 if key not in rw_vpd:
403 sys.exit('Missing required RW VPD field: %s' % key)
404 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
405 value = rw_vpd[key]
406 if (known_valid_values is not None) and (value not in known_valid_values):
407 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800408 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800409 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800410
Jon Salz81350812012-10-11 16:13:22 +0800411 if not options.hwid or not options.probe_results:
412 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800413
414 if options.hwid:
415 hwid_str = options.hwid
416 else:
417 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
418 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700419 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800420 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800421 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700422 device = hw_db.GetDevice(hwid.board)
423 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
424 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800425 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800426 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800427 if options.probe_results:
428 # Pull in probe results (including VPD data) from the given file
429 # rather than probing the current system.
430 probe_results = hwid_tool.ProbeResults.Decode(
431 open(options.probe_results).read())
432 ro_vpd = {}
433 rw_vpd = {}
434 for k, v in probe_results.found_volatile_values.items():
Hung-Te Lin56b18402015-01-16 14:52:30 +0800435 match = re.match(r'^vpd\.(ro|rw)\.(\w+)$', k)
Jon Salz0f8a6842012-09-25 11:28:22 +0800436 if match:
437 del probe_results.found_volatile_values[k]
438 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
439 else:
440 probe_results = Probe()
441 ro_vpd = ReadRoVpd(main_fw_file)
442 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700443 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800444 probe_results.found_probe_value_map)
Tammo Spalink95c43732012-07-25 15:57:14 -0700445 cooked_volatiles = device.MatchVolatileValues(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800446 probe_results.found_volatile_values)
Tammo Spalink95c43732012-07-25 15:57:14 -0700447 cooked_initial_configs = device.MatchInitialConfigValues(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800448 probe_results.initial_configs)
Tammo Spalink95c43732012-07-25 15:57:14 -0700449 component_data = hwid_tool.ComponentData(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800450 extant_components=cooked_components.matched,
451 classes_missing=probe_results.missing_component_classes)
Tammo Spalink95c43732012-07-25 15:57:14 -0700452 match_tree = device.BuildMatchTree(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800453 component_data, cooked_volatiles.matched_tags)
Tammo Spalink95c43732012-07-25 15:57:14 -0700454 matched_hwids = device.GetMatchTreeHwids(match_tree)
455 print 'HWID status: %s\n' % hwid_status
456 print 'probed system components:'
457 print YamlWrite(cooked_components.__dict__)
458 print 'missing component classes:'
459 print YamlWrite(probe_results.missing_component_classes)
460 print 'probed volatiles:'
461 print YamlWrite(cooked_volatiles.__dict__)
462 print 'probed initial_configs:'
463 print YamlWrite(cooked_initial_configs)
464 print 'hwid match tree:'
465 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800466 event_log.Log(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800467 'probe',
468 found_components=cooked_components.__dict__,
469 missing_component_classes=probe_results.missing_component_classes,
470 volatiles=cooked_volatiles.__dict__,
471 initial_configs=cooked_initial_configs)
Tammo Spalink95c43732012-07-25 15:57:14 -0700472 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800473 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700474 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800475 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700476 YamlWrite(cooked_components.unmatched))
477 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800478 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700479 component_data.Encode())
480 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800481 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700482 (', '.join(sorted(match_tree)), hwid.bom))
483 err_msg += 'target bom %r matches components' % hwid.bom
484 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
Hung-Te Lin56b18402015-01-16 14:52:30 +0800485 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800486 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700487 matched_variants = match_tree.get(hwid.bom, {})
488 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800489 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700490 hwid.variant)
491 matched_volatiles = matched_variants.get(hwid.variant, {})
492 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800493 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700494 hwid.volatile)
495 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800496 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800497 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800498 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700499 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800500
501
502@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700503def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800504 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800505
Ricky Lianga70a1202013-03-15 15:03:17 +0800506 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800507
508
509@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700510def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800511 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800512
Ricky Lianga70a1202013-03-15 15:03:17 +0800513 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800514 logging.info('Firmware bitmap initial locale set to %d (%s).',
515 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800516
517
518@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700519def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800520 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800521
Ricky Lianga70a1202013-03-15 15:03:17 +0800522 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800523
524
525@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700526def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800527 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800528
Ricky Lianga70a1202013-03-15 15:03:17 +0800529 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800530
Hung-Te Lin56b18402015-01-16 14:52:30 +0800531
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800532@Command('verify_tpm')
533def VerifyTPM(options): # pylint: disable=W0613
534 """Verify TPM is cleared."""
535
536 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800537
Hung-Te Lin56b18402015-01-16 14:52:30 +0800538
Hung-Te Lindd708d42014-07-11 17:05:01 +0800539@Command('verify_me_locked')
540def VerifyManagementEngineLocked(options): # pylint: disable=W0613
541 """Verify Managment Engine is locked."""
542
543 return GetGooftool(options).VerifyManagementEngineLocked()
544
Hung-Te Lin56b18402015-01-16 14:52:30 +0800545
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800546@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800547def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800548 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800549
Ricky Lianga70a1202013-03-15 15:03:17 +0800550 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800551
552
553@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700554def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800555 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800556
Ricky Lianga70a1202013-03-15 15:03:17 +0800557 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800558 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800559 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800560
561
Jon Salzadd90d32014-04-29 16:16:27 +0800562@Command('verify_branding')
563def VerifyBranding(options): # pylint: disable=W0613
564 """Verify that branding fields are properly set.
565
566 customization_id, if set in the RO VPD, must be of the correct format.
567
568 rlz_brand_code must be set either in the RO VPD or OEM partition, and must
569 be of the correct format.
570 """
571 return GetGooftool(options).VerifyBranding()
572
573
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800574@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700575def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800576 """Enable then verify firmware write protection."""
577
Hung-Te Linb21c6682012-08-01 13:53:57 +0800578 def CalculateLegacyRange(fw_type, length, section_data,
579 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800580 ro_size = length / 2
581 ro_a = int(section_data[0] / ro_size)
582 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
583 if ro_a != ro_b:
Hung-Te Lin56b18402015-01-16 14:52:30 +0800584 raise Error('%s firmware section %s has illegal size' %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800585 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800586 ro_offset = ro_a * ro_size
587 return (ro_offset, ro_size)
588
589 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800590 """Calculate protection size, then invoke flashrom.
591
592 Our supported chips only allow write protecting half their total
593 size, so we parition the flash chipset space accordingly.
594 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800595
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800596 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800597 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800598 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800599 if image.has_section(wp_section):
600 section_data = image.get_section_area(wp_section)
601 ro_offset = section_data[0]
602 ro_size = section_data[1]
603 elif image.has_section(legacy_section):
604 section_data = image.get_section_area(legacy_section)
605 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800606 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800607 else:
608 raise Error('could not find %s firmware section %s or %s' %
609 (fw_type, wp_section, legacy_section))
610
611 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
612 ro_offset, ro_size)
613 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800614
615 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800616 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800617 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
618 if ec_fw_file is not None:
619 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800620 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800621 else:
622 logging.warning('EC not write protected (seems there is no EC flash).')
623
624
625@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800626def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800627 """Zero out the GBB flags, in preparation for transition to release state.
628
629 No GBB flags are set in release/shipping state, but they are useful
630 for factory/development. See "gbb_utility --flags" for details.
631 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800632
Ricky Lianga70a1202013-03-15 15:03:17 +0800633 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800634 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800635
636
Jon Salzaa3a30e2013-05-15 15:56:28 +0800637@Command('clear_factory_vpd_entries')
638def ClearFactoryVPDEntries(options): # pylint: disable=W0613
639 """Clears factory.* items in the RW VPD."""
640 entries = GetGooftool(options).ClearFactoryVPDEntries()
641 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
642
643
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800644@Command('prepare_wipe',
645 CmdArg('--fast', action='store_true',
646 help='use non-secure but faster wipe method.'))
647def PrepareWipe(options):
648 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800649
Ricky Lianga70a1202013-03-15 15:03:17 +0800650 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800651
Hung-Te Lin56b18402015-01-16 14:52:30 +0800652
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800653@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800654 CmdArg('--no_write_protect', action='store_true',
655 help='Do not check write protection switch state.'),
Ricky Liang43b879b2014-02-24 11:36:55 +0800656 _hwid_version_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700657 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800658 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800659 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800660 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800661 _hwid_cmd_arg,
662 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800663def Verify(options):
664 """Verifies if whole factory process is ready for finalization.
665
666 This routine performs all the necessary checks to make sure the
667 device is ready to be finalized, but does not modify state. These
668 checks include dev switch, firmware write protection switch, hwid,
669 system time, keys, and root file system.
670 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800671
Hung-Te Lin6d827542012-07-19 11:50:41 +0800672 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800673 VerifyWPSwitch(options)
Hung-Te Lindd708d42014-07-11 17:05:01 +0800674 VerifyManagementEngineLocked(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800675 VerifyDevSwitch(options)
676 if options.hwid_version == 2:
Ricky Liang43b879b2014-02-24 11:36:55 +0800677 VerifyHWIDv2(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800678 elif options.hwid_version == 3:
Ricky Liangc662be32013-12-24 11:50:23 +0800679 VerifyHWIDv3(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800680 else:
681 raise Error, 'Invalid HWID version: %r' % options.hwid_version
682 VerifySystemTime(options)
683 VerifyKeys(options)
684 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800685 VerifyTPM(options)
Jon Salzadd90d32014-04-29 16:16:27 +0800686 VerifyBranding(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800687
Hung-Te Lin56b18402015-01-16 14:52:30 +0800688
Jon Salzfe9036f2014-01-16 14:11:23 +0800689@Command('untar_stateful_files')
Hung-Te Lin388bce22014-06-03 19:56:40 +0800690def UntarStatefulFiles(unused_options):
Jon Salzfe9036f2014-01-16 14:11:23 +0800691 """Untars stateful files from stateful_files.tar.xz on stateful partition.
692
693 If that file does not exist (which should only be R30 and earlier),
694 this is a no-op.
695 """
696 tar_file = os.path.join(DEVICE_STATEFUL_PATH, 'stateful_files.tar.xz')
697 if os.path.exists(tar_file):
698 Spawn(['tar', 'xf', tar_file], cwd=DEVICE_STATEFUL_PATH,
699 log=True, check_call=True)
700 else:
701 logging.warning('No stateful files at %s', tar_file)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800702
Jon Salz40b9f822014-07-25 16:39:55 +0800703
704@Command('log_source_hashes')
705def LogSourceHashes(options): # pylint: disable=W0613
706 """Logs hashes of source files in the factory toolkit."""
Jon Salze60307f2014-08-05 16:20:00 +0800707 # WARNING: The following line is necessary to validate the integrity
708 # of the factory software. Do not remove or modify it.
709 #
710 # 警告:此行会验证工厂软件的完整性,禁止删除或修改。
Jon Salz40b9f822014-07-25 16:39:55 +0800711 event_log.Log(
712 'source_hashes',
Jon Salz9596ae02014-07-29 14:25:49 +0800713 **file_utils.HashSourceTree(os.path.join(factory.FACTORY_PATH, 'py')))
Jon Salz40b9f822014-07-25 16:39:55 +0800714
715
Tammo Spalink86a61c62012-05-25 15:10:35 +0800716@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700717def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800718 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800719
Ricky Liang43b879b2014-02-24 11:36:55 +0800720 event_log.Log('system_details', **GetGooftool(options).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800721
722
Jon Salza88b83b2013-05-27 20:00:35 +0800723def CreateReportArchiveBlob(*args, **kwargs):
724 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800725
Jon Salza88b83b2013-05-27 20:00:35 +0800726 Args:
727 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800728
Jon Salza88b83b2013-05-27 20:00:35 +0800729 Returns:
730 An xmlrpclib.Binary object containing a .tar.xz file.
731 """
732 with open(CreateReportArchive(*args, **kwargs)) as f:
733 return xmlrpclib.Binary(f.read())
734
735
736def CreateReportArchive(device_sn=None, add_file=None):
737 """Creates a report archive in a temporary directory.
738
739 Args:
740 device_sn: The device serial number (optional).
741 add_file: A list of files to add (optional).
742
743 Returns:
744 Path to the archive.
745 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800746 def NormalizeAsFileName(token):
747 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800748
749 target_name = '%s%s.tar.xz' % (
750 time.strftime('%Y%m%dT%H%M%SZ',
751 time.gmtime()),
Hung-Te Lin56b18402015-01-16 14:52:30 +0800752 ('' if device_sn is None else
753 '_' + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800754 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800755
Tammo Spalink86a61c62012-05-25 15:10:35 +0800756 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800757 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800758 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800759 if add_file:
760 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800761 # Require absolute paths since the tar command may change the
762 # directory.
763 if not f.startswith('/'):
764 raise Error('Not an absolute path: %s' % f)
765 if not os.path.exists(f):
766 raise Error('File does not exist: %s' % f)
767 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800768 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800769
770 if ((cmd_result.status == 1) and
771 all((x == '' or
772 'file changed as we read it' in x or
773 "Removing leading `/' from member names" in x)
774 for x in cmd_result.stderr.split('\n'))):
775 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800776 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800777 ignore_stdout=True)
778 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800779 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
780 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800781
Jon Salza88b83b2013-05-27 20:00:35 +0800782 return target_path
783
784_upload_method_cmd_arg = CmdArg(
785 '--upload_method', metavar='METHOD:PARAM',
786 help=('How to perform the upload. METHOD should be one of '
787 '{ftp, shopfloor, ftps, cpfe}.'))
788_add_file_cmd_arg = CmdArg(
789 '--add_file', metavar='FILE', action='append',
790 help='Extra file to include in report (must be an absolute path)')
791
Hung-Te Lin56b18402015-01-16 14:52:30 +0800792
Jon Salza88b83b2013-05-27 20:00:35 +0800793@Command('upload_report',
794 _upload_method_cmd_arg,
795 _add_file_cmd_arg)
796def UploadReport(options):
797 """Create a report containing key device details."""
798 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
799 device_sn = ro_vpd.get('serial_number', None)
800 if device_sn is None:
801 logging.warning('RO_VPD missing device serial number')
802 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
803 target_path = CreateReportArchive(device_sn)
804
Tammo Spalink86a61c62012-05-25 15:10:35 +0800805 if options.upload_method is None or options.upload_method == 'none':
806 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
807 return
808 method, param = options.upload_method.split(':', 1)
809 if method == 'shopfloor':
810 report_upload.ShopFloorUpload(target_path, param)
811 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700812 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800813 elif method == 'ftps':
814 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
815 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800816 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800817 else:
818 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800819
820
821@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800822 CmdArg('--no_write_protect', action='store_true',
823 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800824 CmdArg('--fast', action='store_true',
825 help='use non-secure but faster wipe method.'),
Ricky Liang43b879b2014-02-24 11:36:55 +0800826 _hwid_version_cmd_arg,
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800827 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700828 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800829 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800830 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800831 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800832 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800833 _hwid_cmd_arg,
834 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800835def Finalize(options):
836 """Verify system readiness and trigger transition into release state.
837
Jon Salzaa3a30e2013-05-15 15:56:28 +0800838 This routine does the following:
839 - Verifies system state (see verify command)
Jon Salzfe9036f2014-01-16 14:11:23 +0800840 - Untars stateful_files.tar.xz, if it exists, in the stateful partition, to
841 initialize files such as the CRX cache
Jon Salzaa3a30e2013-05-15 15:56:28 +0800842 - Modifies firmware bitmaps to match locale
843 - Clears all factory-friendly flags from the GBB
844 - Removes factory-specific entries from RW_VPD (factory.*)
845 - Enables firmware write protection (cannot rollback after this)
846 - Uploads system logs & reports
847 - Sets the necessary boot flags to cause wipe of the factory image on the
848 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800849 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800850 Verify(options)
Jon Salz40b9f822014-07-25 16:39:55 +0800851 LogSourceHashes(options)
Jon Salzfe9036f2014-01-16 14:11:23 +0800852 UntarStatefulFiles(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800853 SetFirmwareBitmapLocale(options)
854 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800855 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800856 if options.no_write_protect:
857 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800858 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800859 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800860 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800861 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800862 UploadReport(options)
863 PrepareWipe(options)
864
865
Ricky Liangc662be32013-12-24 11:50:23 +0800866def VerifyHWIDv3(options):
867 """A simple wrapper that calls out to HWID utils to verify version 3 HWID.
Ricky Liang53390232013-03-08 15:37:57 +0800868
Ricky Liangc662be32013-12-24 11:50:23 +0800869 This is mainly for Gooftool to verify v3 HWID during finalize. For testing
870 and development purposes, please use `hwid` command.
Ricky Liang53390232013-03-08 15:37:57 +0800871 """
Ricky Liangc662be32013-12-24 11:50:23 +0800872 db = GetGooftool(options).db
873 encoded_string = options.hwid or hwid_utils.GetHWIDString()
Ricky Liang7905f272013-03-16 01:57:10 +0800874 if options.probe_results:
Ricky Liangc662be32013-12-24 11:50:23 +0800875 probed_results = yaml.load(open(options.probe_results).read())
Ricky Liang7905f272013-03-16 01:57:10 +0800876 else:
Ricky Liangc662be32013-12-24 11:50:23 +0800877 probed_results = yaml.load(Probe(probe_vpd=True).Encode())
878 vpd = hwid_utils.GetVPD(probed_results)
Ricky Liang53390232013-03-08 15:37:57 +0800879
Ricky Liangc662be32013-12-24 11:50:23 +0800880 event_log.Log('probed_results', probed_results=probed_results)
881 event_log.Log('vpd', vpd=vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800882
Ricky Liangc662be32013-12-24 11:50:23 +0800883 hwid_utils.VerifyHWID(db, encoded_string, probed_results, vpd,
Hung-Te Lin56b18402015-01-16 14:52:30 +0800884 rma_mode=options.rma_mode)
Ricky Liang53390232013-03-08 15:37:57 +0800885
Ricky Liangc662be32013-12-24 11:50:23 +0800886 event_log.Log('verified_hwid', hwid=encoded_string)
Ricky Liang53390232013-03-08 15:37:57 +0800887
888
Ricky Liang59611a62013-06-11 13:47:33 +0800889def ParseDecodedHWID(hwid):
890 """Parse the HWID object into a more compact dict.
891
892 Args:
893 hwid: A decoded HWID object.
894
895 Returns:
896 A dict containing the board name, the binary string, and the list of
897 components.
898 """
899 results = {}
900 results['board'] = hwid.database.board
901 results['binary_string'] = hwid.binary_string
902 results['components'] = collections.defaultdict(list)
903 components = hwid.bom.components
904 for comp_cls in sorted(components):
905 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
906 if not probed_values:
907 db_components = hwid.database.components
908 probed_values = db_components.GetComponentAttributes(
909 comp_cls, comp_name).get('values')
910 results['components'][comp_cls].append(
911 {comp_name: probed_values if probed_values else None})
912 # Convert defaultdict to dict.
913 results['components'] = dict(results['components'])
914 return results
915
916
henryhsu44d793a2013-07-20 00:07:38 +0800917@Command('get_firmware_hash',
918 CmdArg('--file', metavar='FILE', help='Firmware File.'))
919def GetFirmwareHash(options):
henryhsuf6f835c2013-07-20 20:49:25 +0800920 """Get firmware hash from a file"""
henryhsu44d793a2013-07-20 00:07:38 +0800921 if os.path.exists(options.file):
922 hashes = CalculateFirmwareHashes(options.file)
923 for section, value_dict in hashes.iteritems():
Hung-Te Lin56b18402015-01-16 14:52:30 +0800924 print '%s:' % section
henryhsu44d793a2013-07-20 00:07:38 +0800925 for key, value in value_dict.iteritems():
Hung-Te Lin56b18402015-01-16 14:52:30 +0800926 print ' %s: %s' % (key, value)
henryhsu44d793a2013-07-20 00:07:38 +0800927 else:
928 raise Error('File does not exist: %s' % options.file)
929
henryhsuf6f835c2013-07-20 20:49:25 +0800930
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800931def Main():
932 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800933
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800934 options = ParseCmdline(
Ricky Liangc662be32013-12-24 11:50:23 +0800935 ('Perform Google required factory tests. All the HWID-related functions '
936 'provided here are mainly for the deprecated HWID v2. To access HWID '
937 'v3-related utilities, please use `hwid` command.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800938 CmdArg('-l', '--log', metavar='PATH',
939 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800940 CmdArg('--suppress-event-logs', action='store_true',
941 help='Suppress event logging.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800942 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800943 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800944 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
945 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800946 logging.debug('gooftool options: %s', repr(options))
947 try:
948 logging.debug('GOOFTOOL command %r', options.command_name)
949 options.command(options)
950 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
951 except Error, e:
952 logging.exception(e)
953 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
954 except Exception, e:
955 logging.exception(e)
956 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
957
958
959if __name__ == '__main__':
960 Main()