blob: 60694e39cf4dde8d3937d46206eaf2cba25d2839 [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.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800284 CmdArg('--fast_fw_probe', action='store_true',
285 help='Do a fast probe for EC and main firmware versions only. '
286 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800287 CmdArg('--no_vol', action='store_true',
288 help='Do not probe volatile data.'),
289 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800290 help='Do not probe initial_config data.'),
291 CmdArg('--include_vpd', action='store_true',
292 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800293def RunProbe(options):
294 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800295 print GetGooftool(options).Probe(
296 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800297 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800298 probe_volatile=not options.no_vol,
299 probe_initial_config=not options.no_ic,
300 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800301
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800302
Tammo Spalink214caf42012-05-28 10:45:00 +0800303@Command('verify_components',
304 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800305 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800306def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800307 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800308
Tammo Spalink5c699832012-07-03 17:50:39 +0800309 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800310 that a corresponding match exists in the component_db -- make sure
311 that these components are present, that they have been approved, but
312 do not check against any specific BOM/HWID configurations.
313 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800314
Andy Chengc531e2f2012-10-15 19:09:17 +0800315 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800316 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800317 options.target_comps)
318 except ValueError, e:
319 sys.exit(e)
320
Ricky Liang53390232013-03-08 15:37:57 +0800321 PrintVerifyComponentsResults(result)
322
323
324def PrintVerifyComponentsResults(result):
325 """Prints out the results of VerifyComponents method call.
326
327 Groups the results into two groups: 'matches' and 'errors', and prints out
328 their values.
329 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800330 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800331 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800332 errors = []
333 for result_list in result.values():
334 for component_name, _, error in result_list:
335 if component_name:
336 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800337 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800338 errors.append(error)
339
Andy Cheng228a8c92012-08-27 10:53:57 +0800340 if matches:
341 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800342 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800343 print '\nerrors:\n %s' % '\n '.join(errors)
344 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800345 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800346 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800347
348
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800349@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700350 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800351 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800352 _probe_results_cmd_arg,
353 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800354def VerifyHwid(options):
355 """Verify system HWID properties match probed device properties.
356
357 First probe components, volatile and initial_config parameters for
358 the DUT. Then use the available device data to produce a list of
359 candidate HWIDs. Then verify the HWID from the DUT is present in
360 that list. Then verify that the DUT initial config values match
361 those specified for its HWID. Finally, verify that VPD contains all
362 the necessary fields as specified by the board data, and when
363 possible verify that values are legitimate.
364 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800365
Ricky Liangf7857c12012-09-17 13:34:41 +0800366 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800367 for key in ro_vpd_keys:
368 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800369 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700370 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800371 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800372 if (known_valid_values is not None) and (value not in known_valid_values):
373 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800374 for key in rw_vpd_keys:
375 if key not in rw_vpd:
376 sys.exit('Missing required RW VPD field: %s' % key)
377 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
378 value = rw_vpd[key]
379 if (known_valid_values is not None) and (value not in known_valid_values):
380 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800381 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800382 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800383
Jon Salz81350812012-10-11 16:13:22 +0800384 if not options.hwid or not options.probe_results:
385 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800386
387 if options.hwid:
388 hwid_str = options.hwid
389 else:
390 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
391 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700392 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800393 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800394 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700395 device = hw_db.GetDevice(hwid.board)
396 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
397 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800398 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800399 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800400 if options.probe_results:
401 # Pull in probe results (including VPD data) from the given file
402 # rather than probing the current system.
403 probe_results = hwid_tool.ProbeResults.Decode(
404 open(options.probe_results).read())
405 ro_vpd = {}
406 rw_vpd = {}
407 for k, v in probe_results.found_volatile_values.items():
408 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
409 if match:
410 del probe_results.found_volatile_values[k]
411 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
412 else:
413 probe_results = Probe()
414 ro_vpd = ReadRoVpd(main_fw_file)
415 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700416 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
417 probe_results.found_probe_value_map)
418 cooked_volatiles = device.MatchVolatileValues(
419 probe_results.found_volatile_values)
420 cooked_initial_configs = device.MatchInitialConfigValues(
421 probe_results.initial_configs)
422 component_data = hwid_tool.ComponentData(
423 extant_components=cooked_components.matched,
424 classes_missing=probe_results.missing_component_classes)
425 match_tree = device.BuildMatchTree(
426 component_data, cooked_volatiles.matched_tags)
427 matched_hwids = device.GetMatchTreeHwids(match_tree)
428 print 'HWID status: %s\n' % hwid_status
429 print 'probed system components:'
430 print YamlWrite(cooked_components.__dict__)
431 print 'missing component classes:'
432 print YamlWrite(probe_results.missing_component_classes)
433 print 'probed volatiles:'
434 print YamlWrite(cooked_volatiles.__dict__)
435 print 'probed initial_configs:'
436 print YamlWrite(cooked_initial_configs)
437 print 'hwid match tree:'
438 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800439 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800440 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700441 found_components=cooked_components.__dict__,
442 missing_component_classes=probe_results.missing_component_classes,
443 volatiles=cooked_volatiles.__dict__,
444 initial_configs=cooked_initial_configs)
445 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800446 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700447 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800448 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700449 YamlWrite(cooked_components.unmatched))
450 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800451 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700452 component_data.Encode())
453 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800454 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700455 (', '.join(sorted(match_tree)), hwid.bom))
456 err_msg += 'target bom %r matches components' % hwid.bom
457 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
458 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800459 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700460 matched_variants = match_tree.get(hwid.bom, {})
461 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800462 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700463 hwid.variant)
464 matched_volatiles = matched_variants.get(hwid.variant, {})
465 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800466 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700467 hwid.volatile)
468 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800469 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800470 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800471 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700472 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800473
474
475@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700476def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800477 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800478
Ricky Lianga70a1202013-03-15 15:03:17 +0800479 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800480
481
482@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700483def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800484 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800485
Ricky Lianga70a1202013-03-15 15:03:17 +0800486 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800487 logging.info('Firmware bitmap initial locale set to %d (%s).',
488 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800489
490
491@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700492def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800493 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800494
Ricky Lianga70a1202013-03-15 15:03:17 +0800495 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496
497
498@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700499def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800500 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800501
Ricky Lianga70a1202013-03-15 15:03:17 +0800502 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800504@Command('verify_tpm')
505def VerifyTPM(options): # pylint: disable=W0613
506 """Verify TPM is cleared."""
507
508 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800509
510@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800511def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800512 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800513
Ricky Lianga70a1202013-03-15 15:03:17 +0800514 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800515
516
517@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700518def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800519 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800520
Ricky Lianga70a1202013-03-15 15:03:17 +0800521 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800522 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800523 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800524
525
526@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700527def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800528 """Enable then verify firmware write protection."""
529
Hung-Te Linb21c6682012-08-01 13:53:57 +0800530 def CalculateLegacyRange(fw_type, length, section_data,
531 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800532 ro_size = length / 2
533 ro_a = int(section_data[0] / ro_size)
534 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
535 if ro_a != ro_b:
536 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800537 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800538 ro_offset = ro_a * ro_size
539 return (ro_offset, ro_size)
540
541 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800542 """Calculate protection size, then invoke flashrom.
543
544 Our supported chips only allow write protecting half their total
545 size, so we parition the flash chipset space accordingly.
546 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800547
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800548 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800549 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800550 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800551 if image.has_section(wp_section):
552 section_data = image.get_section_area(wp_section)
553 ro_offset = section_data[0]
554 ro_size = section_data[1]
555 elif image.has_section(legacy_section):
556 section_data = image.get_section_area(legacy_section)
557 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800558 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800559 else:
560 raise Error('could not find %s firmware section %s or %s' %
561 (fw_type, wp_section, legacy_section))
562
563 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
564 ro_offset, ro_size)
565 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800566
567 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800568 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800569 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
570 if ec_fw_file is not None:
571 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800572 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800573 else:
574 logging.warning('EC not write protected (seems there is no EC flash).')
575
576
577@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800578def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800579 """Zero out the GBB flags, in preparation for transition to release state.
580
581 No GBB flags are set in release/shipping state, but they are useful
582 for factory/development. See "gbb_utility --flags" for details.
583 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800584
Ricky Lianga70a1202013-03-15 15:03:17 +0800585 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800586 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800587
588
Jon Salzaa3a30e2013-05-15 15:56:28 +0800589@Command('clear_factory_vpd_entries')
590def ClearFactoryVPDEntries(options): # pylint: disable=W0613
591 """Clears factory.* items in the RW VPD."""
592 entries = GetGooftool(options).ClearFactoryVPDEntries()
593 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
594
595
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800596@Command('prepare_wipe',
597 CmdArg('--fast', action='store_true',
598 help='use non-secure but faster wipe method.'))
599def PrepareWipe(options):
600 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800601
Ricky Lianga70a1202013-03-15 15:03:17 +0800602 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800603
604@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800605 CmdArg('--no_write_protect', action='store_true',
606 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700607 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800608 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800609 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800610 _probe_results_cmd_arg,
611 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800612def Verify(options):
613 """Verifies if whole factory process is ready for finalization.
614
615 This routine performs all the necessary checks to make sure the
616 device is ready to be finalized, but does not modify state. These
617 checks include dev switch, firmware write protection switch, hwid,
618 system time, keys, and root file system.
619 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800620
Hung-Te Lin6d827542012-07-19 11:50:41 +0800621 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800622 VerifyWPSwitch(options)
623 VerifyDevSwitch(options)
624 if options.hwid_version == 2:
625 VerifyHwid(options)
626 elif options.hwid_version == 3:
627 VerifyHwidV3(options)
628 else:
629 raise Error, 'Invalid HWID version: %r' % options.hwid_version
630 VerifySystemTime(options)
631 VerifyKeys(options)
632 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800633 VerifyTPM(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800634
635
Tammo Spalink86a61c62012-05-25 15:10:35 +0800636@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700637def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800638 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800639
Andy Cheng0465d132013-03-20 12:12:06 +0800640 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800641 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800642
643
Jon Salza88b83b2013-05-27 20:00:35 +0800644def CreateReportArchiveBlob(*args, **kwargs):
645 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800646
Jon Salza88b83b2013-05-27 20:00:35 +0800647 Args:
648 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800649
Jon Salza88b83b2013-05-27 20:00:35 +0800650 Returns:
651 An xmlrpclib.Binary object containing a .tar.xz file.
652 """
653 with open(CreateReportArchive(*args, **kwargs)) as f:
654 return xmlrpclib.Binary(f.read())
655
656
657def CreateReportArchive(device_sn=None, add_file=None):
658 """Creates a report archive in a temporary directory.
659
660 Args:
661 device_sn: The device serial number (optional).
662 add_file: A list of files to add (optional).
663
664 Returns:
665 Path to the archive.
666 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800667 def NormalizeAsFileName(token):
668 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800669
670 target_name = '%s%s.tar.xz' % (
671 time.strftime('%Y%m%dT%H%M%SZ',
672 time.gmtime()),
673 ("" if device_sn is None else
674 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800675 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800676
Tammo Spalink86a61c62012-05-25 15:10:35 +0800677 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800678 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800679 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800680 if add_file:
681 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800682 # Require absolute paths since the tar command may change the
683 # directory.
684 if not f.startswith('/'):
685 raise Error('Not an absolute path: %s' % f)
686 if not os.path.exists(f):
687 raise Error('File does not exist: %s' % f)
688 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800689 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800690
691 if ((cmd_result.status == 1) and
692 all((x == '' or
693 'file changed as we read it' in x or
694 "Removing leading `/' from member names" in x)
695 for x in cmd_result.stderr.split('\n'))):
696 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800697 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800698 ignore_stdout=True)
699 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800700 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
701 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800702
Jon Salza88b83b2013-05-27 20:00:35 +0800703 return target_path
704
705_upload_method_cmd_arg = CmdArg(
706 '--upload_method', metavar='METHOD:PARAM',
707 help=('How to perform the upload. METHOD should be one of '
708 '{ftp, shopfloor, ftps, cpfe}.'))
709_add_file_cmd_arg = CmdArg(
710 '--add_file', metavar='FILE', action='append',
711 help='Extra file to include in report (must be an absolute path)')
712
713@Command('upload_report',
714 _upload_method_cmd_arg,
715 _add_file_cmd_arg)
716def UploadReport(options):
717 """Create a report containing key device details."""
718 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
719 device_sn = ro_vpd.get('serial_number', None)
720 if device_sn is None:
721 logging.warning('RO_VPD missing device serial number')
722 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
723 target_path = CreateReportArchive(device_sn)
724
Tammo Spalink86a61c62012-05-25 15:10:35 +0800725 if options.upload_method is None or options.upload_method == 'none':
726 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
727 return
728 method, param = options.upload_method.split(':', 1)
729 if method == 'shopfloor':
730 report_upload.ShopFloorUpload(target_path, param)
731 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700732 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800733 elif method == 'ftps':
734 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
735 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800736 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800737 else:
738 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800739
740
741@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800742 CmdArg('--no_write_protect', action='store_true',
743 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800744 CmdArg('--fast', action='store_true',
745 help='use non-secure but faster wipe method.'),
746 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700747 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800748 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800749 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800750 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800751 _probe_results_cmd_arg,
752 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800753def Finalize(options):
754 """Verify system readiness and trigger transition into release state.
755
Jon Salzaa3a30e2013-05-15 15:56:28 +0800756 This routine does the following:
757 - Verifies system state (see verify command)
758 - Modifies firmware bitmaps to match locale
759 - Clears all factory-friendly flags from the GBB
760 - Removes factory-specific entries from RW_VPD (factory.*)
761 - Enables firmware write protection (cannot rollback after this)
762 - Uploads system logs & reports
763 - Sets the necessary boot flags to cause wipe of the factory image on the
764 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800765 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800766 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800767 SetFirmwareBitmapLocale(options)
768 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800769 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800770 if options.no_write_protect:
771 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800772 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800773 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800774 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800775 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800776 UploadReport(options)
777 PrepareWipe(options)
778
779
Ricky Liang53390232013-03-08 15:37:57 +0800780@Command('verify_components_v3',
781 _board_cmd_arg,
782 _hwdb_path_cmd_arg,
783 CmdArg('target_comps', nargs='*'))
784def VerifyComponentsV3(options):
785 """Verify that probeable components all match entries in the component_db.
786
787 This method uses the HWIDv3 component database to verify components.
788
789 Probe for each component class in the target_comps and verify
790 that a corresponding match exists in the component_db -- make sure
791 that these components are present, that they have been approved, but
792 do not check against any specific BOM/HWID configurations.
793 """
794
Ricky Lianga70a1202013-03-15 15:03:17 +0800795 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800796 PrintVerifyComponentsResults(result)
797
798
799@Command('generate_hwid_v3',
800 _board_cmd_arg,
801 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800802 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800803 _device_info_cmd_arg)
804def GenerateHwidV3(options):
805 """Generates the HWID of the DUT.
806
807 The HWID is generated based on the given device info and the probe results
808 retrieved by probing the DUT. If there are conflits of component information
809 between device info and probe result, priority is given to device info.
810 """
811 try:
Ricky Liang7905f272013-03-16 01:57:10 +0800812 with open(options.device_info) as f:
813 device_info = yaml.load(f.read())
Ricky Liang53390232013-03-08 15:37:57 +0800814 except Exception, e:
815 raise Error, 'Invalid device_info: %s' % e
Ricky Liang7905f272013-03-16 01:57:10 +0800816 if options.probe_results:
817 with open(options.probe_results) as f:
818 probe_results = hwid_tool.ProbeResults.Decode(f.read())
819 else:
820 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800821 print 'device_info:'
822 print device_info
Ricky Liang5b4568d2013-04-23 17:15:23 +0800823 print 'probe results:'
Ricky Liang53390232013-03-08 15:37:57 +0800824 print probe_results.Encode()
825
826 # Do not log device_info for now until we're sure that it does not contain
827 # any sensitive infomation.
828 # TODO(jcliang): Add logging for device_info when appropriate.
829
Andy Cheng0465d132013-03-20 12:12:06 +0800830 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800831 'probe',
832 found_components=probe_results.found_probe_value_map,
833 missing_component_classes=probe_results.missing_component_classes,
834 volatiles=probe_results.found_volatile_values,
835 initial_configs=probe_results.initial_configs)
836
Ricky Lianga70a1202013-03-15 15:03:17 +0800837 hwid_object = GetGooftool(options).GenerateHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800838 device_info, probe_results)
Ricky Liang53390232013-03-08 15:37:57 +0800839
840 final_bom = {}
841 for component_class, component_values in (
842 hwid_object.bom.components.iteritems()):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800843 final_bom[component_class] = [v.probed_values for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800844 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800845 'final_bom',
846 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800847 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800848 'generated_hwid',
849 encoded_string=hwid_object.encoded_string,
850 binary_string=hwid_object.binary_string)
851 print 'Encoded HWID string:', hwid_object.encoded_string
852 print 'Binary HWID string:', hwid_object.binary_string
853
854
855@Command('verify_hwid_v3',
856 _board_cmd_arg,
857 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800858 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800859 _hwid_cmd_arg)
860def VerifyHwidV3(options):
861 """Verify system HWID properties match probed device properties.
862
863 First probe components, volatile and initial_config parameters for
864 the DUT. Then use the available device data to produce a list of
865 candidate HWIDs. Then verify the HWID from the DUT is present in
866 that list. Then verify that the DUT initial config values match
867 those specified for its HWID. Finally, verify that VPD contains all
868 the necessary fields as specified by the board data, and when
869 possible verify that values are legitimate.
870 """
Ricky Liang7905f272013-03-16 01:57:10 +0800871 if not options.probe_results:
872 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800873 if options.hwid:
874 hwid_str = options.hwid
875 else:
876 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
877 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
878 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800879 if options.probe_results:
880 # Pull in probe results (including VPD data) from the given file
881 # rather than probing the current system.
882 with open(options.probe_results) as f:
883 probe_results = hwid_tool.ProbeResults.Decode(f.read())
884 probed_ro_vpd = {}
885 probed_rw_vpd = {}
886 for k, v in probe_results.found_volatile_values.items():
887 # Use items(), not iteritems(), since we will be modifying the dict in the
888 # loop.
889 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
890 if match:
891 del probe_results.found_volatile_values[k]
892 (probed_ro_vpd if match.group(1) == 'ro'
893 else probed_rw_vpd)[match.group(2)] = v
894 else:
895 probe_results = Probe()
896 probed_ro_vpd = ReadRoVpd(main_fw_file)
897 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800898 print 'probe result:'
899 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800900 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800901 'probe',
902 found_components=probe_results.found_probe_value_map,
903 missing_component_classes=probe_results.missing_component_classes,
904 volatiles=probe_results.found_volatile_values,
905 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800906 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800907 probed_rw_vpd=FilterDict(probed_rw_vpd))
908
Ricky Lianga70a1202013-03-15 15:03:17 +0800909 GetGooftool(options).VerifyHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800910 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800911
Andy Cheng0465d132013-03-20 12:12:06 +0800912 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800913 print 'Verification SUCCESS!'
914
915
Ricky Liang59611a62013-06-11 13:47:33 +0800916def ParseDecodedHWID(hwid):
917 """Parse the HWID object into a more compact dict.
918
919 Args:
920 hwid: A decoded HWID object.
921
922 Returns:
923 A dict containing the board name, the binary string, and the list of
924 components.
925 """
926 results = {}
927 results['board'] = hwid.database.board
928 results['binary_string'] = hwid.binary_string
929 results['components'] = collections.defaultdict(list)
930 components = hwid.bom.components
931 for comp_cls in sorted(components):
932 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
933 if not probed_values:
934 db_components = hwid.database.components
935 probed_values = db_components.GetComponentAttributes(
936 comp_cls, comp_name).get('values')
937 results['components'][comp_cls].append(
938 {comp_name: probed_values if probed_values else None})
939 # Convert defaultdict to dict.
940 results['components'] = dict(results['components'])
941 return results
942
943
Ricky Liang7905f272013-03-16 01:57:10 +0800944@Command('decode_hwid_v3',
945 _board_cmd_arg,
946 _hwdb_path_cmd_arg,
947 _hwid_cmd_arg)
948def DecodeHwidV3(options):
949 """Decodes the given v3 HWID and prints out decoded information.
950
951 If no HWID is given, the HWID stored on the device will be loaded and used
952 instead.
953 """
954 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
955 hwdb_path=options.hwdb_path).DecodeHwidV3(
956 options.hwid)
Ricky Liang59611a62013-06-11 13:47:33 +0800957 print yaml.dump(ParseDecodedHWID(decoded_hwid_context),
958 default_flow_style=False)
Ricky Liang7905f272013-03-16 01:57:10 +0800959
960
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800961def Main():
962 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800963
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800964 options = ParseCmdline(
965 'Perform Google required factory tests.',
966 CmdArg('-l', '--log', metavar='PATH',
967 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800968 CmdArg('--suppress-event-logs', action='store_true',
969 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800970 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800971 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800972 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800973 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800974 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
975 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800976 logging.debug('gooftool options: %s', repr(options))
977 try:
978 logging.debug('GOOFTOOL command %r', options.command_name)
979 options.command(options)
980 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
981 except Error, e:
982 logging.exception(e)
983 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
984 except Exception, e:
985 logging.exception(e)
986 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
987
988
989if __name__ == '__main__':
990 Main()