blob: d1d4fbcd5c07fb860bcbeb5f052ac36e07f0f46a [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
Ricky Liangeede7922013-06-19 10:18:41 +080041from cros.factory.hwid import common
cychiang7fe09372012-07-04 14:31:23 +080042from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080043from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080044from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080045
Tammo Spalink5c699832012-07-03 17:50:39 +080046
Tammo Spalink5c699832012-07-03 17:50:39 +080047# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
48# treat that specially (as a smoot exit, as opposed to the more
49# verbose output for generic Error).
50
51
Ricky Lianga70a1202013-03-15 15:03:17 +080052def GetGooftool(options):
53 if options.hwid_version == 2:
54 hwdb_path = getattr(options, 'hwdb_path', None)
55 component_db = (
56 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
57 return Gooftool(hwid_version=2, component_db=component_db)
58 elif options.hwid_version == 3:
59 board = getattr(options, 'board', None)
60 hwdb_path = getattr(options, 'hwdb_path', None)
61 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
62 else:
63 raise Error, 'Invalid HWID version: %r' % options.hwid_version
64
65
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080066@Command('write_hwid',
67 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080068def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080069 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080070
Tammo Spalink95c43732012-07-25 15:57:14 -070071 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080072 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080073 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070074 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080075
76
Ricky Liang53390232013-03-08 15:37:57 +080077_board_cmd_arg = CmdArg(
78 '--board', metavar='BOARD',
79 default=None, help='Board name to test.')
80
Tammo Spalink8fab5312012-05-28 18:33:30 +080081_hwdb_path_cmd_arg = CmdArg(
82 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +080083 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +080084 help='Path to the HWID database.')
85
Tammo Spalink95c43732012-07-25 15:57:14 -070086_hwid_status_list_cmd_arg = CmdArg(
87 '--status', nargs='*', default=['supported'],
88 help='allow only HWIDs with these status values')
89
Jon Salzce124fb2012-10-02 17:42:03 +080090_probe_results_cmd_arg = CmdArg(
91 '--probe_results', metavar='RESULTS.yaml',
92 help=('Output from "gooftool probe" (used instead of '
93 'probing this system).'))
94
Ricky Liang53390232013-03-08 15:37:57 +080095_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080096 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +080097 help='A dict of device info to use instead of fetching from shopfllor '
98 'server.')
99
Jon Salzce124fb2012-10-02 17:42:03 +0800100_hwid_cmd_arg = CmdArg(
101 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800102 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800103
Tammo Spalink95c43732012-07-25 15:57:14 -0700104
105@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800106 _hwdb_path_cmd_arg,
107 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700108 help='optional BOARD name, needed only if data is present '
109 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800110 CmdArg('--bom', metavar='BOM', help='BOM name'),
111 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800112 CmdArg('--optimistic', action='store_true',
113 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700114 CmdArg('--comps', nargs='*', default=[],
115 help='list of canonical component names'),
116 CmdArg('--missing', nargs='*', default=[],
117 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800118 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700119 help='consider only HWIDs within this list of status values'))
120def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800121 """Determine a list of possible HWIDs using provided args and probeing.
122
123 VOLATILE can always be determined by probing. To get a unique
124 result, VARIANT must be specified for all cases where the matching
125 BOM has more than one associated variant code, otherwise all HWID
126 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700127 alternatively be specified using the --stdin_comps argument, which
128 allows specifying a list of canonical names (one per line) on stdin,
129 one per line. Based on what is known from BOM and stdin_comps,
130 determine a list of components to probe for, and use those probe
131 results to resolve a list of matching HWIDs. If no boms,
132 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800133 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800134
135 Returns (on stdout): A list of HWIDs that match the available probe
136 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700137
138 Example:
139
140 // Three ways to specify a keyboard (assuming it is a variant component)
141 gooftool best_match_hwids --missing keyboard
142 gooftool best_match_hwids --variant A or
143 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800144 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800145
Tammo Spalink5c699832012-07-03 17:50:39 +0800146 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700147 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800148 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800149 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800150 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800151 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800152 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700153 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800154 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800155 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800156 device.VariantExists(options.variant)
157 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700158 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700159 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700160 % YamlWrite(sorted(
161 hwid_tool.ComponentSpecClasses(component_spec) &
162 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700163 component_spec = hwid_tool.CombineComponentSpecs(
164 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700165 if options.comps or options.missing:
166 map(comp_db.CompExists, options.comps)
167 map(comp_db.CompClassExists, options.missing)
168 extra_comp_spec = comp_db.CreateComponentSpec(
169 components=options.comps,
170 missing=options.missing)
171 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
172 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
173 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700174 % YamlWrite(sorted(
175 hwid_tool.ComponentSpecClasses(component_spec) &
176 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700177 component_spec = hwid_tool.CombineComponentSpecs(
178 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700179 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700180 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800181 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800182 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
183 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700184 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700185 'as inputs, and cannot be probed for:\n%s'
186 'This problem can often be addressed by specifying all of '
187 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800188 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700189 print 'probing for missing classes:'
190 print YamlWrite(list(missing_classes))
191 probe_results = Probe(target_comp_classes=list(missing_classes),
192 probe_volatile=False, probe_initial_config=False)
193 cooked_components = comp_db.MatchComponentProbeValues(
194 probe_results.found_probe_value_map)
195 if cooked_components.unmatched:
196 sys.exit('ERROR: some probed components are unrecognized:\n%s'
197 % YamlWrite(cooked_components.unmatched))
198 probed_comp_spec = comp_db.CreateComponentSpec(
199 components=cooked_components.matched,
200 missing=probe_results.missing_component_classes)
201 component_spec = hwid_tool.CombineComponentSpecs(
202 component_spec, probed_comp_spec)
203 print YamlWrite({'component data used for matching': {
204 'missing component classes': component_spec.classes_missing,
205 'found components': component_spec.components}})
206 component_data = hwid_tool.ComponentData(
207 extant_components=hwid_tool.ComponentSpecCompClassMap(
208 component_spec).keys(),
209 classes_missing=component_spec.classes_missing)
210 match_tree = device.BuildMatchTree(component_data)
211 if not match_tree:
212 sys.exit('FAILURE: NO matching BOMs found')
213 print 'potential BOMs/VARIANTs:'
214 potential_variants = set()
215 potential_volatiles = set()
216 for bom_name, variant_tree in match_tree.items():
217 print ' BOM: %-8s VARIANTS: %s' % (
218 bom_name, ', '.join(sorted(variant_tree)))
219 for variant_code in variant_tree:
220 potential_variants.add(variant_code)
221 for volatile_code in device.volatiles:
222 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
223 if status in options.status:
224 potential_volatiles.add(volatile_code)
225 print ''
226 if len(potential_variants) == 0:
227 sys.exit('FAILURE: no matching VARIANTs found')
228 if len(potential_volatiles) == 0:
229 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
230 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700231 if (options.optimistic and
232 len(match_tree) == 1 and
233 len(potential_variants) == 1 and
234 len(potential_volatiles) == 1):
235 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
236 potential_variants.pop(),
237 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800238 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700239 print ('probing VOLATILEs to resolve potential matches: %s\n' %
240 ', '.join(sorted(potential_volatiles)))
241 vol_probe_results = Probe(
242 target_comp_classes=[],
243 probe_volatile=True,
244 probe_initial_config=False)
245 cooked_volatiles = device.MatchVolatileValues(
246 vol_probe_results.found_volatile_values)
247 match_tree = device.BuildMatchTree(
248 component_data, cooked_volatiles.matched_tags)
249 matched_hwids = device.GetMatchTreeHwids(match_tree)
250 if matched_hwids:
251 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800252 if matched_hwids[hwid] in options.status:
253 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700254 return
255 print 'exact HWID matching failed, but the following BOMs match: %s' % (
256 ', '.join(sorted(match_tree)))
257 if options.optimistic and len(match_tree) == 1:
258 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800259 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700260 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800261 if len(variant_matches) == 1:
262 var_code = set(variant_matches).pop()
263 elif len(bom.variants) == 1:
264 var_code = set(bom.variants).pop()
265 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700266 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
267 'because there were too many variants to choose from for BOM %r'
268 % bom_name)
269 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
270 for vol_code in device.volatiles
271 if device.GetHwidStatus(bom_name, var_code, vol_code)
272 in options.status]
273 for hwid in hwids:
274 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800275 return
276 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700277 print ('optimistic matching not attempted because either it was '
278 'not requested, or because the number of BOMs was <> 1\n')
279 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800280
281
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800282@Command('probe',
283 CmdArg('--comps', nargs='*',
284 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800285 CmdArg('--fast_fw_probe', action='store_true',
286 help='Do a fast probe for EC and main firmware versions only. '
287 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800288 CmdArg('--no_vol', action='store_true',
289 help='Do not probe volatile data.'),
290 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800291 help='Do not probe initial_config data.'),
292 CmdArg('--include_vpd', action='store_true',
293 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800294def RunProbe(options):
295 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800296 print GetGooftool(options).Probe(
297 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800298 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800299 probe_volatile=not options.no_vol,
300 probe_initial_config=not options.no_ic,
301 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800302
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800303
Tammo Spalink214caf42012-05-28 10:45:00 +0800304@Command('verify_components',
305 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800306 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800307def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800308 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800309
Tammo Spalink5c699832012-07-03 17:50:39 +0800310 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800311 that a corresponding match exists in the component_db -- make sure
312 that these components are present, that they have been approved, but
313 do not check against any specific BOM/HWID configurations.
314 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800315
Andy Chengc531e2f2012-10-15 19:09:17 +0800316 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800317 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800318 options.target_comps)
319 except ValueError, e:
320 sys.exit(e)
321
Ricky Liang53390232013-03-08 15:37:57 +0800322 PrintVerifyComponentsResults(result)
323
324
325def PrintVerifyComponentsResults(result):
326 """Prints out the results of VerifyComponents method call.
327
328 Groups the results into two groups: 'matches' and 'errors', and prints out
329 their values.
330 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800331 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800332 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800333 errors = []
334 for result_list in result.values():
335 for component_name, _, error in result_list:
336 if component_name:
337 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800338 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800339 errors.append(error)
340
Andy Cheng228a8c92012-08-27 10:53:57 +0800341 if matches:
342 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800343 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800344 print '\nerrors:\n %s' % '\n '.join(errors)
345 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800346 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800347 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800348
349
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800350@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700351 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800352 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800353 _probe_results_cmd_arg,
354 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800355def VerifyHwid(options):
356 """Verify system HWID properties match probed device properties.
357
358 First probe components, volatile and initial_config parameters for
359 the DUT. Then use the available device data to produce a list of
360 candidate HWIDs. Then verify the HWID from the DUT is present in
361 that list. Then verify that the DUT initial config values match
362 those specified for its HWID. Finally, verify that VPD contains all
363 the necessary fields as specified by the board data, and when
364 possible verify that values are legitimate.
365 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800366
Ricky Liangf7857c12012-09-17 13:34:41 +0800367 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800368 for key in ro_vpd_keys:
369 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800370 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700371 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800372 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800373 if (known_valid_values is not None) and (value not in known_valid_values):
374 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800375 for key in rw_vpd_keys:
376 if key not in rw_vpd:
377 sys.exit('Missing required RW VPD field: %s' % key)
378 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
379 value = rw_vpd[key]
380 if (known_valid_values is not None) and (value not in known_valid_values):
381 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800382 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800383 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800384
Jon Salz81350812012-10-11 16:13:22 +0800385 if not options.hwid or not options.probe_results:
386 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800387
388 if options.hwid:
389 hwid_str = options.hwid
390 else:
391 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
392 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700393 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800394 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800395 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700396 device = hw_db.GetDevice(hwid.board)
397 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
398 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800399 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800400 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800401 if options.probe_results:
402 # Pull in probe results (including VPD data) from the given file
403 # rather than probing the current system.
404 probe_results = hwid_tool.ProbeResults.Decode(
405 open(options.probe_results).read())
406 ro_vpd = {}
407 rw_vpd = {}
408 for k, v in probe_results.found_volatile_values.items():
409 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
410 if match:
411 del probe_results.found_volatile_values[k]
412 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
413 else:
414 probe_results = Probe()
415 ro_vpd = ReadRoVpd(main_fw_file)
416 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700417 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
418 probe_results.found_probe_value_map)
419 cooked_volatiles = device.MatchVolatileValues(
420 probe_results.found_volatile_values)
421 cooked_initial_configs = device.MatchInitialConfigValues(
422 probe_results.initial_configs)
423 component_data = hwid_tool.ComponentData(
424 extant_components=cooked_components.matched,
425 classes_missing=probe_results.missing_component_classes)
426 match_tree = device.BuildMatchTree(
427 component_data, cooked_volatiles.matched_tags)
428 matched_hwids = device.GetMatchTreeHwids(match_tree)
429 print 'HWID status: %s\n' % hwid_status
430 print 'probed system components:'
431 print YamlWrite(cooked_components.__dict__)
432 print 'missing component classes:'
433 print YamlWrite(probe_results.missing_component_classes)
434 print 'probed volatiles:'
435 print YamlWrite(cooked_volatiles.__dict__)
436 print 'probed initial_configs:'
437 print YamlWrite(cooked_initial_configs)
438 print 'hwid match tree:'
439 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800440 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800441 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700442 found_components=cooked_components.__dict__,
443 missing_component_classes=probe_results.missing_component_classes,
444 volatiles=cooked_volatiles.__dict__,
445 initial_configs=cooked_initial_configs)
446 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800447 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700448 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800449 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700450 YamlWrite(cooked_components.unmatched))
451 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800452 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700453 component_data.Encode())
454 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800455 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700456 (', '.join(sorted(match_tree)), hwid.bom))
457 err_msg += 'target bom %r matches components' % hwid.bom
458 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
459 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800460 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700461 matched_variants = match_tree.get(hwid.bom, {})
462 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800463 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700464 hwid.variant)
465 matched_volatiles = matched_variants.get(hwid.variant, {})
466 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800467 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700468 hwid.volatile)
469 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800470 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800471 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800472 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700473 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800474
475
476@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700477def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800478 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800479
Ricky Lianga70a1202013-03-15 15:03:17 +0800480 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800481
482
483@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700484def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800485 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800486
Ricky Lianga70a1202013-03-15 15:03:17 +0800487 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800488 logging.info('Firmware bitmap initial locale set to %d (%s).',
489 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800490
491
492@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700493def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800494 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800495
Ricky Lianga70a1202013-03-15 15:03:17 +0800496 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800497
498
499@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700500def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800501 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800502
Ricky Lianga70a1202013-03-15 15:03:17 +0800503 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800504
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800505@Command('verify_tpm')
506def VerifyTPM(options): # pylint: disable=W0613
507 """Verify TPM is cleared."""
508
509 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800510
511@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800512def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800513 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800514
Ricky Lianga70a1202013-03-15 15:03:17 +0800515 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800516
517
518@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700519def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800520 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800521
Ricky Lianga70a1202013-03-15 15:03:17 +0800522 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800523 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800524 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800525
526
527@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700528def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800529 """Enable then verify firmware write protection."""
530
Hung-Te Linb21c6682012-08-01 13:53:57 +0800531 def CalculateLegacyRange(fw_type, length, section_data,
532 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800533 ro_size = length / 2
534 ro_a = int(section_data[0] / ro_size)
535 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
536 if ro_a != ro_b:
537 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800538 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800539 ro_offset = ro_a * ro_size
540 return (ro_offset, ro_size)
541
542 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800543 """Calculate protection size, then invoke flashrom.
544
545 Our supported chips only allow write protecting half their total
546 size, so we parition the flash chipset space accordingly.
547 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800548
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800549 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800550 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800551 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800552 if image.has_section(wp_section):
553 section_data = image.get_section_area(wp_section)
554 ro_offset = section_data[0]
555 ro_size = section_data[1]
556 elif image.has_section(legacy_section):
557 section_data = image.get_section_area(legacy_section)
558 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800559 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800560 else:
561 raise Error('could not find %s firmware section %s or %s' %
562 (fw_type, wp_section, legacy_section))
563
564 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
565 ro_offset, ro_size)
566 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800567
568 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800569 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800570 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
571 if ec_fw_file is not None:
572 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800573 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800574 else:
575 logging.warning('EC not write protected (seems there is no EC flash).')
576
577
578@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800579def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800580 """Zero out the GBB flags, in preparation for transition to release state.
581
582 No GBB flags are set in release/shipping state, but they are useful
583 for factory/development. See "gbb_utility --flags" for details.
584 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800585
Ricky Lianga70a1202013-03-15 15:03:17 +0800586 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800587 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800588
589
Jon Salzaa3a30e2013-05-15 15:56:28 +0800590@Command('clear_factory_vpd_entries')
591def ClearFactoryVPDEntries(options): # pylint: disable=W0613
592 """Clears factory.* items in the RW VPD."""
593 entries = GetGooftool(options).ClearFactoryVPDEntries()
594 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
595
596
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800597@Command('prepare_wipe',
598 CmdArg('--fast', action='store_true',
599 help='use non-secure but faster wipe method.'))
600def PrepareWipe(options):
601 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800602
Ricky Lianga70a1202013-03-15 15:03:17 +0800603 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800604
605@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800606 CmdArg('--no_write_protect', action='store_true',
607 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700608 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800609 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800610 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800611 _probe_results_cmd_arg,
612 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800613def Verify(options):
614 """Verifies if whole factory process is ready for finalization.
615
616 This routine performs all the necessary checks to make sure the
617 device is ready to be finalized, but does not modify state. These
618 checks include dev switch, firmware write protection switch, hwid,
619 system time, keys, and root file system.
620 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800621
Hung-Te Lin6d827542012-07-19 11:50:41 +0800622 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800623 VerifyWPSwitch(options)
624 VerifyDevSwitch(options)
625 if options.hwid_version == 2:
626 VerifyHwid(options)
627 elif options.hwid_version == 3:
628 VerifyHwidV3(options)
629 else:
630 raise Error, 'Invalid HWID version: %r' % options.hwid_version
631 VerifySystemTime(options)
632 VerifyKeys(options)
633 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800634 VerifyTPM(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800635
636
Tammo Spalink86a61c62012-05-25 15:10:35 +0800637@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700638def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800639 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800640
Andy Cheng0465d132013-03-20 12:12:06 +0800641 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800642 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800643
644
Jon Salza88b83b2013-05-27 20:00:35 +0800645def CreateReportArchiveBlob(*args, **kwargs):
646 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800647
Jon Salza88b83b2013-05-27 20:00:35 +0800648 Args:
649 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800650
Jon Salza88b83b2013-05-27 20:00:35 +0800651 Returns:
652 An xmlrpclib.Binary object containing a .tar.xz file.
653 """
654 with open(CreateReportArchive(*args, **kwargs)) as f:
655 return xmlrpclib.Binary(f.read())
656
657
658def CreateReportArchive(device_sn=None, add_file=None):
659 """Creates a report archive in a temporary directory.
660
661 Args:
662 device_sn: The device serial number (optional).
663 add_file: A list of files to add (optional).
664
665 Returns:
666 Path to the archive.
667 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800668 def NormalizeAsFileName(token):
669 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800670
671 target_name = '%s%s.tar.xz' % (
672 time.strftime('%Y%m%dT%H%M%SZ',
673 time.gmtime()),
674 ("" if device_sn is None else
675 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800676 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800677
Tammo Spalink86a61c62012-05-25 15:10:35 +0800678 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800679 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800680 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800681 if add_file:
682 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800683 # Require absolute paths since the tar command may change the
684 # directory.
685 if not f.startswith('/'):
686 raise Error('Not an absolute path: %s' % f)
687 if not os.path.exists(f):
688 raise Error('File does not exist: %s' % f)
689 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800690 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800691
692 if ((cmd_result.status == 1) and
693 all((x == '' or
694 'file changed as we read it' in x or
695 "Removing leading `/' from member names" in x)
696 for x in cmd_result.stderr.split('\n'))):
697 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800698 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800699 ignore_stdout=True)
700 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800701 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
702 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800703
Jon Salza88b83b2013-05-27 20:00:35 +0800704 return target_path
705
706_upload_method_cmd_arg = CmdArg(
707 '--upload_method', metavar='METHOD:PARAM',
708 help=('How to perform the upload. METHOD should be one of '
709 '{ftp, shopfloor, ftps, cpfe}.'))
710_add_file_cmd_arg = CmdArg(
711 '--add_file', metavar='FILE', action='append',
712 help='Extra file to include in report (must be an absolute path)')
713
714@Command('upload_report',
715 _upload_method_cmd_arg,
716 _add_file_cmd_arg)
717def UploadReport(options):
718 """Create a report containing key device details."""
719 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
720 device_sn = ro_vpd.get('serial_number', None)
721 if device_sn is None:
722 logging.warning('RO_VPD missing device serial number')
723 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
724 target_path = CreateReportArchive(device_sn)
725
Tammo Spalink86a61c62012-05-25 15:10:35 +0800726 if options.upload_method is None or options.upload_method == 'none':
727 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
728 return
729 method, param = options.upload_method.split(':', 1)
730 if method == 'shopfloor':
731 report_upload.ShopFloorUpload(target_path, param)
732 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700733 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800734 elif method == 'ftps':
735 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
736 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800737 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800738 else:
739 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800740
741
742@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800743 CmdArg('--no_write_protect', action='store_true',
744 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800745 CmdArg('--fast', action='store_true',
746 help='use non-secure but faster wipe method.'),
747 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700748 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800749 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800750 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800751 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800752 _probe_results_cmd_arg,
753 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800754def Finalize(options):
755 """Verify system readiness and trigger transition into release state.
756
Jon Salzaa3a30e2013-05-15 15:56:28 +0800757 This routine does the following:
758 - Verifies system state (see verify command)
759 - Modifies firmware bitmaps to match locale
760 - Clears all factory-friendly flags from the GBB
761 - Removes factory-specific entries from RW_VPD (factory.*)
762 - Enables firmware write protection (cannot rollback after this)
763 - Uploads system logs & reports
764 - Sets the necessary boot flags to cause wipe of the factory image on the
765 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800766 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800767 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800768 SetFirmwareBitmapLocale(options)
769 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800770 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800771 if options.no_write_protect:
772 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800773 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800774 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800775 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800776 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800777 UploadReport(options)
778 PrepareWipe(options)
779
780
Ricky Liang53390232013-03-08 15:37:57 +0800781@Command('verify_components_v3',
782 _board_cmd_arg,
783 _hwdb_path_cmd_arg,
784 CmdArg('target_comps', nargs='*'))
785def VerifyComponentsV3(options):
786 """Verify that probeable components all match entries in the component_db.
787
788 This method uses the HWIDv3 component database to verify components.
789
790 Probe for each component class in the target_comps and verify
791 that a corresponding match exists in the component_db -- make sure
792 that these components are present, that they have been approved, but
793 do not check against any specific BOM/HWID configurations.
794 """
795
Ricky Lianga70a1202013-03-15 15:03:17 +0800796 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800797 PrintVerifyComponentsResults(result)
798
799
800@Command('generate_hwid_v3',
801 _board_cmd_arg,
802 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800803 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800804 _device_info_cmd_arg)
805def GenerateHwidV3(options):
806 """Generates the HWID of the DUT.
807
808 The HWID is generated based on the given device info and the probe results
809 retrieved by probing the DUT. If there are conflits of component information
810 between device info and probe result, priority is given to device info.
811 """
812 try:
Ricky Liang7905f272013-03-16 01:57:10 +0800813 with open(options.device_info) as f:
814 device_info = yaml.load(f.read())
Ricky Liang53390232013-03-08 15:37:57 +0800815 except Exception, e:
816 raise Error, 'Invalid device_info: %s' % e
Ricky Liang7905f272013-03-16 01:57:10 +0800817 if options.probe_results:
818 with open(options.probe_results) as f:
819 probe_results = hwid_tool.ProbeResults.Decode(f.read())
820 else:
821 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800822 print 'device_info:'
823 print device_info
Ricky Liang5b4568d2013-04-23 17:15:23 +0800824 print 'probe results:'
Ricky Liang53390232013-03-08 15:37:57 +0800825 print probe_results.Encode()
826
827 # Do not log device_info for now until we're sure that it does not contain
828 # any sensitive infomation.
829 # TODO(jcliang): Add logging for device_info when appropriate.
830
Andy Cheng0465d132013-03-20 12:12:06 +0800831 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800832 'probe',
833 found_components=probe_results.found_probe_value_map,
834 missing_component_classes=probe_results.missing_component_classes,
835 volatiles=probe_results.found_volatile_values,
836 initial_configs=probe_results.initial_configs)
837
Ricky Lianga70a1202013-03-15 15:03:17 +0800838 hwid_object = GetGooftool(options).GenerateHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800839 device_info, probe_results)
Ricky Liang53390232013-03-08 15:37:57 +0800840
841 final_bom = {}
842 for component_class, component_values in (
843 hwid_object.bom.components.iteritems()):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800844 final_bom[component_class] = [v.probed_values for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800845 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800846 'final_bom',
847 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800848 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800849 'generated_hwid',
850 encoded_string=hwid_object.encoded_string,
851 binary_string=hwid_object.binary_string)
852 print 'Encoded HWID string:', hwid_object.encoded_string
853 print 'Binary HWID string:', hwid_object.binary_string
854
855
856@Command('verify_hwid_v3',
857 _board_cmd_arg,
858 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800859 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800860 _hwid_cmd_arg)
861def VerifyHwidV3(options):
862 """Verify system HWID properties match probed device properties.
863
864 First probe components, volatile and initial_config parameters for
865 the DUT. Then use the available device data to produce a list of
866 candidate HWIDs. Then verify the HWID from the DUT is present in
867 that list. Then verify that the DUT initial config values match
868 those specified for its HWID. Finally, verify that VPD contains all
869 the necessary fields as specified by the board data, and when
870 possible verify that values are legitimate.
871 """
Ricky Liang7905f272013-03-16 01:57:10 +0800872 if not options.probe_results:
873 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800874 if options.hwid:
875 hwid_str = options.hwid
876 else:
877 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
878 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
879 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800880 if options.probe_results:
881 # Pull in probe results (including VPD data) from the given file
882 # rather than probing the current system.
883 with open(options.probe_results) as f:
884 probe_results = hwid_tool.ProbeResults.Decode(f.read())
885 probed_ro_vpd = {}
886 probed_rw_vpd = {}
887 for k, v in probe_results.found_volatile_values.items():
888 # Use items(), not iteritems(), since we will be modifying the dict in the
889 # loop.
890 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
891 if match:
892 del probe_results.found_volatile_values[k]
893 (probed_ro_vpd if match.group(1) == 'ro'
894 else probed_rw_vpd)[match.group(2)] = v
895 else:
896 probe_results = Probe()
897 probed_ro_vpd = ReadRoVpd(main_fw_file)
898 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800899 print 'probe result:'
900 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800901 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800902 'probe',
903 found_components=probe_results.found_probe_value_map,
904 missing_component_classes=probe_results.missing_component_classes,
905 volatiles=probe_results.found_volatile_values,
906 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800907 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800908 probed_rw_vpd=FilterDict(probed_rw_vpd))
909
Ricky Liangeede7922013-06-19 10:18:41 +0800910 if not options.board:
911 options.board = common.ProbeBoard(hwid_str)
Ricky Lianga70a1202013-03-15 15:03:17 +0800912 GetGooftool(options).VerifyHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800913 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800914
Andy Cheng0465d132013-03-20 12:12:06 +0800915 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800916 print 'Verification SUCCESS!'
917
918
Ricky Liang59611a62013-06-11 13:47:33 +0800919def ParseDecodedHWID(hwid):
920 """Parse the HWID object into a more compact dict.
921
922 Args:
923 hwid: A decoded HWID object.
924
925 Returns:
926 A dict containing the board name, the binary string, and the list of
927 components.
928 """
929 results = {}
930 results['board'] = hwid.database.board
931 results['binary_string'] = hwid.binary_string
932 results['components'] = collections.defaultdict(list)
933 components = hwid.bom.components
934 for comp_cls in sorted(components):
935 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
936 if not probed_values:
937 db_components = hwid.database.components
938 probed_values = db_components.GetComponentAttributes(
939 comp_cls, comp_name).get('values')
940 results['components'][comp_cls].append(
941 {comp_name: probed_values if probed_values else None})
942 # Convert defaultdict to dict.
943 results['components'] = dict(results['components'])
944 return results
945
946
Ricky Liang7905f272013-03-16 01:57:10 +0800947@Command('decode_hwid_v3',
948 _board_cmd_arg,
949 _hwdb_path_cmd_arg,
950 _hwid_cmd_arg)
951def DecodeHwidV3(options):
952 """Decodes the given v3 HWID and prints out decoded information.
953
954 If no HWID is given, the HWID stored on the device will be loaded and used
955 instead.
956 """
Ricky Liangeede7922013-06-19 10:18:41 +0800957 if not options.board:
958 options.board = common.ProbeBoard(options.hwid)
Ricky Liang7905f272013-03-16 01:57:10 +0800959 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
960 hwdb_path=options.hwdb_path).DecodeHwidV3(
961 options.hwid)
Ricky Liang59611a62013-06-11 13:47:33 +0800962 print yaml.dump(ParseDecodedHWID(decoded_hwid_context),
963 default_flow_style=False)
Ricky Liang7905f272013-03-16 01:57:10 +0800964
965
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800966def Main():
967 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800968
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800969 options = ParseCmdline(
970 'Perform Google required factory tests.',
971 CmdArg('-l', '--log', metavar='PATH',
972 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800973 CmdArg('--suppress-event-logs', action='store_true',
974 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800975 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800976 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800977 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800978 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800979 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
980 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800981 logging.debug('gooftool options: %s', repr(options))
982 try:
983 logging.debug('GOOFTOOL command %r', options.command_name)
984 options.command(options)
985 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
986 except Error, e:
987 logging.exception(e)
988 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
989 except Exception, e:
990 logging.exception(e)
991 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
992
993
994if __name__ == '__main__':
995 Main()