blob: 9bd2dbffef6f0632e162ba6146729b3683807c81 [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
Jon Salz193d7c62013-03-07 13:40:19 +080037from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080038from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
39from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070040from cros.factory.hwdb import hwid_tool
cychiang7fe09372012-07-04 14:31:23 +080041from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080042from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080043from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080044
Tammo Spalink5c699832012-07-03 17:50:39 +080045
Tammo Spalink5c699832012-07-03 17:50:39 +080046# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
47# treat that specially (as a smoot exit, as opposed to the more
48# verbose output for generic Error).
49
50
Ricky Lianga70a1202013-03-15 15:03:17 +080051def GetGooftool(options):
52 if options.hwid_version == 2:
53 hwdb_path = getattr(options, 'hwdb_path', None)
54 component_db = (
55 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
56 return Gooftool(hwid_version=2, component_db=component_db)
57 elif options.hwid_version == 3:
58 board = getattr(options, 'board', None)
59 hwdb_path = getattr(options, 'hwdb_path', None)
60 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
61 else:
62 raise Error, 'Invalid HWID version: %r' % options.hwid_version
63
64
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080065@Command('write_hwid',
66 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080067def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080068 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080069
Tammo Spalink95c43732012-07-25 15:57:14 -070070 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080071 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080072 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070073 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080074
75
Ricky Liang53390232013-03-08 15:37:57 +080076_board_cmd_arg = CmdArg(
77 '--board', metavar='BOARD',
78 default=None, help='Board name to test.')
79
Tammo Spalink8fab5312012-05-28 18:33:30 +080080_hwdb_path_cmd_arg = CmdArg(
81 '--hwdb_path', metavar='PATH',
82 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
83 help='Path to the HWID database.')
84
Tammo Spalink95c43732012-07-25 15:57:14 -070085_hwid_status_list_cmd_arg = CmdArg(
86 '--status', nargs='*', default=['supported'],
87 help='allow only HWIDs with these status values')
88
Jon Salzce124fb2012-10-02 17:42:03 +080089_probe_results_cmd_arg = CmdArg(
90 '--probe_results', metavar='RESULTS.yaml',
91 help=('Output from "gooftool probe" (used instead of '
92 'probing this system).'))
93
Ricky Liang53390232013-03-08 15:37:57 +080094_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080095 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +080096 help='A dict of device info to use instead of fetching from shopfllor '
97 'server.')
98
Jon Salzce124fb2012-10-02 17:42:03 +080099_hwid_cmd_arg = CmdArg(
100 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800101 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800102
Tammo Spalink95c43732012-07-25 15:57:14 -0700103
104@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800105 _hwdb_path_cmd_arg,
106 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700107 help='optional BOARD name, needed only if data is present '
108 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800109 CmdArg('--bom', metavar='BOM', help='BOM name'),
110 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800111 CmdArg('--optimistic', action='store_true',
112 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700113 CmdArg('--comps', nargs='*', default=[],
114 help='list of canonical component names'),
115 CmdArg('--missing', nargs='*', default=[],
116 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800117 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700118 help='consider only HWIDs within this list of status values'))
119def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800120 """Determine a list of possible HWIDs using provided args and probeing.
121
122 VOLATILE can always be determined by probing. To get a unique
123 result, VARIANT must be specified for all cases where the matching
124 BOM has more than one associated variant code, otherwise all HWID
125 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700126 alternatively be specified using the --stdin_comps argument, which
127 allows specifying a list of canonical names (one per line) on stdin,
128 one per line. Based on what is known from BOM and stdin_comps,
129 determine a list of components to probe for, and use those probe
130 results to resolve a list of matching HWIDs. If no boms,
131 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800132 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800133
134 Returns (on stdout): A list of HWIDs that match the available probe
135 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700136
137 Example:
138
139 // Three ways to specify a keyboard (assuming it is a variant component)
140 gooftool best_match_hwids --missing keyboard
141 gooftool best_match_hwids --variant A or
142 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800143 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800144
Tammo Spalink5c699832012-07-03 17:50:39 +0800145 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700146 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800147 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800148 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800149 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800150 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800151 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700152 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800153 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800154 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800155 device.VariantExists(options.variant)
156 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700157 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700158 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700159 % YamlWrite(sorted(
160 hwid_tool.ComponentSpecClasses(component_spec) &
161 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700162 component_spec = hwid_tool.CombineComponentSpecs(
163 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700164 if options.comps or options.missing:
165 map(comp_db.CompExists, options.comps)
166 map(comp_db.CompClassExists, options.missing)
167 extra_comp_spec = comp_db.CreateComponentSpec(
168 components=options.comps,
169 missing=options.missing)
170 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
171 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
172 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700173 % YamlWrite(sorted(
174 hwid_tool.ComponentSpecClasses(component_spec) &
175 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700176 component_spec = hwid_tool.CombineComponentSpecs(
177 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700178 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700179 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800180 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800181 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
182 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700183 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700184 'as inputs, and cannot be probed for:\n%s'
185 'This problem can often be addressed by specifying all of '
186 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800187 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700188 print 'probing for missing classes:'
189 print YamlWrite(list(missing_classes))
190 probe_results = Probe(target_comp_classes=list(missing_classes),
191 probe_volatile=False, probe_initial_config=False)
192 cooked_components = comp_db.MatchComponentProbeValues(
193 probe_results.found_probe_value_map)
194 if cooked_components.unmatched:
195 sys.exit('ERROR: some probed components are unrecognized:\n%s'
196 % YamlWrite(cooked_components.unmatched))
197 probed_comp_spec = comp_db.CreateComponentSpec(
198 components=cooked_components.matched,
199 missing=probe_results.missing_component_classes)
200 component_spec = hwid_tool.CombineComponentSpecs(
201 component_spec, probed_comp_spec)
202 print YamlWrite({'component data used for matching': {
203 'missing component classes': component_spec.classes_missing,
204 'found components': component_spec.components}})
205 component_data = hwid_tool.ComponentData(
206 extant_components=hwid_tool.ComponentSpecCompClassMap(
207 component_spec).keys(),
208 classes_missing=component_spec.classes_missing)
209 match_tree = device.BuildMatchTree(component_data)
210 if not match_tree:
211 sys.exit('FAILURE: NO matching BOMs found')
212 print 'potential BOMs/VARIANTs:'
213 potential_variants = set()
214 potential_volatiles = set()
215 for bom_name, variant_tree in match_tree.items():
216 print ' BOM: %-8s VARIANTS: %s' % (
217 bom_name, ', '.join(sorted(variant_tree)))
218 for variant_code in variant_tree:
219 potential_variants.add(variant_code)
220 for volatile_code in device.volatiles:
221 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
222 if status in options.status:
223 potential_volatiles.add(volatile_code)
224 print ''
225 if len(potential_variants) == 0:
226 sys.exit('FAILURE: no matching VARIANTs found')
227 if len(potential_volatiles) == 0:
228 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
229 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700230 if (options.optimistic and
231 len(match_tree) == 1 and
232 len(potential_variants) == 1 and
233 len(potential_volatiles) == 1):
234 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
235 potential_variants.pop(),
236 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800237 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700238 print ('probing VOLATILEs to resolve potential matches: %s\n' %
239 ', '.join(sorted(potential_volatiles)))
240 vol_probe_results = Probe(
241 target_comp_classes=[],
242 probe_volatile=True,
243 probe_initial_config=False)
244 cooked_volatiles = device.MatchVolatileValues(
245 vol_probe_results.found_volatile_values)
246 match_tree = device.BuildMatchTree(
247 component_data, cooked_volatiles.matched_tags)
248 matched_hwids = device.GetMatchTreeHwids(match_tree)
249 if matched_hwids:
250 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800251 if matched_hwids[hwid] in options.status:
252 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700253 return
254 print 'exact HWID matching failed, but the following BOMs match: %s' % (
255 ', '.join(sorted(match_tree)))
256 if options.optimistic and len(match_tree) == 1:
257 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800258 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700259 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800260 if len(variant_matches) == 1:
261 var_code = set(variant_matches).pop()
262 elif len(bom.variants) == 1:
263 var_code = set(bom.variants).pop()
264 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700265 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
266 'because there were too many variants to choose from for BOM %r'
267 % bom_name)
268 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
269 for vol_code in device.volatiles
270 if device.GetHwidStatus(bom_name, var_code, vol_code)
271 in options.status]
272 for hwid in hwids:
273 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800274 return
275 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700276 print ('optimistic matching not attempted because either it was '
277 'not requested, or because the number of BOMs was <> 1\n')
278 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800279
280
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800281@Command('probe',
282 CmdArg('--comps', nargs='*',
283 help='List of keys from the component_db registry.'),
284 CmdArg('--no_vol', action='store_true',
285 help='Do not probe volatile data.'),
286 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800287 help='Do not probe initial_config data.'),
288 CmdArg('--include_vpd', action='store_true',
289 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800290def RunProbe(options):
291 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800292 print GetGooftool(options).Probe(
293 target_comp_classes=options.comps,
294 probe_volatile=not options.no_vol,
295 probe_initial_config=not options.no_ic,
296 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800297
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800298
Tammo Spalink214caf42012-05-28 10:45:00 +0800299@Command('verify_components',
300 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800301 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800302def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800303 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800304
Tammo Spalink5c699832012-07-03 17:50:39 +0800305 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800306 that a corresponding match exists in the component_db -- make sure
307 that these components are present, that they have been approved, but
308 do not check against any specific BOM/HWID configurations.
309 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800310
Andy Chengc531e2f2012-10-15 19:09:17 +0800311 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800312 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800313 options.target_comps)
314 except ValueError, e:
315 sys.exit(e)
316
Ricky Liang53390232013-03-08 15:37:57 +0800317 PrintVerifyComponentsResults(result)
318
319
320def PrintVerifyComponentsResults(result):
321 """Prints out the results of VerifyComponents method call.
322
323 Groups the results into two groups: 'matches' and 'errors', and prints out
324 their values.
325 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800326 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800327 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800328 errors = []
329 for result_list in result.values():
330 for component_name, _, error in result_list:
331 if component_name:
332 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800333 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800334 errors.append(error)
335
Andy Cheng228a8c92012-08-27 10:53:57 +0800336 if matches:
337 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800338 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800339 print '\nerrors:\n %s' % '\n '.join(errors)
340 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800341 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800342 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800343
344
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800345@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700346 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800347 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800348 _probe_results_cmd_arg,
349 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800350def VerifyHwid(options):
351 """Verify system HWID properties match probed device properties.
352
353 First probe components, volatile and initial_config parameters for
354 the DUT. Then use the available device data to produce a list of
355 candidate HWIDs. Then verify the HWID from the DUT is present in
356 that list. Then verify that the DUT initial config values match
357 those specified for its HWID. Finally, verify that VPD contains all
358 the necessary fields as specified by the board data, and when
359 possible verify that values are legitimate.
360 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800361
Ricky Liangf7857c12012-09-17 13:34:41 +0800362 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800363 for key in ro_vpd_keys:
364 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800365 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700366 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800367 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800368 if (known_valid_values is not None) and (value not in known_valid_values):
369 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800370 for key in rw_vpd_keys:
371 if key not in rw_vpd:
372 sys.exit('Missing required RW VPD field: %s' % key)
373 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
374 value = rw_vpd[key]
375 if (known_valid_values is not None) and (value not in known_valid_values):
376 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800377 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800378 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800379
Jon Salz81350812012-10-11 16:13:22 +0800380 if not options.hwid or not options.probe_results:
381 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800382
383 if options.hwid:
384 hwid_str = options.hwid
385 else:
386 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
387 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700388 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800389 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800390 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700391 device = hw_db.GetDevice(hwid.board)
392 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
393 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800394 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800395 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800396 if options.probe_results:
397 # Pull in probe results (including VPD data) from the given file
398 # rather than probing the current system.
399 probe_results = hwid_tool.ProbeResults.Decode(
400 open(options.probe_results).read())
401 ro_vpd = {}
402 rw_vpd = {}
403 for k, v in probe_results.found_volatile_values.items():
404 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
405 if match:
406 del probe_results.found_volatile_values[k]
407 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
408 else:
409 probe_results = Probe()
410 ro_vpd = ReadRoVpd(main_fw_file)
411 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700412 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
413 probe_results.found_probe_value_map)
414 cooked_volatiles = device.MatchVolatileValues(
415 probe_results.found_volatile_values)
416 cooked_initial_configs = device.MatchInitialConfigValues(
417 probe_results.initial_configs)
418 component_data = hwid_tool.ComponentData(
419 extant_components=cooked_components.matched,
420 classes_missing=probe_results.missing_component_classes)
421 match_tree = device.BuildMatchTree(
422 component_data, cooked_volatiles.matched_tags)
423 matched_hwids = device.GetMatchTreeHwids(match_tree)
424 print 'HWID status: %s\n' % hwid_status
425 print 'probed system components:'
426 print YamlWrite(cooked_components.__dict__)
427 print 'missing component classes:'
428 print YamlWrite(probe_results.missing_component_classes)
429 print 'probed volatiles:'
430 print YamlWrite(cooked_volatiles.__dict__)
431 print 'probed initial_configs:'
432 print YamlWrite(cooked_initial_configs)
433 print 'hwid match tree:'
434 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800435 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800436 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700437 found_components=cooked_components.__dict__,
438 missing_component_classes=probe_results.missing_component_classes,
439 volatiles=cooked_volatiles.__dict__,
440 initial_configs=cooked_initial_configs)
441 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800442 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700443 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800444 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700445 YamlWrite(cooked_components.unmatched))
446 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800447 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700448 component_data.Encode())
449 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800450 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700451 (', '.join(sorted(match_tree)), hwid.bom))
452 err_msg += 'target bom %r matches components' % hwid.bom
453 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
454 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800455 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700456 matched_variants = match_tree.get(hwid.bom, {})
457 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800458 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700459 hwid.variant)
460 matched_volatiles = matched_variants.get(hwid.variant, {})
461 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800462 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700463 hwid.volatile)
464 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800465 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800466 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800467 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700468 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800469
470
471@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700472def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800473 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800474
Ricky Lianga70a1202013-03-15 15:03:17 +0800475 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800476
477
478@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700479def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800480 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800481
Ricky Lianga70a1202013-03-15 15:03:17 +0800482 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800483 logging.info('Firmware bitmap initial locale set to %d (%s).',
484 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800485
486
487@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700488def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800489 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800490
Ricky Lianga70a1202013-03-15 15:03:17 +0800491 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800492
493
494@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700495def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800497
Ricky Lianga70a1202013-03-15 15:03:17 +0800498 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800499
500
501@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800502def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800504
Ricky Lianga70a1202013-03-15 15:03:17 +0800505 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800506
507
508@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700509def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800510 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800511
Ricky Lianga70a1202013-03-15 15:03:17 +0800512 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800513 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800514 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800515
516
517@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700518def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800519 """Enable then verify firmware write protection."""
520
Hung-Te Linb21c6682012-08-01 13:53:57 +0800521 def CalculateLegacyRange(fw_type, length, section_data,
522 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800523 ro_size = length / 2
524 ro_a = int(section_data[0] / ro_size)
525 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
526 if ro_a != ro_b:
527 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800528 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800529 ro_offset = ro_a * ro_size
530 return (ro_offset, ro_size)
531
532 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800533 """Calculate protection size, then invoke flashrom.
534
535 Our supported chips only allow write protecting half their total
536 size, so we parition the flash chipset space accordingly.
537 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800538
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800539 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800540 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800541 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800542 if image.has_section(wp_section):
543 section_data = image.get_section_area(wp_section)
544 ro_offset = section_data[0]
545 ro_size = section_data[1]
546 elif image.has_section(legacy_section):
547 section_data = image.get_section_area(legacy_section)
548 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800549 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800550 else:
551 raise Error('could not find %s firmware section %s or %s' %
552 (fw_type, wp_section, legacy_section))
553
554 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
555 ro_offset, ro_size)
556 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800557
558 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800559 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800560 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
561 if ec_fw_file is not None:
562 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800563 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800564 else:
565 logging.warning('EC not write protected (seems there is no EC flash).')
566
567
568@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800569def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800570 """Zero out the GBB flags, in preparation for transition to release state.
571
572 No GBB flags are set in release/shipping state, but they are useful
573 for factory/development. See "gbb_utility --flags" for details.
574 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800575
Ricky Lianga70a1202013-03-15 15:03:17 +0800576 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800577 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800578
579
Jon Salzaa3a30e2013-05-15 15:56:28 +0800580@Command('clear_factory_vpd_entries')
581def ClearFactoryVPDEntries(options): # pylint: disable=W0613
582 """Clears factory.* items in the RW VPD."""
583 entries = GetGooftool(options).ClearFactoryVPDEntries()
584 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
585
586
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800587@Command('prepare_wipe',
588 CmdArg('--fast', action='store_true',
589 help='use non-secure but faster wipe method.'))
590def PrepareWipe(options):
591 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800592
Ricky Lianga70a1202013-03-15 15:03:17 +0800593 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800594
595@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800596 CmdArg('--no_write_protect', action='store_true',
597 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700598 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800599 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800600 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800601 _probe_results_cmd_arg,
602 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800603def Verify(options):
604 """Verifies if whole factory process is ready for finalization.
605
606 This routine performs all the necessary checks to make sure the
607 device is ready to be finalized, but does not modify state. These
608 checks include dev switch, firmware write protection switch, hwid,
609 system time, keys, and root file system.
610 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800611
Hung-Te Lin6d827542012-07-19 11:50:41 +0800612 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800613 VerifyWPSwitch(options)
614 VerifyDevSwitch(options)
615 if options.hwid_version == 2:
616 VerifyHwid(options)
617 elif options.hwid_version == 3:
618 VerifyHwidV3(options)
619 else:
620 raise Error, 'Invalid HWID version: %r' % options.hwid_version
621 VerifySystemTime(options)
622 VerifyKeys(options)
623 VerifyRootFs(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800624
625
Tammo Spalink86a61c62012-05-25 15:10:35 +0800626@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700627def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800628 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800629
Andy Cheng0465d132013-03-20 12:12:06 +0800630 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800631 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800632
633
Jon Salza88b83b2013-05-27 20:00:35 +0800634def CreateReportArchiveBlob(*args, **kwargs):
635 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800636
Jon Salza88b83b2013-05-27 20:00:35 +0800637 Args:
638 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800639
Jon Salza88b83b2013-05-27 20:00:35 +0800640 Returns:
641 An xmlrpclib.Binary object containing a .tar.xz file.
642 """
643 with open(CreateReportArchive(*args, **kwargs)) as f:
644 return xmlrpclib.Binary(f.read())
645
646
647def CreateReportArchive(device_sn=None, add_file=None):
648 """Creates a report archive in a temporary directory.
649
650 Args:
651 device_sn: The device serial number (optional).
652 add_file: A list of files to add (optional).
653
654 Returns:
655 Path to the archive.
656 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800657 def NormalizeAsFileName(token):
658 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800659
660 target_name = '%s%s.tar.xz' % (
661 time.strftime('%Y%m%dT%H%M%SZ',
662 time.gmtime()),
663 ("" if device_sn is None else
664 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800665 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800666
Tammo Spalink86a61c62012-05-25 15:10:35 +0800667 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800668 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800669 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800670 if add_file:
671 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800672 # Require absolute paths since the tar command may change the
673 # directory.
674 if not f.startswith('/'):
675 raise Error('Not an absolute path: %s' % f)
676 if not os.path.exists(f):
677 raise Error('File does not exist: %s' % f)
678 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800679 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800680
681 if ((cmd_result.status == 1) and
682 all((x == '' or
683 'file changed as we read it' in x or
684 "Removing leading `/' from member names" in x)
685 for x in cmd_result.stderr.split('\n'))):
686 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800687 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800688 ignore_stdout=True)
689 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800690 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
691 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800692
Jon Salza88b83b2013-05-27 20:00:35 +0800693 return target_path
694
695_upload_method_cmd_arg = CmdArg(
696 '--upload_method', metavar='METHOD:PARAM',
697 help=('How to perform the upload. METHOD should be one of '
698 '{ftp, shopfloor, ftps, cpfe}.'))
699_add_file_cmd_arg = CmdArg(
700 '--add_file', metavar='FILE', action='append',
701 help='Extra file to include in report (must be an absolute path)')
702
703@Command('upload_report',
704 _upload_method_cmd_arg,
705 _add_file_cmd_arg)
706def UploadReport(options):
707 """Create a report containing key device details."""
708 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
709 device_sn = ro_vpd.get('serial_number', None)
710 if device_sn is None:
711 logging.warning('RO_VPD missing device serial number')
712 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
713 target_path = CreateReportArchive(device_sn)
714
Tammo Spalink86a61c62012-05-25 15:10:35 +0800715 if options.upload_method is None or options.upload_method == 'none':
716 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
717 return
718 method, param = options.upload_method.split(':', 1)
719 if method == 'shopfloor':
720 report_upload.ShopFloorUpload(target_path, param)
721 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700722 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800723 elif method == 'ftps':
724 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
725 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800726 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800727 else:
728 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800729
730
731@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800732 CmdArg('--no_write_protect', action='store_true',
733 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800734 CmdArg('--fast', action='store_true',
735 help='use non-secure but faster wipe method.'),
736 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700737 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800738 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800739 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800740 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800741 _probe_results_cmd_arg,
742 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800743def Finalize(options):
744 """Verify system readiness and trigger transition into release state.
745
Jon Salzaa3a30e2013-05-15 15:56:28 +0800746 This routine does the following:
747 - Verifies system state (see verify command)
748 - Modifies firmware bitmaps to match locale
749 - Clears all factory-friendly flags from the GBB
750 - Removes factory-specific entries from RW_VPD (factory.*)
751 - Enables firmware write protection (cannot rollback after this)
752 - Uploads system logs & reports
753 - Sets the necessary boot flags to cause wipe of the factory image on the
754 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800755 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800756 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800757 SetFirmwareBitmapLocale(options)
758 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800759 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800760 if options.no_write_protect:
761 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800762 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800763 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800764 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800765 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800766 UploadReport(options)
767 PrepareWipe(options)
768
769
Ricky Liang53390232013-03-08 15:37:57 +0800770@Command('verify_components_v3',
771 _board_cmd_arg,
772 _hwdb_path_cmd_arg,
773 CmdArg('target_comps', nargs='*'))
774def VerifyComponentsV3(options):
775 """Verify that probeable components all match entries in the component_db.
776
777 This method uses the HWIDv3 component database to verify components.
778
779 Probe for each component class in the target_comps and verify
780 that a corresponding match exists in the component_db -- make sure
781 that these components are present, that they have been approved, but
782 do not check against any specific BOM/HWID configurations.
783 """
784
Ricky Lianga70a1202013-03-15 15:03:17 +0800785 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800786 PrintVerifyComponentsResults(result)
787
788
789@Command('generate_hwid_v3',
790 _board_cmd_arg,
791 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800792 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800793 _device_info_cmd_arg)
794def GenerateHwidV3(options):
795 """Generates the HWID of the DUT.
796
797 The HWID is generated based on the given device info and the probe results
798 retrieved by probing the DUT. If there are conflits of component information
799 between device info and probe result, priority is given to device info.
800 """
801 try:
Ricky Liang7905f272013-03-16 01:57:10 +0800802 with open(options.device_info) as f:
803 device_info = yaml.load(f.read())
Ricky Liang53390232013-03-08 15:37:57 +0800804 except Exception, e:
805 raise Error, 'Invalid device_info: %s' % e
Ricky Liang7905f272013-03-16 01:57:10 +0800806 if options.probe_results:
807 with open(options.probe_results) as f:
808 probe_results = hwid_tool.ProbeResults.Decode(f.read())
809 else:
810 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800811 print 'device_info:'
812 print device_info
Ricky Liang5b4568d2013-04-23 17:15:23 +0800813 print 'probe results:'
Ricky Liang53390232013-03-08 15:37:57 +0800814 print probe_results.Encode()
815
816 # Do not log device_info for now until we're sure that it does not contain
817 # any sensitive infomation.
818 # TODO(jcliang): Add logging for device_info when appropriate.
819
Andy Cheng0465d132013-03-20 12:12:06 +0800820 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800821 'probe',
822 found_components=probe_results.found_probe_value_map,
823 missing_component_classes=probe_results.missing_component_classes,
824 volatiles=probe_results.found_volatile_values,
825 initial_configs=probe_results.initial_configs)
826
Ricky Lianga70a1202013-03-15 15:03:17 +0800827 hwid_object = GetGooftool(options).GenerateHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800828 device_info, probe_results)
Ricky Liang53390232013-03-08 15:37:57 +0800829
830 final_bom = {}
831 for component_class, component_values in (
832 hwid_object.bom.components.iteritems()):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800833 final_bom[component_class] = [v.probed_values for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800834 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800835 'final_bom',
836 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800837 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800838 'generated_hwid',
839 encoded_string=hwid_object.encoded_string,
840 binary_string=hwid_object.binary_string)
841 print 'Encoded HWID string:', hwid_object.encoded_string
842 print 'Binary HWID string:', hwid_object.binary_string
843
844
845@Command('verify_hwid_v3',
846 _board_cmd_arg,
847 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800848 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800849 _hwid_cmd_arg)
850def VerifyHwidV3(options):
851 """Verify system HWID properties match probed device properties.
852
853 First probe components, volatile and initial_config parameters for
854 the DUT. Then use the available device data to produce a list of
855 candidate HWIDs. Then verify the HWID from the DUT is present in
856 that list. Then verify that the DUT initial config values match
857 those specified for its HWID. Finally, verify that VPD contains all
858 the necessary fields as specified by the board data, and when
859 possible verify that values are legitimate.
860 """
Ricky Liang7905f272013-03-16 01:57:10 +0800861 if not options.probe_results:
862 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800863 if options.hwid:
864 hwid_str = options.hwid
865 else:
866 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
867 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
868 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800869 if options.probe_results:
870 # Pull in probe results (including VPD data) from the given file
871 # rather than probing the current system.
872 with open(options.probe_results) as f:
873 probe_results = hwid_tool.ProbeResults.Decode(f.read())
874 probed_ro_vpd = {}
875 probed_rw_vpd = {}
876 for k, v in probe_results.found_volatile_values.items():
877 # Use items(), not iteritems(), since we will be modifying the dict in the
878 # loop.
879 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
880 if match:
881 del probe_results.found_volatile_values[k]
882 (probed_ro_vpd if match.group(1) == 'ro'
883 else probed_rw_vpd)[match.group(2)] = v
884 else:
885 probe_results = Probe()
886 probed_ro_vpd = ReadRoVpd(main_fw_file)
887 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800888 print 'probe result:'
889 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800890 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800891 'probe',
892 found_components=probe_results.found_probe_value_map,
893 missing_component_classes=probe_results.missing_component_classes,
894 volatiles=probe_results.found_volatile_values,
895 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800896 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800897 probed_rw_vpd=FilterDict(probed_rw_vpd))
898
Ricky Lianga70a1202013-03-15 15:03:17 +0800899 GetGooftool(options).VerifyHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800900 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800901
Andy Cheng0465d132013-03-20 12:12:06 +0800902 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800903 print 'Verification SUCCESS!'
904
905
Ricky Liang7905f272013-03-16 01:57:10 +0800906@Command('decode_hwid_v3',
907 _board_cmd_arg,
908 _hwdb_path_cmd_arg,
909 _hwid_cmd_arg)
910def DecodeHwidV3(options):
911 """Decodes the given v3 HWID and prints out decoded information.
912
913 If no HWID is given, the HWID stored on the device will be loaded and used
914 instead.
915 """
916 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
917 hwdb_path=options.hwdb_path).DecodeHwidV3(
918 options.hwid)
919
Ricky Liang5b4568d2013-04-23 17:15:23 +0800920 results = {}
921 results['board'] = decoded_hwid_context.database.board
922 results['binary_string'] = decoded_hwid_context.binary_string
923 results['components'] = collections.defaultdict(list)
Ricky Liang7905f272013-03-16 01:57:10 +0800924 components = decoded_hwid_context.bom.components
925 for comp_cls in sorted(components):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800926 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
927 if not probed_values:
Ricky Liang7905f272013-03-16 01:57:10 +0800928 db_components = decoded_hwid_context.database.components
Ricky Liang5b4568d2013-04-23 17:15:23 +0800929 probed_values = db_components.GetComponentAttributes(
Ricky Liang58d96e62013-06-06 17:20:45 +0800930 comp_cls, comp_name).get('values')
Ricky Liang5b4568d2013-04-23 17:15:23 +0800931 results['components'][comp_cls].append(
932 {comp_name: probed_values if probed_values else None})
933 # Convert defaultdict to dict.
934 results['components'] = dict(results['components'])
935 print yaml.dump(results, default_flow_style=False)
Ricky Liang7905f272013-03-16 01:57:10 +0800936
937
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800938def Main():
939 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800940
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800941 options = ParseCmdline(
942 'Perform Google required factory tests.',
943 CmdArg('-l', '--log', metavar='PATH',
944 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800945 CmdArg('--suppress-event-logs', action='store_true',
946 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800947 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800948 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800949 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800950 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800951 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
952 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800953 logging.debug('gooftool options: %s', repr(options))
954 try:
955 logging.debug('GOOFTOOL command %r', options.command_name)
956 options.command(options)
957 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
958 except Error, e:
959 logging.exception(e)
960 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
961 except Exception, e:
962 logging.exception(e)
963 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
964
965
966if __name__ == '__main__':
967 Main()