blob: 228658d25769a21f80537484d55eb96355d8695b [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
Ricky Liangf1ded8a2013-06-25 11:29:01 +080042from cros.factory.test import shopfloor
cychiang7fe09372012-07-04 14:31:23 +080043from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080044from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080045from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080046
Tammo Spalink5c699832012-07-03 17:50:39 +080047
Tammo Spalink5c699832012-07-03 17:50:39 +080048# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
49# treat that specially (as a smoot exit, as opposed to the more
50# verbose output for generic Error).
51
52
Ricky Lianga70a1202013-03-15 15:03:17 +080053def GetGooftool(options):
54 if options.hwid_version == 2:
55 hwdb_path = getattr(options, 'hwdb_path', None)
56 component_db = (
57 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
58 return Gooftool(hwid_version=2, component_db=component_db)
59 elif options.hwid_version == 3:
60 board = getattr(options, 'board', None)
61 hwdb_path = getattr(options, 'hwdb_path', None)
62 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
63 else:
64 raise Error, 'Invalid HWID version: %r' % options.hwid_version
65
66
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080067@Command('write_hwid',
68 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080069def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080070 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080071
Tammo Spalink95c43732012-07-25 15:57:14 -070072 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080073 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080074 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070075 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080076
77
Ricky Liang53390232013-03-08 15:37:57 +080078_board_cmd_arg = CmdArg(
79 '--board', metavar='BOARD',
80 default=None, help='Board name to test.')
81
Tammo Spalink8fab5312012-05-28 18:33:30 +080082_hwdb_path_cmd_arg = CmdArg(
83 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +080084 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +080085 help='Path to the HWID database.')
86
Tammo Spalink95c43732012-07-25 15:57:14 -070087_hwid_status_list_cmd_arg = CmdArg(
88 '--status', nargs='*', default=['supported'],
89 help='allow only HWIDs with these status values')
90
Jon Salzce124fb2012-10-02 17:42:03 +080091_probe_results_cmd_arg = CmdArg(
92 '--probe_results', metavar='RESULTS.yaml',
93 help=('Output from "gooftool probe" (used instead of '
94 'probing this system).'))
95
Ricky Liang53390232013-03-08 15:37:57 +080096_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080097 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +080098 help='A dict of device info to use instead of fetching from shopfllor '
99 'server.')
100
Jon Salzce124fb2012-10-02 17:42:03 +0800101_hwid_cmd_arg = CmdArg(
102 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800103 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800104
Tammo Spalink95c43732012-07-25 15:57:14 -0700105
106@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800107 _hwdb_path_cmd_arg,
108 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700109 help='optional BOARD name, needed only if data is present '
110 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800111 CmdArg('--bom', metavar='BOM', help='BOM name'),
112 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800113 CmdArg('--optimistic', action='store_true',
114 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700115 CmdArg('--comps', nargs='*', default=[],
116 help='list of canonical component names'),
117 CmdArg('--missing', nargs='*', default=[],
118 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800119 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700120 help='consider only HWIDs within this list of status values'))
121def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800122 """Determine a list of possible HWIDs using provided args and probeing.
123
124 VOLATILE can always be determined by probing. To get a unique
125 result, VARIANT must be specified for all cases where the matching
126 BOM has more than one associated variant code, otherwise all HWID
127 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700128 alternatively be specified using the --stdin_comps argument, which
129 allows specifying a list of canonical names (one per line) on stdin,
130 one per line. Based on what is known from BOM and stdin_comps,
131 determine a list of components to probe for, and use those probe
132 results to resolve a list of matching HWIDs. If no boms,
133 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800134 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800135
136 Returns (on stdout): A list of HWIDs that match the available probe
137 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700138
139 Example:
140
141 // Three ways to specify a keyboard (assuming it is a variant component)
142 gooftool best_match_hwids --missing keyboard
143 gooftool best_match_hwids --variant A or
144 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800145 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800146
Tammo Spalink5c699832012-07-03 17:50:39 +0800147 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700148 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800149 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800150 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800151 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800152 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800153 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700154 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800155 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800156 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800157 device.VariantExists(options.variant)
158 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700159 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700160 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700161 % YamlWrite(sorted(
162 hwid_tool.ComponentSpecClasses(component_spec) &
163 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700164 component_spec = hwid_tool.CombineComponentSpecs(
165 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700166 if options.comps or options.missing:
167 map(comp_db.CompExists, options.comps)
168 map(comp_db.CompClassExists, options.missing)
169 extra_comp_spec = comp_db.CreateComponentSpec(
170 components=options.comps,
171 missing=options.missing)
172 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
173 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
174 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700175 % YamlWrite(sorted(
176 hwid_tool.ComponentSpecClasses(component_spec) &
177 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700178 component_spec = hwid_tool.CombineComponentSpecs(
179 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700180 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700181 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800182 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800183 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
184 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700185 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700186 'as inputs, and cannot be probed for:\n%s'
187 'This problem can often be addressed by specifying all of '
188 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800189 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700190 print 'probing for missing classes:'
191 print YamlWrite(list(missing_classes))
192 probe_results = Probe(target_comp_classes=list(missing_classes),
193 probe_volatile=False, probe_initial_config=False)
194 cooked_components = comp_db.MatchComponentProbeValues(
195 probe_results.found_probe_value_map)
196 if cooked_components.unmatched:
197 sys.exit('ERROR: some probed components are unrecognized:\n%s'
198 % YamlWrite(cooked_components.unmatched))
199 probed_comp_spec = comp_db.CreateComponentSpec(
200 components=cooked_components.matched,
201 missing=probe_results.missing_component_classes)
202 component_spec = hwid_tool.CombineComponentSpecs(
203 component_spec, probed_comp_spec)
204 print YamlWrite({'component data used for matching': {
205 'missing component classes': component_spec.classes_missing,
206 'found components': component_spec.components}})
207 component_data = hwid_tool.ComponentData(
208 extant_components=hwid_tool.ComponentSpecCompClassMap(
209 component_spec).keys(),
210 classes_missing=component_spec.classes_missing)
211 match_tree = device.BuildMatchTree(component_data)
212 if not match_tree:
213 sys.exit('FAILURE: NO matching BOMs found')
214 print 'potential BOMs/VARIANTs:'
215 potential_variants = set()
216 potential_volatiles = set()
217 for bom_name, variant_tree in match_tree.items():
218 print ' BOM: %-8s VARIANTS: %s' % (
219 bom_name, ', '.join(sorted(variant_tree)))
220 for variant_code in variant_tree:
221 potential_variants.add(variant_code)
222 for volatile_code in device.volatiles:
223 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
224 if status in options.status:
225 potential_volatiles.add(volatile_code)
226 print ''
227 if len(potential_variants) == 0:
228 sys.exit('FAILURE: no matching VARIANTs found')
229 if len(potential_volatiles) == 0:
230 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
231 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700232 if (options.optimistic and
233 len(match_tree) == 1 and
234 len(potential_variants) == 1 and
235 len(potential_volatiles) == 1):
236 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
237 potential_variants.pop(),
238 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800239 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700240 print ('probing VOLATILEs to resolve potential matches: %s\n' %
241 ', '.join(sorted(potential_volatiles)))
242 vol_probe_results = Probe(
243 target_comp_classes=[],
244 probe_volatile=True,
245 probe_initial_config=False)
246 cooked_volatiles = device.MatchVolatileValues(
247 vol_probe_results.found_volatile_values)
248 match_tree = device.BuildMatchTree(
249 component_data, cooked_volatiles.matched_tags)
250 matched_hwids = device.GetMatchTreeHwids(match_tree)
251 if matched_hwids:
252 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800253 if matched_hwids[hwid] in options.status:
254 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700255 return
256 print 'exact HWID matching failed, but the following BOMs match: %s' % (
257 ', '.join(sorted(match_tree)))
258 if options.optimistic and len(match_tree) == 1:
259 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800260 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700261 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800262 if len(variant_matches) == 1:
263 var_code = set(variant_matches).pop()
264 elif len(bom.variants) == 1:
265 var_code = set(bom.variants).pop()
266 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700267 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
268 'because there were too many variants to choose from for BOM %r'
269 % bom_name)
270 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
271 for vol_code in device.volatiles
272 if device.GetHwidStatus(bom_name, var_code, vol_code)
273 in options.status]
274 for hwid in hwids:
275 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800276 return
277 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700278 print ('optimistic matching not attempted because either it was '
279 'not requested, or because the number of BOMs was <> 1\n')
280 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800281
282
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800283@Command('probe',
284 CmdArg('--comps', nargs='*',
285 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800286 CmdArg('--fast_fw_probe', action='store_true',
287 help='Do a fast probe for EC and main firmware versions only. '
288 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800289 CmdArg('--no_vol', action='store_true',
290 help='Do not probe volatile data.'),
291 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800292 help='Do not probe initial_config data.'),
293 CmdArg('--include_vpd', action='store_true',
294 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800295def RunProbe(options):
296 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800297 print GetGooftool(options).Probe(
298 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800299 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800300 probe_volatile=not options.no_vol,
301 probe_initial_config=not options.no_ic,
302 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800303
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800304
Tammo Spalink214caf42012-05-28 10:45:00 +0800305@Command('verify_components',
306 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800307 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800308def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800309 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800310
Tammo Spalink5c699832012-07-03 17:50:39 +0800311 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800312 that a corresponding match exists in the component_db -- make sure
313 that these components are present, that they have been approved, but
314 do not check against any specific BOM/HWID configurations.
315 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800316
Andy Chengc531e2f2012-10-15 19:09:17 +0800317 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800318 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800319 options.target_comps)
320 except ValueError, e:
321 sys.exit(e)
322
Ricky Liang53390232013-03-08 15:37:57 +0800323 PrintVerifyComponentsResults(result)
324
325
326def PrintVerifyComponentsResults(result):
327 """Prints out the results of VerifyComponents method call.
328
329 Groups the results into two groups: 'matches' and 'errors', and prints out
330 their values.
331 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800332 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800333 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800334 errors = []
335 for result_list in result.values():
336 for component_name, _, error in result_list:
337 if component_name:
338 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800339 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800340 errors.append(error)
341
Andy Cheng228a8c92012-08-27 10:53:57 +0800342 if matches:
343 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800344 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800345 print '\nerrors:\n %s' % '\n '.join(errors)
346 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800347 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800348 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800349
350
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800351@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700352 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800353 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800354 _probe_results_cmd_arg,
355 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800356def VerifyHwid(options):
357 """Verify system HWID properties match probed device properties.
358
359 First probe components, volatile and initial_config parameters for
360 the DUT. Then use the available device data to produce a list of
361 candidate HWIDs. Then verify the HWID from the DUT is present in
362 that list. Then verify that the DUT initial config values match
363 those specified for its HWID. Finally, verify that VPD contains all
364 the necessary fields as specified by the board data, and when
365 possible verify that values are legitimate.
366 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800367
Ricky Liangf7857c12012-09-17 13:34:41 +0800368 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800369 for key in ro_vpd_keys:
370 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800371 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700372 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800373 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800374 if (known_valid_values is not None) and (value not in known_valid_values):
375 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800376 for key in rw_vpd_keys:
377 if key not in rw_vpd:
378 sys.exit('Missing required RW VPD field: %s' % key)
379 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
380 value = rw_vpd[key]
381 if (known_valid_values is not None) and (value not in known_valid_values):
382 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800383 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800384 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800385
Jon Salz81350812012-10-11 16:13:22 +0800386 if not options.hwid or not options.probe_results:
387 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800388
389 if options.hwid:
390 hwid_str = options.hwid
391 else:
392 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
393 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700394 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800395 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800396 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700397 device = hw_db.GetDevice(hwid.board)
398 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
399 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800400 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800401 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800402 if options.probe_results:
403 # Pull in probe results (including VPD data) from the given file
404 # rather than probing the current system.
405 probe_results = hwid_tool.ProbeResults.Decode(
406 open(options.probe_results).read())
407 ro_vpd = {}
408 rw_vpd = {}
409 for k, v in probe_results.found_volatile_values.items():
410 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
411 if match:
412 del probe_results.found_volatile_values[k]
413 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
414 else:
415 probe_results = Probe()
416 ro_vpd = ReadRoVpd(main_fw_file)
417 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700418 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
419 probe_results.found_probe_value_map)
420 cooked_volatiles = device.MatchVolatileValues(
421 probe_results.found_volatile_values)
422 cooked_initial_configs = device.MatchInitialConfigValues(
423 probe_results.initial_configs)
424 component_data = hwid_tool.ComponentData(
425 extant_components=cooked_components.matched,
426 classes_missing=probe_results.missing_component_classes)
427 match_tree = device.BuildMatchTree(
428 component_data, cooked_volatiles.matched_tags)
429 matched_hwids = device.GetMatchTreeHwids(match_tree)
430 print 'HWID status: %s\n' % hwid_status
431 print 'probed system components:'
432 print YamlWrite(cooked_components.__dict__)
433 print 'missing component classes:'
434 print YamlWrite(probe_results.missing_component_classes)
435 print 'probed volatiles:'
436 print YamlWrite(cooked_volatiles.__dict__)
437 print 'probed initial_configs:'
438 print YamlWrite(cooked_initial_configs)
439 print 'hwid match tree:'
440 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800441 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800442 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700443 found_components=cooked_components.__dict__,
444 missing_component_classes=probe_results.missing_component_classes,
445 volatiles=cooked_volatiles.__dict__,
446 initial_configs=cooked_initial_configs)
447 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800448 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700449 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800450 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700451 YamlWrite(cooked_components.unmatched))
452 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800453 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700454 component_data.Encode())
455 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800456 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700457 (', '.join(sorted(match_tree)), hwid.bom))
458 err_msg += 'target bom %r matches components' % hwid.bom
459 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
460 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800461 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700462 matched_variants = match_tree.get(hwid.bom, {})
463 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800464 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700465 hwid.variant)
466 matched_volatiles = matched_variants.get(hwid.variant, {})
467 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800468 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700469 hwid.volatile)
470 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800471 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800472 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800473 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700474 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800475
476
477@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700478def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800479 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800480
Ricky Lianga70a1202013-03-15 15:03:17 +0800481 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800482
483
484@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700485def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800486 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800487
Ricky Lianga70a1202013-03-15 15:03:17 +0800488 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800489 logging.info('Firmware bitmap initial locale set to %d (%s).',
490 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800491
492
493@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700494def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800495 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800496
Ricky Lianga70a1202013-03-15 15:03:17 +0800497 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800498
499
500@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700501def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800502 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800503
Ricky Lianga70a1202013-03-15 15:03:17 +0800504 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800505
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800506@Command('verify_tpm')
507def VerifyTPM(options): # pylint: disable=W0613
508 """Verify TPM is cleared."""
509
510 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800511
512@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800513def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800514 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800515
Ricky Lianga70a1202013-03-15 15:03:17 +0800516 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800517
518
519@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700520def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800521 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800522
Ricky Lianga70a1202013-03-15 15:03:17 +0800523 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800524 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800525 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800526
527
528@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700529def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800530 """Enable then verify firmware write protection."""
531
Hung-Te Linb21c6682012-08-01 13:53:57 +0800532 def CalculateLegacyRange(fw_type, length, section_data,
533 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800534 ro_size = length / 2
535 ro_a = int(section_data[0] / ro_size)
536 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
537 if ro_a != ro_b:
538 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800539 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800540 ro_offset = ro_a * ro_size
541 return (ro_offset, ro_size)
542
543 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800544 """Calculate protection size, then invoke flashrom.
545
546 Our supported chips only allow write protecting half their total
547 size, so we parition the flash chipset space accordingly.
548 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800549
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800550 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800551 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800552 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800553 if image.has_section(wp_section):
554 section_data = image.get_section_area(wp_section)
555 ro_offset = section_data[0]
556 ro_size = section_data[1]
557 elif image.has_section(legacy_section):
558 section_data = image.get_section_area(legacy_section)
559 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800560 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800561 else:
562 raise Error('could not find %s firmware section %s or %s' %
563 (fw_type, wp_section, legacy_section))
564
565 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
566 ro_offset, ro_size)
567 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800568
569 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800570 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800571 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
572 if ec_fw_file is not None:
573 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800574 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800575 else:
576 logging.warning('EC not write protected (seems there is no EC flash).')
577
578
579@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800580def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800581 """Zero out the GBB flags, in preparation for transition to release state.
582
583 No GBB flags are set in release/shipping state, but they are useful
584 for factory/development. See "gbb_utility --flags" for details.
585 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800586
Ricky Lianga70a1202013-03-15 15:03:17 +0800587 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800588 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800589
590
Jon Salzaa3a30e2013-05-15 15:56:28 +0800591@Command('clear_factory_vpd_entries')
592def ClearFactoryVPDEntries(options): # pylint: disable=W0613
593 """Clears factory.* items in the RW VPD."""
594 entries = GetGooftool(options).ClearFactoryVPDEntries()
595 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
596
597
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800598@Command('prepare_wipe',
599 CmdArg('--fast', action='store_true',
600 help='use non-secure but faster wipe method.'))
601def PrepareWipe(options):
602 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800603
Ricky Lianga70a1202013-03-15 15:03:17 +0800604 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800605
606@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800607 CmdArg('--no_write_protect', action='store_true',
608 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700609 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800610 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800611 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800612 _probe_results_cmd_arg,
613 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800614def Verify(options):
615 """Verifies if whole factory process is ready for finalization.
616
617 This routine performs all the necessary checks to make sure the
618 device is ready to be finalized, but does not modify state. These
619 checks include dev switch, firmware write protection switch, hwid,
620 system time, keys, and root file system.
621 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800622
Hung-Te Lin6d827542012-07-19 11:50:41 +0800623 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800624 VerifyWPSwitch(options)
625 VerifyDevSwitch(options)
626 if options.hwid_version == 2:
627 VerifyHwid(options)
628 elif options.hwid_version == 3:
629 VerifyHwidV3(options)
630 else:
631 raise Error, 'Invalid HWID version: %r' % options.hwid_version
632 VerifySystemTime(options)
633 VerifyKeys(options)
634 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800635 VerifyTPM(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800636
637
Tammo Spalink86a61c62012-05-25 15:10:35 +0800638@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700639def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800640 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800641
Andy Cheng0465d132013-03-20 12:12:06 +0800642 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800643 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800644
645
Jon Salza88b83b2013-05-27 20:00:35 +0800646def CreateReportArchiveBlob(*args, **kwargs):
647 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800648
Jon Salza88b83b2013-05-27 20:00:35 +0800649 Args:
650 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800651
Jon Salza88b83b2013-05-27 20:00:35 +0800652 Returns:
653 An xmlrpclib.Binary object containing a .tar.xz file.
654 """
655 with open(CreateReportArchive(*args, **kwargs)) as f:
656 return xmlrpclib.Binary(f.read())
657
658
659def CreateReportArchive(device_sn=None, add_file=None):
660 """Creates a report archive in a temporary directory.
661
662 Args:
663 device_sn: The device serial number (optional).
664 add_file: A list of files to add (optional).
665
666 Returns:
667 Path to the archive.
668 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800669 def NormalizeAsFileName(token):
670 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800671
672 target_name = '%s%s.tar.xz' % (
673 time.strftime('%Y%m%dT%H%M%SZ',
674 time.gmtime()),
675 ("" if device_sn is None else
676 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800677 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800678
Tammo Spalink86a61c62012-05-25 15:10:35 +0800679 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800680 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800681 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800682 if add_file:
683 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800684 # Require absolute paths since the tar command may change the
685 # directory.
686 if not f.startswith('/'):
687 raise Error('Not an absolute path: %s' % f)
688 if not os.path.exists(f):
689 raise Error('File does not exist: %s' % f)
690 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800691 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800692
693 if ((cmd_result.status == 1) and
694 all((x == '' or
695 'file changed as we read it' in x or
696 "Removing leading `/' from member names" in x)
697 for x in cmd_result.stderr.split('\n'))):
698 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800699 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800700 ignore_stdout=True)
701 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800702 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
703 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800704
Jon Salza88b83b2013-05-27 20:00:35 +0800705 return target_path
706
707_upload_method_cmd_arg = CmdArg(
708 '--upload_method', metavar='METHOD:PARAM',
709 help=('How to perform the upload. METHOD should be one of '
710 '{ftp, shopfloor, ftps, cpfe}.'))
711_add_file_cmd_arg = CmdArg(
712 '--add_file', metavar='FILE', action='append',
713 help='Extra file to include in report (must be an absolute path)')
714
715@Command('upload_report',
716 _upload_method_cmd_arg,
717 _add_file_cmd_arg)
718def UploadReport(options):
719 """Create a report containing key device details."""
720 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
721 device_sn = ro_vpd.get('serial_number', None)
722 if device_sn is None:
723 logging.warning('RO_VPD missing device serial number')
724 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
725 target_path = CreateReportArchive(device_sn)
726
Tammo Spalink86a61c62012-05-25 15:10:35 +0800727 if options.upload_method is None or options.upload_method == 'none':
728 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
729 return
730 method, param = options.upload_method.split(':', 1)
731 if method == 'shopfloor':
732 report_upload.ShopFloorUpload(target_path, param)
733 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700734 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800735 elif method == 'ftps':
736 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
737 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800738 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800739 else:
740 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800741
742
743@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800744 CmdArg('--no_write_protect', action='store_true',
745 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800746 CmdArg('--fast', action='store_true',
747 help='use non-secure but faster wipe method.'),
748 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700749 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800750 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800751 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800752 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800753 _probe_results_cmd_arg,
754 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800755def Finalize(options):
756 """Verify system readiness and trigger transition into release state.
757
Jon Salzaa3a30e2013-05-15 15:56:28 +0800758 This routine does the following:
759 - Verifies system state (see verify command)
760 - Modifies firmware bitmaps to match locale
761 - Clears all factory-friendly flags from the GBB
762 - Removes factory-specific entries from RW_VPD (factory.*)
763 - Enables firmware write protection (cannot rollback after this)
764 - Uploads system logs & reports
765 - Sets the necessary boot flags to cause wipe of the factory image on the
766 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800767 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800768 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800769 SetFirmwareBitmapLocale(options)
770 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800771 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800772 if options.no_write_protect:
773 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800774 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800775 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800776 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800777 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800778 UploadReport(options)
779 PrepareWipe(options)
780
781
Ricky Liang53390232013-03-08 15:37:57 +0800782@Command('verify_components_v3',
783 _board_cmd_arg,
784 _hwdb_path_cmd_arg,
785 CmdArg('target_comps', nargs='*'))
786def VerifyComponentsV3(options):
787 """Verify that probeable components all match entries in the component_db.
788
789 This method uses the HWIDv3 component database to verify components.
790
791 Probe for each component class in the target_comps and verify
792 that a corresponding match exists in the component_db -- make sure
793 that these components are present, that they have been approved, but
794 do not check against any specific BOM/HWID configurations.
795 """
796
Ricky Lianga70a1202013-03-15 15:03:17 +0800797 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800798 PrintVerifyComponentsResults(result)
799
800
801@Command('generate_hwid_v3',
802 _board_cmd_arg,
803 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800804 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800805 _device_info_cmd_arg)
806def GenerateHwidV3(options):
807 """Generates the HWID of the DUT.
808
809 The HWID is generated based on the given device info and the probe results
810 retrieved by probing the DUT. If there are conflits of component information
811 between device info and probe result, priority is given to device info.
812 """
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800813 if options.device_info:
Ricky Liang7905f272013-03-16 01:57:10 +0800814 with open(options.device_info) as f:
815 device_info = yaml.load(f.read())
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800816 else:
817 device_info = shopfloor.GetDeviceData()
Ricky Liang7905f272013-03-16 01:57:10 +0800818 if options.probe_results:
819 with open(options.probe_results) as f:
820 probe_results = hwid_tool.ProbeResults.Decode(f.read())
821 else:
822 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800823 print 'device_info:'
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800824 print yaml.dump(device_info)
Ricky Liang5b4568d2013-04-23 17:15:23 +0800825 print 'probe results:'
Ricky Liang53390232013-03-08 15:37:57 +0800826 print probe_results.Encode()
827
828 # Do not log device_info for now until we're sure that it does not contain
829 # any sensitive infomation.
830 # TODO(jcliang): Add logging for device_info when appropriate.
831
Andy Cheng0465d132013-03-20 12:12:06 +0800832 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800833 'probe',
834 found_components=probe_results.found_probe_value_map,
835 missing_component_classes=probe_results.missing_component_classes,
836 volatiles=probe_results.found_volatile_values,
837 initial_configs=probe_results.initial_configs)
838
Ricky Lianga70a1202013-03-15 15:03:17 +0800839 hwid_object = GetGooftool(options).GenerateHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800840 device_info, probe_results)
Ricky Liang53390232013-03-08 15:37:57 +0800841
842 final_bom = {}
843 for component_class, component_values in (
844 hwid_object.bom.components.iteritems()):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800845 final_bom[component_class] = [v.probed_values for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800846 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800847 'final_bom',
848 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800849 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800850 'generated_hwid',
851 encoded_string=hwid_object.encoded_string,
852 binary_string=hwid_object.binary_string)
853 print 'Encoded HWID string:', hwid_object.encoded_string
854 print 'Binary HWID string:', hwid_object.binary_string
855
856
857@Command('verify_hwid_v3',
858 _board_cmd_arg,
859 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800860 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800861 _hwid_cmd_arg)
862def VerifyHwidV3(options):
863 """Verify system HWID properties match probed device properties.
864
865 First probe components, volatile and initial_config parameters for
866 the DUT. Then use the available device data to produce a list of
867 candidate HWIDs. Then verify the HWID from the DUT is present in
868 that list. Then verify that the DUT initial config values match
869 those specified for its HWID. Finally, verify that VPD contains all
870 the necessary fields as specified by the board data, and when
871 possible verify that values are legitimate.
872 """
Ricky Liang7905f272013-03-16 01:57:10 +0800873 if not options.probe_results:
874 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800875 if options.hwid:
876 hwid_str = options.hwid
877 else:
878 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
879 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
880 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800881 if options.probe_results:
882 # Pull in probe results (including VPD data) from the given file
883 # rather than probing the current system.
884 with open(options.probe_results) as f:
885 probe_results = hwid_tool.ProbeResults.Decode(f.read())
886 probed_ro_vpd = {}
887 probed_rw_vpd = {}
888 for k, v in probe_results.found_volatile_values.items():
889 # Use items(), not iteritems(), since we will be modifying the dict in the
890 # loop.
891 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
892 if match:
893 del probe_results.found_volatile_values[k]
894 (probed_ro_vpd if match.group(1) == 'ro'
895 else probed_rw_vpd)[match.group(2)] = v
896 else:
897 probe_results = Probe()
898 probed_ro_vpd = ReadRoVpd(main_fw_file)
899 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800900 print 'probe result:'
901 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800902 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800903 'probe',
904 found_components=probe_results.found_probe_value_map,
905 missing_component_classes=probe_results.missing_component_classes,
906 volatiles=probe_results.found_volatile_values,
907 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800908 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800909 probed_rw_vpd=FilterDict(probed_rw_vpd))
910
Ricky Liangeede7922013-06-19 10:18:41 +0800911 if not options.board:
912 options.board = common.ProbeBoard(hwid_str)
Ricky Lianga70a1202013-03-15 15:03:17 +0800913 GetGooftool(options).VerifyHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800914 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800915
Andy Cheng0465d132013-03-20 12:12:06 +0800916 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800917 print 'Verification SUCCESS!'
918
919
Ricky Liang59611a62013-06-11 13:47:33 +0800920def ParseDecodedHWID(hwid):
921 """Parse the HWID object into a more compact dict.
922
923 Args:
924 hwid: A decoded HWID object.
925
926 Returns:
927 A dict containing the board name, the binary string, and the list of
928 components.
929 """
930 results = {}
931 results['board'] = hwid.database.board
932 results['binary_string'] = hwid.binary_string
933 results['components'] = collections.defaultdict(list)
934 components = hwid.bom.components
935 for comp_cls in sorted(components):
936 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
937 if not probed_values:
938 db_components = hwid.database.components
939 probed_values = db_components.GetComponentAttributes(
940 comp_cls, comp_name).get('values')
941 results['components'][comp_cls].append(
942 {comp_name: probed_values if probed_values else None})
943 # Convert defaultdict to dict.
944 results['components'] = dict(results['components'])
945 return results
946
947
Ricky Liang7905f272013-03-16 01:57:10 +0800948@Command('decode_hwid_v3',
949 _board_cmd_arg,
950 _hwdb_path_cmd_arg,
951 _hwid_cmd_arg)
952def DecodeHwidV3(options):
953 """Decodes the given v3 HWID and prints out decoded information.
954
955 If no HWID is given, the HWID stored on the device will be loaded and used
956 instead.
957 """
Ricky Liangeede7922013-06-19 10:18:41 +0800958 if not options.board:
959 options.board = common.ProbeBoard(options.hwid)
Ricky Liang7905f272013-03-16 01:57:10 +0800960 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
961 hwdb_path=options.hwdb_path).DecodeHwidV3(
962 options.hwid)
Ricky Liang59611a62013-06-11 13:47:33 +0800963 print yaml.dump(ParseDecodedHWID(decoded_hwid_context),
964 default_flow_style=False)
Ricky Liang7905f272013-03-16 01:57:10 +0800965
966
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800967def Main():
968 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800969
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800970 options = ParseCmdline(
971 'Perform Google required factory tests.',
972 CmdArg('-l', '--log', metavar='PATH',
973 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800974 CmdArg('--suppress-event-logs', action='store_true',
975 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800976 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800977 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800978 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800979 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800980 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
981 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800982 logging.debug('gooftool options: %s', repr(options))
983 try:
984 logging.debug('GOOFTOOL command %r', options.command_name)
985 options.command(options)
986 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
987 except Error, e:
988 logging.exception(e)
989 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
990 except Exception, e:
991 logging.exception(e)
992 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
993
994
995if __name__ == '__main__':
996 Main()