blob: 66fb61019059f9c5dd2a0f73d1649cb564ef89d9 [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Tammo Spalink01e11722012-07-24 10:17:54 -07002# pylint: disable=E1101
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08003#
4# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Google Factory Tool.
9
10This tool is indended to be used on factory assembly lines. It
11provides all of the Google required test functionality and must be run
12on each device as part of the assembly process.
13"""
14
Ricky Liang5b4568d2013-04-23 17:15:23 +080015import collections
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080016import logging
17import os
Jon Salz65266432012-07-30 19:02:49 +080018import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080019import re
20import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080021import time
Jon Salza88b83b2013-05-27 20:00:35 +080022import xmlrpclib
Ricky Liang7905f272013-03-16 01:57:10 +080023import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080024
Andy Cheng2582d292012-12-04 17:38:28 +080025from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080026
Tammo Spalinka40293e2012-07-04 14:58:56 +080027import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080028
Andy Cheng0465d132013-03-20 12:12:06 +080029from cros.factory import event_log
Jon Salz0f8a6842012-09-25 11:28:22 +080030from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070031from cros.factory.common import YamlWrite
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
Ricky Liangeede7922013-06-19 10:18:41 +080042from cros.factory.hwid import common
Ricky Liangf1ded8a2013-06-25 11:29:01 +080043from cros.factory.test import shopfloor
cychiang7fe09372012-07-04 14:31:23 +080044from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080045from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080046from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080047
Tammo Spalink5c699832012-07-03 17:50:39 +080048
Tammo Spalink5c699832012-07-03 17:50:39 +080049# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
50# treat that specially (as a smoot exit, as opposed to the more
51# verbose output for generic Error).
52
53
Ricky Lianga70a1202013-03-15 15:03:17 +080054def GetGooftool(options):
55 if options.hwid_version == 2:
56 hwdb_path = getattr(options, 'hwdb_path', None)
57 component_db = (
58 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
59 return Gooftool(hwid_version=2, component_db=component_db)
60 elif options.hwid_version == 3:
61 board = getattr(options, 'board', None)
62 hwdb_path = getattr(options, 'hwdb_path', None)
63 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
64 else:
65 raise Error, 'Invalid HWID version: %r' % options.hwid_version
66
67
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080068@Command('write_hwid',
69 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080070def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080071 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080072
Tammo Spalink95c43732012-07-25 15:57:14 -070073 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080074 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080075 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070076 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080077
78
Ricky Liang53390232013-03-08 15:37:57 +080079_board_cmd_arg = CmdArg(
80 '--board', metavar='BOARD',
81 default=None, help='Board name to test.')
82
Tammo Spalink8fab5312012-05-28 18:33:30 +080083_hwdb_path_cmd_arg = CmdArg(
84 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +080085 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +080086 help='Path to the HWID database.')
87
Tammo Spalink95c43732012-07-25 15:57:14 -070088_hwid_status_list_cmd_arg = CmdArg(
89 '--status', nargs='*', default=['supported'],
90 help='allow only HWIDs with these status values')
91
Jon Salzce124fb2012-10-02 17:42:03 +080092_probe_results_cmd_arg = CmdArg(
93 '--probe_results', metavar='RESULTS.yaml',
94 help=('Output from "gooftool probe" (used instead of '
95 'probing this system).'))
96
Ricky Liang53390232013-03-08 15:37:57 +080097_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080098 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +080099 help='A dict of device info to use instead of fetching from shopfllor '
100 'server.')
101
Jon Salzce124fb2012-10-02 17:42:03 +0800102_hwid_cmd_arg = CmdArg(
103 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800104 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800105
Bernie Thompson3c11c872013-07-22 18:22:45 -0700106_rma_mode_cmd_arg = CmdArg(
107 '--rma_mode', action='store_true',
108 help='Enable RMA mode, do not check for deprecated components.')
Tammo Spalink95c43732012-07-25 15:57:14 -0700109
110@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800111 _hwdb_path_cmd_arg,
112 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700113 help='optional BOARD name, needed only if data is present '
114 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800115 CmdArg('--bom', metavar='BOM', help='BOM name'),
116 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800117 CmdArg('--optimistic', action='store_true',
118 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700119 CmdArg('--comps', nargs='*', default=[],
120 help='list of canonical component names'),
121 CmdArg('--missing', nargs='*', default=[],
122 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800123 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700124 help='consider only HWIDs within this list of status values'))
125def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800126 """Determine a list of possible HWIDs using provided args and probeing.
127
128 VOLATILE can always be determined by probing. To get a unique
129 result, VARIANT must be specified for all cases where the matching
130 BOM has more than one associated variant code, otherwise all HWID
131 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700132 alternatively be specified using the --stdin_comps argument, which
133 allows specifying a list of canonical names (one per line) on stdin,
134 one per line. Based on what is known from BOM and stdin_comps,
135 determine a list of components to probe for, and use those probe
136 results to resolve a list of matching HWIDs. If no boms,
137 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800138 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800139
140 Returns (on stdout): A list of HWIDs that match the available probe
141 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700142
143 Example:
144
145 // Three ways to specify a keyboard (assuming it is a variant component)
146 gooftool best_match_hwids --missing keyboard
147 gooftool best_match_hwids --variant A or
148 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800149 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800150
Tammo Spalink5c699832012-07-03 17:50:39 +0800151 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700152 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800153 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800154 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800155 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800156 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800157 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700158 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800159 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800160 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800161 device.VariantExists(options.variant)
162 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700163 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700164 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700165 % YamlWrite(sorted(
166 hwid_tool.ComponentSpecClasses(component_spec) &
167 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700168 component_spec = hwid_tool.CombineComponentSpecs(
169 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700170 if options.comps or options.missing:
171 map(comp_db.CompExists, options.comps)
172 map(comp_db.CompClassExists, options.missing)
173 extra_comp_spec = comp_db.CreateComponentSpec(
174 components=options.comps,
175 missing=options.missing)
176 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
177 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
178 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700179 % YamlWrite(sorted(
180 hwid_tool.ComponentSpecClasses(component_spec) &
181 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700182 component_spec = hwid_tool.CombineComponentSpecs(
183 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700184 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700185 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800186 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800187 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
188 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700189 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700190 'as inputs, and cannot be probed for:\n%s'
191 'This problem can often be addressed by specifying all of '
192 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800193 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700194 print 'probing for missing classes:'
195 print YamlWrite(list(missing_classes))
196 probe_results = Probe(target_comp_classes=list(missing_classes),
197 probe_volatile=False, probe_initial_config=False)
198 cooked_components = comp_db.MatchComponentProbeValues(
199 probe_results.found_probe_value_map)
200 if cooked_components.unmatched:
201 sys.exit('ERROR: some probed components are unrecognized:\n%s'
202 % YamlWrite(cooked_components.unmatched))
203 probed_comp_spec = comp_db.CreateComponentSpec(
204 components=cooked_components.matched,
205 missing=probe_results.missing_component_classes)
206 component_spec = hwid_tool.CombineComponentSpecs(
207 component_spec, probed_comp_spec)
208 print YamlWrite({'component data used for matching': {
209 'missing component classes': component_spec.classes_missing,
210 'found components': component_spec.components}})
211 component_data = hwid_tool.ComponentData(
212 extant_components=hwid_tool.ComponentSpecCompClassMap(
213 component_spec).keys(),
214 classes_missing=component_spec.classes_missing)
215 match_tree = device.BuildMatchTree(component_data)
216 if not match_tree:
217 sys.exit('FAILURE: NO matching BOMs found')
218 print 'potential BOMs/VARIANTs:'
219 potential_variants = set()
220 potential_volatiles = set()
221 for bom_name, variant_tree in match_tree.items():
222 print ' BOM: %-8s VARIANTS: %s' % (
223 bom_name, ', '.join(sorted(variant_tree)))
224 for variant_code in variant_tree:
225 potential_variants.add(variant_code)
226 for volatile_code in device.volatiles:
227 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
228 if status in options.status:
229 potential_volatiles.add(volatile_code)
230 print ''
231 if len(potential_variants) == 0:
232 sys.exit('FAILURE: no matching VARIANTs found')
233 if len(potential_volatiles) == 0:
234 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
235 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700236 if (options.optimistic and
237 len(match_tree) == 1 and
238 len(potential_variants) == 1 and
239 len(potential_volatiles) == 1):
240 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
241 potential_variants.pop(),
242 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800243 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700244 print ('probing VOLATILEs to resolve potential matches: %s\n' %
245 ', '.join(sorted(potential_volatiles)))
246 vol_probe_results = Probe(
247 target_comp_classes=[],
248 probe_volatile=True,
249 probe_initial_config=False)
250 cooked_volatiles = device.MatchVolatileValues(
251 vol_probe_results.found_volatile_values)
252 match_tree = device.BuildMatchTree(
253 component_data, cooked_volatiles.matched_tags)
254 matched_hwids = device.GetMatchTreeHwids(match_tree)
255 if matched_hwids:
256 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800257 if matched_hwids[hwid] in options.status:
258 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700259 return
260 print 'exact HWID matching failed, but the following BOMs match: %s' % (
261 ', '.join(sorted(match_tree)))
262 if options.optimistic and len(match_tree) == 1:
263 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800264 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700265 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800266 if len(variant_matches) == 1:
267 var_code = set(variant_matches).pop()
268 elif len(bom.variants) == 1:
269 var_code = set(bom.variants).pop()
270 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700271 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
272 'because there were too many variants to choose from for BOM %r'
273 % bom_name)
274 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
275 for vol_code in device.volatiles
276 if device.GetHwidStatus(bom_name, var_code, vol_code)
277 in options.status]
278 for hwid in hwids:
279 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800280 return
281 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700282 print ('optimistic matching not attempted because either it was '
283 'not requested, or because the number of BOMs was <> 1\n')
284 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800285
286
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800287@Command('probe',
288 CmdArg('--comps', nargs='*',
289 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800290 CmdArg('--fast_fw_probe', action='store_true',
291 help='Do a fast probe for EC and main firmware versions only. '
292 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800293 CmdArg('--no_vol', action='store_true',
294 help='Do not probe volatile data.'),
295 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800296 help='Do not probe initial_config data.'),
297 CmdArg('--include_vpd', action='store_true',
298 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800299def RunProbe(options):
300 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800301 print GetGooftool(options).Probe(
302 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800303 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800304 probe_volatile=not options.no_vol,
305 probe_initial_config=not options.no_ic,
306 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800307
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800308
Tammo Spalink214caf42012-05-28 10:45:00 +0800309@Command('verify_components',
310 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800311 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800312def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800313 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800314
Tammo Spalink5c699832012-07-03 17:50:39 +0800315 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800316 that a corresponding match exists in the component_db -- make sure
317 that these components are present, that they have been approved, but
318 do not check against any specific BOM/HWID configurations.
319 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800320
Andy Chengc531e2f2012-10-15 19:09:17 +0800321 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800322 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800323 options.target_comps)
324 except ValueError, e:
325 sys.exit(e)
326
Ricky Liang53390232013-03-08 15:37:57 +0800327 PrintVerifyComponentsResults(result)
328
329
330def PrintVerifyComponentsResults(result):
331 """Prints out the results of VerifyComponents method call.
332
333 Groups the results into two groups: 'matches' and 'errors', and prints out
334 their values.
335 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800336 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800337 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800338 errors = []
339 for result_list in result.values():
340 for component_name, _, error in result_list:
341 if component_name:
342 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800343 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800344 errors.append(error)
345
Andy Cheng228a8c92012-08-27 10:53:57 +0800346 if matches:
347 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800348 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800349 print '\nerrors:\n %s' % '\n '.join(errors)
350 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800351 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800352 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800353
354
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800355@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700356 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800357 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800358 _probe_results_cmd_arg,
359 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800360def VerifyHwid(options):
361 """Verify system HWID properties match probed device properties.
362
363 First probe components, volatile and initial_config parameters for
364 the DUT. Then use the available device data to produce a list of
365 candidate HWIDs. Then verify the HWID from the DUT is present in
366 that list. Then verify that the DUT initial config values match
367 those specified for its HWID. Finally, verify that VPD contains all
368 the necessary fields as specified by the board data, and when
369 possible verify that values are legitimate.
370 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800371
Ricky Liangf7857c12012-09-17 13:34:41 +0800372 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800373 for key in ro_vpd_keys:
374 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800375 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700376 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800377 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800378 if (known_valid_values is not None) and (value not in known_valid_values):
379 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800380 for key in rw_vpd_keys:
381 if key not in rw_vpd:
382 sys.exit('Missing required RW VPD field: %s' % key)
383 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
384 value = rw_vpd[key]
385 if (known_valid_values is not None) and (value not in known_valid_values):
386 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800387 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800388 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800389
Jon Salz81350812012-10-11 16:13:22 +0800390 if not options.hwid or not options.probe_results:
391 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800392
393 if options.hwid:
394 hwid_str = options.hwid
395 else:
396 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
397 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700398 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800399 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800400 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700401 device = hw_db.GetDevice(hwid.board)
402 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
403 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800404 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800405 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800406 if options.probe_results:
407 # Pull in probe results (including VPD data) from the given file
408 # rather than probing the current system.
409 probe_results = hwid_tool.ProbeResults.Decode(
410 open(options.probe_results).read())
411 ro_vpd = {}
412 rw_vpd = {}
413 for k, v in probe_results.found_volatile_values.items():
414 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
415 if match:
416 del probe_results.found_volatile_values[k]
417 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
418 else:
419 probe_results = Probe()
420 ro_vpd = ReadRoVpd(main_fw_file)
421 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700422 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
423 probe_results.found_probe_value_map)
424 cooked_volatiles = device.MatchVolatileValues(
425 probe_results.found_volatile_values)
426 cooked_initial_configs = device.MatchInitialConfigValues(
427 probe_results.initial_configs)
428 component_data = hwid_tool.ComponentData(
429 extant_components=cooked_components.matched,
430 classes_missing=probe_results.missing_component_classes)
431 match_tree = device.BuildMatchTree(
432 component_data, cooked_volatiles.matched_tags)
433 matched_hwids = device.GetMatchTreeHwids(match_tree)
434 print 'HWID status: %s\n' % hwid_status
435 print 'probed system components:'
436 print YamlWrite(cooked_components.__dict__)
437 print 'missing component classes:'
438 print YamlWrite(probe_results.missing_component_classes)
439 print 'probed volatiles:'
440 print YamlWrite(cooked_volatiles.__dict__)
441 print 'probed initial_configs:'
442 print YamlWrite(cooked_initial_configs)
443 print 'hwid match tree:'
444 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800445 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800446 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700447 found_components=cooked_components.__dict__,
448 missing_component_classes=probe_results.missing_component_classes,
449 volatiles=cooked_volatiles.__dict__,
450 initial_configs=cooked_initial_configs)
451 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800452 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700453 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800454 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700455 YamlWrite(cooked_components.unmatched))
456 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800457 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700458 component_data.Encode())
459 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800460 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700461 (', '.join(sorted(match_tree)), hwid.bom))
462 err_msg += 'target bom %r matches components' % hwid.bom
463 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
464 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800465 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700466 matched_variants = match_tree.get(hwid.bom, {})
467 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800468 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700469 hwid.variant)
470 matched_volatiles = matched_variants.get(hwid.variant, {})
471 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800472 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700473 hwid.volatile)
474 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800475 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800476 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800477 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700478 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800479
480
481@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700482def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800483 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800484
Ricky Lianga70a1202013-03-15 15:03:17 +0800485 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800486
487
488@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700489def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800490 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800491
Ricky Lianga70a1202013-03-15 15:03:17 +0800492 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800493 logging.info('Firmware bitmap initial locale set to %d (%s).',
494 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800495
496
497@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700498def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800499 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800500
Ricky Lianga70a1202013-03-15 15:03:17 +0800501 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800502
503
504@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700505def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800506 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800507
Ricky Lianga70a1202013-03-15 15:03:17 +0800508 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800509
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800510@Command('verify_tpm')
511def VerifyTPM(options): # pylint: disable=W0613
512 """Verify TPM is cleared."""
513
514 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800515
516@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800517def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800518 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800519
Ricky Lianga70a1202013-03-15 15:03:17 +0800520 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800521
522
523@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700524def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800525 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800526
Ricky Lianga70a1202013-03-15 15:03:17 +0800527 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800528 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800529 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800530
531
532@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700533def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800534 """Enable then verify firmware write protection."""
535
Hung-Te Linb21c6682012-08-01 13:53:57 +0800536 def CalculateLegacyRange(fw_type, length, section_data,
537 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800538 ro_size = length / 2
539 ro_a = int(section_data[0] / ro_size)
540 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
541 if ro_a != ro_b:
542 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800543 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800544 ro_offset = ro_a * ro_size
545 return (ro_offset, ro_size)
546
547 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800548 """Calculate protection size, then invoke flashrom.
549
550 Our supported chips only allow write protecting half their total
551 size, so we parition the flash chipset space accordingly.
552 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800553
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800554 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800555 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800556 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800557 if image.has_section(wp_section):
558 section_data = image.get_section_area(wp_section)
559 ro_offset = section_data[0]
560 ro_size = section_data[1]
561 elif image.has_section(legacy_section):
562 section_data = image.get_section_area(legacy_section)
563 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800564 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800565 else:
566 raise Error('could not find %s firmware section %s or %s' %
567 (fw_type, wp_section, legacy_section))
568
569 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
570 ro_offset, ro_size)
571 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800572
573 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800574 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800575 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
576 if ec_fw_file is not None:
577 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800578 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800579 else:
580 logging.warning('EC not write protected (seems there is no EC flash).')
581
582
583@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800584def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800585 """Zero out the GBB flags, in preparation for transition to release state.
586
587 No GBB flags are set in release/shipping state, but they are useful
588 for factory/development. See "gbb_utility --flags" for details.
589 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800590
Ricky Lianga70a1202013-03-15 15:03:17 +0800591 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800592 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800593
594
Jon Salzaa3a30e2013-05-15 15:56:28 +0800595@Command('clear_factory_vpd_entries')
596def ClearFactoryVPDEntries(options): # pylint: disable=W0613
597 """Clears factory.* items in the RW VPD."""
598 entries = GetGooftool(options).ClearFactoryVPDEntries()
599 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
600
601
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800602@Command('prepare_wipe',
603 CmdArg('--fast', action='store_true',
604 help='use non-secure but faster wipe method.'))
605def PrepareWipe(options):
606 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800607
Ricky Lianga70a1202013-03-15 15:03:17 +0800608 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800609
610@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800611 CmdArg('--no_write_protect', action='store_true',
612 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700613 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800614 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800615 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800616 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800617 _hwid_cmd_arg,
618 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800619def Verify(options):
620 """Verifies if whole factory process is ready for finalization.
621
622 This routine performs all the necessary checks to make sure the
623 device is ready to be finalized, but does not modify state. These
624 checks include dev switch, firmware write protection switch, hwid,
625 system time, keys, and root file system.
626 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800627
Hung-Te Lin6d827542012-07-19 11:50:41 +0800628 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800629 VerifyWPSwitch(options)
630 VerifyDevSwitch(options)
631 if options.hwid_version == 2:
632 VerifyHwid(options)
633 elif options.hwid_version == 3:
634 VerifyHwidV3(options)
635 else:
636 raise Error, 'Invalid HWID version: %r' % options.hwid_version
637 VerifySystemTime(options)
638 VerifyKeys(options)
639 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800640 VerifyTPM(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800641
642
Tammo Spalink86a61c62012-05-25 15:10:35 +0800643@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700644def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800645 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800646
Andy Cheng0465d132013-03-20 12:12:06 +0800647 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800648 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800649
650
Jon Salza88b83b2013-05-27 20:00:35 +0800651def CreateReportArchiveBlob(*args, **kwargs):
652 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800653
Jon Salza88b83b2013-05-27 20:00:35 +0800654 Args:
655 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800656
Jon Salza88b83b2013-05-27 20:00:35 +0800657 Returns:
658 An xmlrpclib.Binary object containing a .tar.xz file.
659 """
660 with open(CreateReportArchive(*args, **kwargs)) as f:
661 return xmlrpclib.Binary(f.read())
662
663
664def CreateReportArchive(device_sn=None, add_file=None):
665 """Creates a report archive in a temporary directory.
666
667 Args:
668 device_sn: The device serial number (optional).
669 add_file: A list of files to add (optional).
670
671 Returns:
672 Path to the archive.
673 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800674 def NormalizeAsFileName(token):
675 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800676
677 target_name = '%s%s.tar.xz' % (
678 time.strftime('%Y%m%dT%H%M%SZ',
679 time.gmtime()),
680 ("" if device_sn is None else
681 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800682 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800683
Tammo Spalink86a61c62012-05-25 15:10:35 +0800684 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800685 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800686 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800687 if add_file:
688 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800689 # Require absolute paths since the tar command may change the
690 # directory.
691 if not f.startswith('/'):
692 raise Error('Not an absolute path: %s' % f)
693 if not os.path.exists(f):
694 raise Error('File does not exist: %s' % f)
695 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800696 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800697
698 if ((cmd_result.status == 1) and
699 all((x == '' or
700 'file changed as we read it' in x or
701 "Removing leading `/' from member names" in x)
702 for x in cmd_result.stderr.split('\n'))):
703 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800704 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800705 ignore_stdout=True)
706 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800707 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
708 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800709
Jon Salza88b83b2013-05-27 20:00:35 +0800710 return target_path
711
712_upload_method_cmd_arg = CmdArg(
713 '--upload_method', metavar='METHOD:PARAM',
714 help=('How to perform the upload. METHOD should be one of '
715 '{ftp, shopfloor, ftps, cpfe}.'))
716_add_file_cmd_arg = CmdArg(
717 '--add_file', metavar='FILE', action='append',
718 help='Extra file to include in report (must be an absolute path)')
719
720@Command('upload_report',
721 _upload_method_cmd_arg,
722 _add_file_cmd_arg)
723def UploadReport(options):
724 """Create a report containing key device details."""
725 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
726 device_sn = ro_vpd.get('serial_number', None)
727 if device_sn is None:
728 logging.warning('RO_VPD missing device serial number')
729 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
730 target_path = CreateReportArchive(device_sn)
731
Tammo Spalink86a61c62012-05-25 15:10:35 +0800732 if options.upload_method is None or options.upload_method == 'none':
733 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
734 return
735 method, param = options.upload_method.split(':', 1)
736 if method == 'shopfloor':
737 report_upload.ShopFloorUpload(target_path, param)
738 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700739 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800740 elif method == 'ftps':
741 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
742 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800743 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800744 else:
745 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800746
747
748@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800749 CmdArg('--no_write_protect', action='store_true',
750 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800751 CmdArg('--fast', action='store_true',
752 help='use non-secure but faster wipe method.'),
753 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700754 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800755 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800756 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800757 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800758 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800759 _hwid_cmd_arg,
760 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800761def Finalize(options):
762 """Verify system readiness and trigger transition into release state.
763
Jon Salzaa3a30e2013-05-15 15:56:28 +0800764 This routine does the following:
765 - Verifies system state (see verify command)
766 - Modifies firmware bitmaps to match locale
767 - Clears all factory-friendly flags from the GBB
768 - Removes factory-specific entries from RW_VPD (factory.*)
769 - Enables firmware write protection (cannot rollback after this)
770 - Uploads system logs & reports
771 - Sets the necessary boot flags to cause wipe of the factory image on the
772 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800773 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800774 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800775 SetFirmwareBitmapLocale(options)
776 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800777 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800778 if options.no_write_protect:
779 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800780 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800781 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800782 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800783 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800784 UploadReport(options)
785 PrepareWipe(options)
786
787
Ricky Liang53390232013-03-08 15:37:57 +0800788@Command('verify_components_v3',
789 _board_cmd_arg,
790 _hwdb_path_cmd_arg,
791 CmdArg('target_comps', nargs='*'))
792def VerifyComponentsV3(options):
793 """Verify that probeable components all match entries in the component_db.
794
795 This method uses the HWIDv3 component database to verify components.
796
797 Probe for each component class in the target_comps and verify
798 that a corresponding match exists in the component_db -- make sure
799 that these components are present, that they have been approved, but
800 do not check against any specific BOM/HWID configurations.
801 """
802
Ricky Lianga70a1202013-03-15 15:03:17 +0800803 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800804 PrintVerifyComponentsResults(result)
805
806
807@Command('generate_hwid_v3',
808 _board_cmd_arg,
809 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800810 _probe_results_cmd_arg,
Bernie Thompson3c11c872013-07-22 18:22:45 -0700811 _device_info_cmd_arg,
812 _rma_mode_cmd_arg)
Ricky Liang53390232013-03-08 15:37:57 +0800813def GenerateHwidV3(options):
814 """Generates the HWID of the DUT.
815
816 The HWID is generated based on the given device info and the probe results
817 retrieved by probing the DUT. If there are conflits of component information
818 between device info and probe result, priority is given to device info.
819 """
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800820 if options.device_info:
Ricky Liang7905f272013-03-16 01:57:10 +0800821 with open(options.device_info) as f:
822 device_info = yaml.load(f.read())
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800823 else:
824 device_info = shopfloor.GetDeviceData()
Ricky Liang7905f272013-03-16 01:57:10 +0800825 if options.probe_results:
826 with open(options.probe_results) as f:
827 probe_results = hwid_tool.ProbeResults.Decode(f.read())
828 else:
829 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800830 print 'device_info:'
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800831 print yaml.dump(device_info)
Ricky Liang5b4568d2013-04-23 17:15:23 +0800832 print 'probe results:'
Ricky Liang53390232013-03-08 15:37:57 +0800833 print probe_results.Encode()
834
835 # Do not log device_info for now until we're sure that it does not contain
836 # any sensitive infomation.
837 # TODO(jcliang): Add logging for device_info when appropriate.
838
Andy Cheng0465d132013-03-20 12:12:06 +0800839 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800840 'probe',
841 found_components=probe_results.found_probe_value_map,
842 missing_component_classes=probe_results.missing_component_classes,
843 volatiles=probe_results.found_volatile_values,
844 initial_configs=probe_results.initial_configs)
845
Ricky Lianga70a1202013-03-15 15:03:17 +0800846 hwid_object = GetGooftool(options).GenerateHwidV3(
Bernie Thompson3c11c872013-07-22 18:22:45 -0700847 device_info, probe_results, rma_mode=options.rma_mode)
Ricky Liang53390232013-03-08 15:37:57 +0800848
849 final_bom = {}
850 for component_class, component_values in (
851 hwid_object.bom.components.iteritems()):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800852 final_bom[component_class] = [v.probed_values for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800853 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800854 'final_bom',
855 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800856 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800857 'generated_hwid',
858 encoded_string=hwid_object.encoded_string,
859 binary_string=hwid_object.binary_string)
860 print 'Encoded HWID string:', hwid_object.encoded_string
861 print 'Binary HWID string:', hwid_object.binary_string
862
863
864@Command('verify_hwid_v3',
865 _board_cmd_arg,
866 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800867 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800868 _hwid_cmd_arg,
869 _rma_mode_cmd_arg)
Ricky Liang53390232013-03-08 15:37:57 +0800870def VerifyHwidV3(options):
871 """Verify system HWID properties match probed device properties.
872
873 First probe components, volatile and initial_config parameters for
874 the DUT. Then use the available device data to produce a list of
875 candidate HWIDs. Then verify the HWID from the DUT is present in
876 that list. Then verify that the DUT initial config values match
877 those specified for its HWID. Finally, verify that VPD contains all
878 the necessary fields as specified by the board data, and when
879 possible verify that values are legitimate.
880 """
Ricky Liang7905f272013-03-16 01:57:10 +0800881 if not options.probe_results:
882 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800883 if options.hwid:
884 hwid_str = options.hwid
885 else:
886 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
887 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
888 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800889 if options.probe_results:
890 # Pull in probe results (including VPD data) from the given file
891 # rather than probing the current system.
892 with open(options.probe_results) as f:
893 probe_results = hwid_tool.ProbeResults.Decode(f.read())
894 probed_ro_vpd = {}
895 probed_rw_vpd = {}
896 for k, v in probe_results.found_volatile_values.items():
897 # Use items(), not iteritems(), since we will be modifying the dict in the
898 # loop.
899 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
900 if match:
901 del probe_results.found_volatile_values[k]
902 (probed_ro_vpd if match.group(1) == 'ro'
903 else probed_rw_vpd)[match.group(2)] = v
904 else:
905 probe_results = Probe()
906 probed_ro_vpd = ReadRoVpd(main_fw_file)
907 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800908 print 'probe result:'
909 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800910 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800911 'probe',
912 found_components=probe_results.found_probe_value_map,
913 missing_component_classes=probe_results.missing_component_classes,
914 volatiles=probe_results.found_volatile_values,
915 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800916 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800917 probed_rw_vpd=FilterDict(probed_rw_vpd))
918
Ricky Liangeede7922013-06-19 10:18:41 +0800919 if not options.board:
920 options.board = common.ProbeBoard(hwid_str)
Ricky Lianga70a1202013-03-15 15:03:17 +0800921 GetGooftool(options).VerifyHwidV3(
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800922 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd,
923 rma_mode=options.rma_mode)
Ricky Liang53390232013-03-08 15:37:57 +0800924
Andy Cheng0465d132013-03-20 12:12:06 +0800925 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800926 print 'Verification SUCCESS!'
927
928
Ricky Liang59611a62013-06-11 13:47:33 +0800929def ParseDecodedHWID(hwid):
930 """Parse the HWID object into a more compact dict.
931
932 Args:
933 hwid: A decoded HWID object.
934
935 Returns:
936 A dict containing the board name, the binary string, and the list of
937 components.
938 """
939 results = {}
940 results['board'] = hwid.database.board
941 results['binary_string'] = hwid.binary_string
942 results['components'] = collections.defaultdict(list)
943 components = hwid.bom.components
944 for comp_cls in sorted(components):
945 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
946 if not probed_values:
947 db_components = hwid.database.components
948 probed_values = db_components.GetComponentAttributes(
949 comp_cls, comp_name).get('values')
950 results['components'][comp_cls].append(
951 {comp_name: probed_values if probed_values else None})
952 # Convert defaultdict to dict.
953 results['components'] = dict(results['components'])
954 return results
955
956
Ricky Liang7905f272013-03-16 01:57:10 +0800957@Command('decode_hwid_v3',
958 _board_cmd_arg,
959 _hwdb_path_cmd_arg,
960 _hwid_cmd_arg)
961def DecodeHwidV3(options):
962 """Decodes the given v3 HWID and prints out decoded information.
963
964 If no HWID is given, the HWID stored on the device will be loaded and used
965 instead.
966 """
Ricky Liangeede7922013-06-19 10:18:41 +0800967 if not options.board:
968 options.board = common.ProbeBoard(options.hwid)
Ricky Liang7905f272013-03-16 01:57:10 +0800969 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
970 hwdb_path=options.hwdb_path).DecodeHwidV3(
971 options.hwid)
Ricky Liang59611a62013-06-11 13:47:33 +0800972 print yaml.dump(ParseDecodedHWID(decoded_hwid_context),
973 default_flow_style=False)
Ricky Liang7905f272013-03-16 01:57:10 +0800974
975
henryhsu44d793a2013-07-20 00:07:38 +0800976@Command('get_firmware_hash',
977 CmdArg('--file', metavar='FILE', help='Firmware File.'))
978def GetFirmwareHash(options):
henryhsuf6f835c2013-07-20 20:49:25 +0800979 """Get firmware hash from a file"""
henryhsu44d793a2013-07-20 00:07:38 +0800980 if os.path.exists(options.file):
981 hashes = CalculateFirmwareHashes(options.file)
982 for section, value_dict in hashes.iteritems():
983 print "%s:" % section
984 for key, value in value_dict.iteritems():
985 print " %s: %s" % (key, value)
986 else:
987 raise Error('File does not exist: %s' % options.file)
988
henryhsuf6f835c2013-07-20 20:49:25 +0800989
990@Command('get_hwid_v3_list',
991 _board_cmd_arg,
992 _hwdb_path_cmd_arg,
henryhsu7c2c18e2013-11-20 15:29:40 +0800993 CmdArg('--image_id', metavar='IMAGE_ID', help='Image ID.'),
994 CmdArg('--status', metavar='STATUS', default='supported',
995 help='Components status. The value should be '
996 '"supported" or "all"'))
henryhsuf6f835c2013-07-20 20:49:25 +0800997def GetHWIDV3List(options):
998 """Generate HWID with all components combination of specified
999 image_id, and output as CSV format.
1000
1001 Args:
1002 board: HWID generated by which board. This parameter is required.
1003 image_id: Which image stage should be generated. If this parameter
1004 is omitted, The maximum of image_id will be used.
1005 This parameter is integer.
henryhsu7c2c18e2013-11-20 15:29:40 +08001006 status: Default value is 'supported'. If you want to generate all
1007 combinations include unsupported and deprecated, you can set
1008 status to 'all'.
henryhsuf6f835c2013-07-20 20:49:25 +08001009 """
1010 if options.board:
henryhsu7c2c18e2013-11-20 15:29:40 +08001011 if options.status not in ('supported', 'all'):
1012 raise Error("Status should be 'supported' or 'all'")
1013 hwid_dict = GetGooftool(options).GetHWIDV3List(options.image_id,
1014 options.status)
henryhsuf6f835c2013-07-20 20:49:25 +08001015 for key, value in iter(sorted(hwid_dict.iteritems())):
1016 print "%s,%s" % (key, value)
1017 else:
1018 raise Error('Board should be speficied')
1019
1020
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001021def Main():
1022 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +08001023
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001024 options = ParseCmdline(
1025 'Perform Google required factory tests.',
1026 CmdArg('-l', '--log', metavar='PATH',
1027 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +08001028 CmdArg('--suppress-event-logs', action='store_true',
1029 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +08001030 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +08001031 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +08001032 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001033 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +08001034 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
1035 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001036 logging.debug('gooftool options: %s', repr(options))
1037 try:
1038 logging.debug('GOOFTOOL command %r', options.command_name)
1039 options.command(options)
1040 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
1041 except Error, e:
1042 logging.exception(e)
1043 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
1044 except Exception, e:
1045 logging.exception(e)
1046 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
1047
1048
1049if __name__ == '__main__':
1050 Main()