blob: 38ca60108912b2d547409a278089cc0c4e91541a [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Tammo Spalink01e11722012-07-24 10:17:54 -07002# pylint: disable=E1101
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08003#
4# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Google Factory Tool.
9
10This tool is indended to be used on factory assembly lines. It
11provides all of the Google required test functionality and must be run
12on each device as part of the assembly process.
13"""
14
Ricky Liang5b4568d2013-04-23 17:15:23 +080015import collections
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080016import logging
17import os
Jon Salz65266432012-07-30 19:02:49 +080018import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080019import re
20import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080021import time
Jon Salza88b83b2013-05-27 20:00:35 +080022import xmlrpclib
Ricky Liang7905f272013-03-16 01:57:10 +080023import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080024
Andy Cheng2582d292012-12-04 17:38:28 +080025from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080026
Tammo Spalinka40293e2012-07-04 14:58:56 +080027import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080028
Andy Cheng0465d132013-03-20 12:12:06 +080029from cros.factory import event_log
Jon Salz0f8a6842012-09-25 11:28:22 +080030from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070031from cros.factory.common import YamlWrite
Andy Chengc531e2f2012-10-15 19:09:17 +080032from cros.factory.gooftool import Gooftool
Ricky Liang53390232013-03-08 15:37:57 +080033from cros.factory.gooftool import crosfw
Tammo Spalink01e11722012-07-24 10:17:54 -070034from cros.factory.gooftool import report_upload
Andy Cheng8ece7382012-08-22 16:25:42 +080035from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080036from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
henryhsu44d793a2013-07-20 00:07:38 +080037from cros.factory.gooftool.probe import CalculateFirmwareHashes
Jon Salz193d7c62013-03-07 13:40:19 +080038from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080039from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
40from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070041from cros.factory.hwdb import hwid_tool
Ricky Liangeede7922013-06-19 10:18:41 +080042from cros.factory.hwid import common
Ricky Liangf1ded8a2013-06-25 11:29:01 +080043from cros.factory.test import shopfloor
cychiang7fe09372012-07-04 14:31:23 +080044from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080045from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080046from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080047
Tammo Spalink5c699832012-07-03 17:50:39 +080048
Tammo Spalink5c699832012-07-03 17:50:39 +080049# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
50# treat that specially (as a smoot exit, as opposed to the more
51# verbose output for generic Error).
52
53
Ricky Lianga70a1202013-03-15 15:03:17 +080054def GetGooftool(options):
55 if options.hwid_version == 2:
56 hwdb_path = getattr(options, 'hwdb_path', None)
57 component_db = (
58 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
59 return Gooftool(hwid_version=2, component_db=component_db)
60 elif options.hwid_version == 3:
61 board = getattr(options, 'board', None)
62 hwdb_path = getattr(options, 'hwdb_path', None)
63 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
64 else:
65 raise Error, 'Invalid HWID version: %r' % options.hwid_version
66
67
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080068@Command('write_hwid',
69 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080070def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080071 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080072
Tammo Spalink95c43732012-07-25 15:57:14 -070073 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080074 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080075 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070076 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080077
78
Ricky Liang53390232013-03-08 15:37:57 +080079_board_cmd_arg = CmdArg(
80 '--board', metavar='BOARD',
81 default=None, help='Board name to test.')
82
Tammo Spalink8fab5312012-05-28 18:33:30 +080083_hwdb_path_cmd_arg = CmdArg(
84 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +080085 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +080086 help='Path to the HWID database.')
87
Tammo Spalink95c43732012-07-25 15:57:14 -070088_hwid_status_list_cmd_arg = CmdArg(
89 '--status', nargs='*', default=['supported'],
90 help='allow only HWIDs with these status values')
91
Jon Salzce124fb2012-10-02 17:42:03 +080092_probe_results_cmd_arg = CmdArg(
93 '--probe_results', metavar='RESULTS.yaml',
94 help=('Output from "gooftool probe" (used instead of '
95 'probing this system).'))
96
Ricky Liang53390232013-03-08 15:37:57 +080097_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080098 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +080099 help='A dict of device info to use instead of fetching from shopfllor '
100 'server.')
101
Jon Salzce124fb2012-10-02 17:42:03 +0800102_hwid_cmd_arg = CmdArg(
103 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800104 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800105
Tammo Spalink95c43732012-07-25 15:57:14 -0700106
107@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800108 _hwdb_path_cmd_arg,
109 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700110 help='optional BOARD name, needed only if data is present '
111 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800112 CmdArg('--bom', metavar='BOM', help='BOM name'),
113 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800114 CmdArg('--optimistic', action='store_true',
115 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700116 CmdArg('--comps', nargs='*', default=[],
117 help='list of canonical component names'),
118 CmdArg('--missing', nargs='*', default=[],
119 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800120 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700121 help='consider only HWIDs within this list of status values'))
122def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800123 """Determine a list of possible HWIDs using provided args and probeing.
124
125 VOLATILE can always be determined by probing. To get a unique
126 result, VARIANT must be specified for all cases where the matching
127 BOM has more than one associated variant code, otherwise all HWID
128 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700129 alternatively be specified using the --stdin_comps argument, which
130 allows specifying a list of canonical names (one per line) on stdin,
131 one per line. Based on what is known from BOM and stdin_comps,
132 determine a list of components to probe for, and use those probe
133 results to resolve a list of matching HWIDs. If no boms,
134 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800135 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800136
137 Returns (on stdout): A list of HWIDs that match the available probe
138 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700139
140 Example:
141
142 // Three ways to specify a keyboard (assuming it is a variant component)
143 gooftool best_match_hwids --missing keyboard
144 gooftool best_match_hwids --variant A or
145 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800146 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800147
Tammo Spalink5c699832012-07-03 17:50:39 +0800148 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700149 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800150 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800151 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800152 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800153 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800154 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700155 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800156 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800157 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800158 device.VariantExists(options.variant)
159 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700160 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700161 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700162 % YamlWrite(sorted(
163 hwid_tool.ComponentSpecClasses(component_spec) &
164 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700165 component_spec = hwid_tool.CombineComponentSpecs(
166 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700167 if options.comps or options.missing:
168 map(comp_db.CompExists, options.comps)
169 map(comp_db.CompClassExists, options.missing)
170 extra_comp_spec = comp_db.CreateComponentSpec(
171 components=options.comps,
172 missing=options.missing)
173 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
174 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
175 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700176 % YamlWrite(sorted(
177 hwid_tool.ComponentSpecClasses(component_spec) &
178 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700179 component_spec = hwid_tool.CombineComponentSpecs(
180 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700181 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700182 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800183 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800184 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
185 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700186 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700187 'as inputs, and cannot be probed for:\n%s'
188 'This problem can often be addressed by specifying all of '
189 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800190 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700191 print 'probing for missing classes:'
192 print YamlWrite(list(missing_classes))
193 probe_results = Probe(target_comp_classes=list(missing_classes),
194 probe_volatile=False, probe_initial_config=False)
195 cooked_components = comp_db.MatchComponentProbeValues(
196 probe_results.found_probe_value_map)
197 if cooked_components.unmatched:
198 sys.exit('ERROR: some probed components are unrecognized:\n%s'
199 % YamlWrite(cooked_components.unmatched))
200 probed_comp_spec = comp_db.CreateComponentSpec(
201 components=cooked_components.matched,
202 missing=probe_results.missing_component_classes)
203 component_spec = hwid_tool.CombineComponentSpecs(
204 component_spec, probed_comp_spec)
205 print YamlWrite({'component data used for matching': {
206 'missing component classes': component_spec.classes_missing,
207 'found components': component_spec.components}})
208 component_data = hwid_tool.ComponentData(
209 extant_components=hwid_tool.ComponentSpecCompClassMap(
210 component_spec).keys(),
211 classes_missing=component_spec.classes_missing)
212 match_tree = device.BuildMatchTree(component_data)
213 if not match_tree:
214 sys.exit('FAILURE: NO matching BOMs found')
215 print 'potential BOMs/VARIANTs:'
216 potential_variants = set()
217 potential_volatiles = set()
218 for bom_name, variant_tree in match_tree.items():
219 print ' BOM: %-8s VARIANTS: %s' % (
220 bom_name, ', '.join(sorted(variant_tree)))
221 for variant_code in variant_tree:
222 potential_variants.add(variant_code)
223 for volatile_code in device.volatiles:
224 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
225 if status in options.status:
226 potential_volatiles.add(volatile_code)
227 print ''
228 if len(potential_variants) == 0:
229 sys.exit('FAILURE: no matching VARIANTs found')
230 if len(potential_volatiles) == 0:
231 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
232 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700233 if (options.optimistic and
234 len(match_tree) == 1 and
235 len(potential_variants) == 1 and
236 len(potential_volatiles) == 1):
237 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
238 potential_variants.pop(),
239 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800240 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700241 print ('probing VOLATILEs to resolve potential matches: %s\n' %
242 ', '.join(sorted(potential_volatiles)))
243 vol_probe_results = Probe(
244 target_comp_classes=[],
245 probe_volatile=True,
246 probe_initial_config=False)
247 cooked_volatiles = device.MatchVolatileValues(
248 vol_probe_results.found_volatile_values)
249 match_tree = device.BuildMatchTree(
250 component_data, cooked_volatiles.matched_tags)
251 matched_hwids = device.GetMatchTreeHwids(match_tree)
252 if matched_hwids:
253 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800254 if matched_hwids[hwid] in options.status:
255 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700256 return
257 print 'exact HWID matching failed, but the following BOMs match: %s' % (
258 ', '.join(sorted(match_tree)))
259 if options.optimistic and len(match_tree) == 1:
260 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800261 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700262 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800263 if len(variant_matches) == 1:
264 var_code = set(variant_matches).pop()
265 elif len(bom.variants) == 1:
266 var_code = set(bom.variants).pop()
267 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700268 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
269 'because there were too many variants to choose from for BOM %r'
270 % bom_name)
271 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
272 for vol_code in device.volatiles
273 if device.GetHwidStatus(bom_name, var_code, vol_code)
274 in options.status]
275 for hwid in hwids:
276 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800277 return
278 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700279 print ('optimistic matching not attempted because either it was '
280 'not requested, or because the number of BOMs was <> 1\n')
281 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800282
283
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800284@Command('probe',
285 CmdArg('--comps', nargs='*',
286 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800287 CmdArg('--fast_fw_probe', action='store_true',
288 help='Do a fast probe for EC and main firmware versions only. '
289 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800290 CmdArg('--no_vol', action='store_true',
291 help='Do not probe volatile data.'),
292 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800293 help='Do not probe initial_config data.'),
294 CmdArg('--include_vpd', action='store_true',
295 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800296def RunProbe(options):
297 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800298 print GetGooftool(options).Probe(
299 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800300 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800301 probe_volatile=not options.no_vol,
302 probe_initial_config=not options.no_ic,
303 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800304
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800305
Tammo Spalink214caf42012-05-28 10:45:00 +0800306@Command('verify_components',
307 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800308 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800309def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800310 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800311
Tammo Spalink5c699832012-07-03 17:50:39 +0800312 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800313 that a corresponding match exists in the component_db -- make sure
314 that these components are present, that they have been approved, but
315 do not check against any specific BOM/HWID configurations.
316 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800317
Andy Chengc531e2f2012-10-15 19:09:17 +0800318 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800319 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800320 options.target_comps)
321 except ValueError, e:
322 sys.exit(e)
323
Ricky Liang53390232013-03-08 15:37:57 +0800324 PrintVerifyComponentsResults(result)
325
326
327def PrintVerifyComponentsResults(result):
328 """Prints out the results of VerifyComponents method call.
329
330 Groups the results into two groups: 'matches' and 'errors', and prints out
331 their values.
332 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800333 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800334 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800335 errors = []
336 for result_list in result.values():
337 for component_name, _, error in result_list:
338 if component_name:
339 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800340 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800341 errors.append(error)
342
Andy Cheng228a8c92012-08-27 10:53:57 +0800343 if matches:
344 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800345 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800346 print '\nerrors:\n %s' % '\n '.join(errors)
347 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800348 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800349 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800350
351
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800352@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700353 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800354 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800355 _probe_results_cmd_arg,
356 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800357def VerifyHwid(options):
358 """Verify system HWID properties match probed device properties.
359
360 First probe components, volatile and initial_config parameters for
361 the DUT. Then use the available device data to produce a list of
362 candidate HWIDs. Then verify the HWID from the DUT is present in
363 that list. Then verify that the DUT initial config values match
364 those specified for its HWID. Finally, verify that VPD contains all
365 the necessary fields as specified by the board data, and when
366 possible verify that values are legitimate.
367 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800368
Ricky Liangf7857c12012-09-17 13:34:41 +0800369 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800370 for key in ro_vpd_keys:
371 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800372 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700373 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800374 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800375 if (known_valid_values is not None) and (value not in known_valid_values):
376 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800377 for key in rw_vpd_keys:
378 if key not in rw_vpd:
379 sys.exit('Missing required RW VPD field: %s' % key)
380 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
381 value = rw_vpd[key]
382 if (known_valid_values is not None) and (value not in known_valid_values):
383 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800384 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800385 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800386
Jon Salz81350812012-10-11 16:13:22 +0800387 if not options.hwid or not options.probe_results:
388 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800389
390 if options.hwid:
391 hwid_str = options.hwid
392 else:
393 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
394 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700395 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800396 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800397 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700398 device = hw_db.GetDevice(hwid.board)
399 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
400 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800401 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800402 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800403 if options.probe_results:
404 # Pull in probe results (including VPD data) from the given file
405 # rather than probing the current system.
406 probe_results = hwid_tool.ProbeResults.Decode(
407 open(options.probe_results).read())
408 ro_vpd = {}
409 rw_vpd = {}
410 for k, v in probe_results.found_volatile_values.items():
411 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
412 if match:
413 del probe_results.found_volatile_values[k]
414 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
415 else:
416 probe_results = Probe()
417 ro_vpd = ReadRoVpd(main_fw_file)
418 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700419 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
420 probe_results.found_probe_value_map)
421 cooked_volatiles = device.MatchVolatileValues(
422 probe_results.found_volatile_values)
423 cooked_initial_configs = device.MatchInitialConfigValues(
424 probe_results.initial_configs)
425 component_data = hwid_tool.ComponentData(
426 extant_components=cooked_components.matched,
427 classes_missing=probe_results.missing_component_classes)
428 match_tree = device.BuildMatchTree(
429 component_data, cooked_volatiles.matched_tags)
430 matched_hwids = device.GetMatchTreeHwids(match_tree)
431 print 'HWID status: %s\n' % hwid_status
432 print 'probed system components:'
433 print YamlWrite(cooked_components.__dict__)
434 print 'missing component classes:'
435 print YamlWrite(probe_results.missing_component_classes)
436 print 'probed volatiles:'
437 print YamlWrite(cooked_volatiles.__dict__)
438 print 'probed initial_configs:'
439 print YamlWrite(cooked_initial_configs)
440 print 'hwid match tree:'
441 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800442 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800443 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700444 found_components=cooked_components.__dict__,
445 missing_component_classes=probe_results.missing_component_classes,
446 volatiles=cooked_volatiles.__dict__,
447 initial_configs=cooked_initial_configs)
448 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800449 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700450 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800451 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700452 YamlWrite(cooked_components.unmatched))
453 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800454 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700455 component_data.Encode())
456 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800457 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700458 (', '.join(sorted(match_tree)), hwid.bom))
459 err_msg += 'target bom %r matches components' % hwid.bom
460 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
461 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800462 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700463 matched_variants = match_tree.get(hwid.bom, {})
464 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800465 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700466 hwid.variant)
467 matched_volatiles = matched_variants.get(hwid.variant, {})
468 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800469 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700470 hwid.volatile)
471 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800472 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800473 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800474 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700475 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800476
477
478@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700479def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800480 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800481
Ricky Lianga70a1202013-03-15 15:03:17 +0800482 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800483
484
485@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700486def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800487 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800488
Ricky Lianga70a1202013-03-15 15:03:17 +0800489 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800490 logging.info('Firmware bitmap initial locale set to %d (%s).',
491 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800492
493
494@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700495def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800497
Ricky Lianga70a1202013-03-15 15:03:17 +0800498 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800499
500
501@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700502def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800504
Ricky Lianga70a1202013-03-15 15:03:17 +0800505 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800506
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800507@Command('verify_tpm')
508def VerifyTPM(options): # pylint: disable=W0613
509 """Verify TPM is cleared."""
510
511 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800512
513@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800514def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800515 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800516
Ricky Lianga70a1202013-03-15 15:03:17 +0800517 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800518
519
520@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700521def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800522 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800523
Ricky Lianga70a1202013-03-15 15:03:17 +0800524 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800525 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800526 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800527
528
529@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700530def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800531 """Enable then verify firmware write protection."""
532
Hung-Te Linb21c6682012-08-01 13:53:57 +0800533 def CalculateLegacyRange(fw_type, length, section_data,
534 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800535 ro_size = length / 2
536 ro_a = int(section_data[0] / ro_size)
537 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
538 if ro_a != ro_b:
539 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800540 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800541 ro_offset = ro_a * ro_size
542 return (ro_offset, ro_size)
543
544 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800545 """Calculate protection size, then invoke flashrom.
546
547 Our supported chips only allow write protecting half their total
548 size, so we parition the flash chipset space accordingly.
549 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800550
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800551 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800552 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800553 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800554 if image.has_section(wp_section):
555 section_data = image.get_section_area(wp_section)
556 ro_offset = section_data[0]
557 ro_size = section_data[1]
558 elif image.has_section(legacy_section):
559 section_data = image.get_section_area(legacy_section)
560 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800561 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800562 else:
563 raise Error('could not find %s firmware section %s or %s' %
564 (fw_type, wp_section, legacy_section))
565
566 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
567 ro_offset, ro_size)
568 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800569
570 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800571 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800572 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
573 if ec_fw_file is not None:
574 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800575 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800576 else:
577 logging.warning('EC not write protected (seems there is no EC flash).')
578
579
580@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800581def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800582 """Zero out the GBB flags, in preparation for transition to release state.
583
584 No GBB flags are set in release/shipping state, but they are useful
585 for factory/development. See "gbb_utility --flags" for details.
586 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800587
Ricky Lianga70a1202013-03-15 15:03:17 +0800588 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800589 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800590
591
Jon Salzaa3a30e2013-05-15 15:56:28 +0800592@Command('clear_factory_vpd_entries')
593def ClearFactoryVPDEntries(options): # pylint: disable=W0613
594 """Clears factory.* items in the RW VPD."""
595 entries = GetGooftool(options).ClearFactoryVPDEntries()
596 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
597
598
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800599@Command('prepare_wipe',
600 CmdArg('--fast', action='store_true',
601 help='use non-secure but faster wipe method.'))
602def PrepareWipe(options):
603 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800604
Ricky Lianga70a1202013-03-15 15:03:17 +0800605 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800606
607@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800608 CmdArg('--no_write_protect', action='store_true',
609 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700610 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800611 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800612 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800613 _probe_results_cmd_arg,
614 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800615def Verify(options):
616 """Verifies if whole factory process is ready for finalization.
617
618 This routine performs all the necessary checks to make sure the
619 device is ready to be finalized, but does not modify state. These
620 checks include dev switch, firmware write protection switch, hwid,
621 system time, keys, and root file system.
622 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800623
Hung-Te Lin6d827542012-07-19 11:50:41 +0800624 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800625 VerifyWPSwitch(options)
626 VerifyDevSwitch(options)
627 if options.hwid_version == 2:
628 VerifyHwid(options)
629 elif options.hwid_version == 3:
630 VerifyHwidV3(options)
631 else:
632 raise Error, 'Invalid HWID version: %r' % options.hwid_version
633 VerifySystemTime(options)
634 VerifyKeys(options)
635 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800636 VerifyTPM(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800637
638
Tammo Spalink86a61c62012-05-25 15:10:35 +0800639@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700640def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800641 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800642
Andy Cheng0465d132013-03-20 12:12:06 +0800643 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800644 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800645
646
Jon Salza88b83b2013-05-27 20:00:35 +0800647def CreateReportArchiveBlob(*args, **kwargs):
648 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800649
Jon Salza88b83b2013-05-27 20:00:35 +0800650 Args:
651 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800652
Jon Salza88b83b2013-05-27 20:00:35 +0800653 Returns:
654 An xmlrpclib.Binary object containing a .tar.xz file.
655 """
656 with open(CreateReportArchive(*args, **kwargs)) as f:
657 return xmlrpclib.Binary(f.read())
658
659
660def CreateReportArchive(device_sn=None, add_file=None):
661 """Creates a report archive in a temporary directory.
662
663 Args:
664 device_sn: The device serial number (optional).
665 add_file: A list of files to add (optional).
666
667 Returns:
668 Path to the archive.
669 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800670 def NormalizeAsFileName(token):
671 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800672
673 target_name = '%s%s.tar.xz' % (
674 time.strftime('%Y%m%dT%H%M%SZ',
675 time.gmtime()),
676 ("" if device_sn is None else
677 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800678 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800679
Tammo Spalink86a61c62012-05-25 15:10:35 +0800680 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800681 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800682 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800683 if add_file:
684 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800685 # Require absolute paths since the tar command may change the
686 # directory.
687 if not f.startswith('/'):
688 raise Error('Not an absolute path: %s' % f)
689 if not os.path.exists(f):
690 raise Error('File does not exist: %s' % f)
691 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800692 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800693
694 if ((cmd_result.status == 1) and
695 all((x == '' or
696 'file changed as we read it' in x or
697 "Removing leading `/' from member names" in x)
698 for x in cmd_result.stderr.split('\n'))):
699 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800700 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800701 ignore_stdout=True)
702 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800703 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
704 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800705
Jon Salza88b83b2013-05-27 20:00:35 +0800706 return target_path
707
708_upload_method_cmd_arg = CmdArg(
709 '--upload_method', metavar='METHOD:PARAM',
710 help=('How to perform the upload. METHOD should be one of '
711 '{ftp, shopfloor, ftps, cpfe}.'))
712_add_file_cmd_arg = CmdArg(
713 '--add_file', metavar='FILE', action='append',
714 help='Extra file to include in report (must be an absolute path)')
715
716@Command('upload_report',
717 _upload_method_cmd_arg,
718 _add_file_cmd_arg)
719def UploadReport(options):
720 """Create a report containing key device details."""
721 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
722 device_sn = ro_vpd.get('serial_number', None)
723 if device_sn is None:
724 logging.warning('RO_VPD missing device serial number')
725 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
726 target_path = CreateReportArchive(device_sn)
727
Tammo Spalink86a61c62012-05-25 15:10:35 +0800728 if options.upload_method is None or options.upload_method == 'none':
729 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
730 return
731 method, param = options.upload_method.split(':', 1)
732 if method == 'shopfloor':
733 report_upload.ShopFloorUpload(target_path, param)
734 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700735 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800736 elif method == 'ftps':
737 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
738 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800739 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800740 else:
741 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800742
743
744@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800745 CmdArg('--no_write_protect', action='store_true',
746 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800747 CmdArg('--fast', action='store_true',
748 help='use non-secure but faster wipe method.'),
749 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700750 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800751 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800752 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800753 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800754 _probe_results_cmd_arg,
755 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800756def Finalize(options):
757 """Verify system readiness and trigger transition into release state.
758
Jon Salzaa3a30e2013-05-15 15:56:28 +0800759 This routine does the following:
760 - Verifies system state (see verify command)
761 - Modifies firmware bitmaps to match locale
762 - Clears all factory-friendly flags from the GBB
763 - Removes factory-specific entries from RW_VPD (factory.*)
764 - Enables firmware write protection (cannot rollback after this)
765 - Uploads system logs & reports
766 - Sets the necessary boot flags to cause wipe of the factory image on the
767 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800768 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800769 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800770 SetFirmwareBitmapLocale(options)
771 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800772 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800773 if options.no_write_protect:
774 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800775 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800776 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800777 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800778 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800779 UploadReport(options)
780 PrepareWipe(options)
781
782
Ricky Liang53390232013-03-08 15:37:57 +0800783@Command('verify_components_v3',
784 _board_cmd_arg,
785 _hwdb_path_cmd_arg,
786 CmdArg('target_comps', nargs='*'))
787def VerifyComponentsV3(options):
788 """Verify that probeable components all match entries in the component_db.
789
790 This method uses the HWIDv3 component database to verify components.
791
792 Probe for each component class in the target_comps and verify
793 that a corresponding match exists in the component_db -- make sure
794 that these components are present, that they have been approved, but
795 do not check against any specific BOM/HWID configurations.
796 """
797
Ricky Lianga70a1202013-03-15 15:03:17 +0800798 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800799 PrintVerifyComponentsResults(result)
800
801
802@Command('generate_hwid_v3',
803 _board_cmd_arg,
804 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800805 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800806 _device_info_cmd_arg)
807def GenerateHwidV3(options):
808 """Generates the HWID of the DUT.
809
810 The HWID is generated based on the given device info and the probe results
811 retrieved by probing the DUT. If there are conflits of component information
812 between device info and probe result, priority is given to device info.
813 """
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800814 if options.device_info:
Ricky Liang7905f272013-03-16 01:57:10 +0800815 with open(options.device_info) as f:
816 device_info = yaml.load(f.read())
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800817 else:
818 device_info = shopfloor.GetDeviceData()
Ricky Liang7905f272013-03-16 01:57:10 +0800819 if options.probe_results:
820 with open(options.probe_results) as f:
821 probe_results = hwid_tool.ProbeResults.Decode(f.read())
822 else:
823 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800824 print 'device_info:'
Ricky Liangf1ded8a2013-06-25 11:29:01 +0800825 print yaml.dump(device_info)
Ricky Liang5b4568d2013-04-23 17:15:23 +0800826 print 'probe results:'
Ricky Liang53390232013-03-08 15:37:57 +0800827 print probe_results.Encode()
828
829 # Do not log device_info for now until we're sure that it does not contain
830 # any sensitive infomation.
831 # TODO(jcliang): Add logging for device_info when appropriate.
832
Andy Cheng0465d132013-03-20 12:12:06 +0800833 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800834 'probe',
835 found_components=probe_results.found_probe_value_map,
836 missing_component_classes=probe_results.missing_component_classes,
837 volatiles=probe_results.found_volatile_values,
838 initial_configs=probe_results.initial_configs)
839
Ricky Lianga70a1202013-03-15 15:03:17 +0800840 hwid_object = GetGooftool(options).GenerateHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800841 device_info, probe_results)
Ricky Liang53390232013-03-08 15:37:57 +0800842
843 final_bom = {}
844 for component_class, component_values in (
845 hwid_object.bom.components.iteritems()):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800846 final_bom[component_class] = [v.probed_values for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800847 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800848 'final_bom',
849 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800850 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800851 'generated_hwid',
852 encoded_string=hwid_object.encoded_string,
853 binary_string=hwid_object.binary_string)
854 print 'Encoded HWID string:', hwid_object.encoded_string
855 print 'Binary HWID string:', hwid_object.binary_string
856
857
858@Command('verify_hwid_v3',
859 _board_cmd_arg,
860 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800861 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800862 _hwid_cmd_arg)
863def VerifyHwidV3(options):
864 """Verify system HWID properties match probed device properties.
865
866 First probe components, volatile and initial_config parameters for
867 the DUT. Then use the available device data to produce a list of
868 candidate HWIDs. Then verify the HWID from the DUT is present in
869 that list. Then verify that the DUT initial config values match
870 those specified for its HWID. Finally, verify that VPD contains all
871 the necessary fields as specified by the board data, and when
872 possible verify that values are legitimate.
873 """
Ricky Liang7905f272013-03-16 01:57:10 +0800874 if not options.probe_results:
875 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800876 if options.hwid:
877 hwid_str = options.hwid
878 else:
879 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
880 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
881 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800882 if options.probe_results:
883 # Pull in probe results (including VPD data) from the given file
884 # rather than probing the current system.
885 with open(options.probe_results) as f:
886 probe_results = hwid_tool.ProbeResults.Decode(f.read())
887 probed_ro_vpd = {}
888 probed_rw_vpd = {}
889 for k, v in probe_results.found_volatile_values.items():
890 # Use items(), not iteritems(), since we will be modifying the dict in the
891 # loop.
892 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
893 if match:
894 del probe_results.found_volatile_values[k]
895 (probed_ro_vpd if match.group(1) == 'ro'
896 else probed_rw_vpd)[match.group(2)] = v
897 else:
898 probe_results = Probe()
899 probed_ro_vpd = ReadRoVpd(main_fw_file)
900 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800901 print 'probe result:'
902 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800903 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800904 'probe',
905 found_components=probe_results.found_probe_value_map,
906 missing_component_classes=probe_results.missing_component_classes,
907 volatiles=probe_results.found_volatile_values,
908 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800909 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800910 probed_rw_vpd=FilterDict(probed_rw_vpd))
911
Ricky Liangeede7922013-06-19 10:18:41 +0800912 if not options.board:
913 options.board = common.ProbeBoard(hwid_str)
Ricky Lianga70a1202013-03-15 15:03:17 +0800914 GetGooftool(options).VerifyHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800915 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800916
Andy Cheng0465d132013-03-20 12:12:06 +0800917 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800918 print 'Verification SUCCESS!'
919
920
Ricky Liang59611a62013-06-11 13:47:33 +0800921def ParseDecodedHWID(hwid):
922 """Parse the HWID object into a more compact dict.
923
924 Args:
925 hwid: A decoded HWID object.
926
927 Returns:
928 A dict containing the board name, the binary string, and the list of
929 components.
930 """
931 results = {}
932 results['board'] = hwid.database.board
933 results['binary_string'] = hwid.binary_string
934 results['components'] = collections.defaultdict(list)
935 components = hwid.bom.components
936 for comp_cls in sorted(components):
937 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
938 if not probed_values:
939 db_components = hwid.database.components
940 probed_values = db_components.GetComponentAttributes(
941 comp_cls, comp_name).get('values')
942 results['components'][comp_cls].append(
943 {comp_name: probed_values if probed_values else None})
944 # Convert defaultdict to dict.
945 results['components'] = dict(results['components'])
946 return results
947
948
Ricky Liang7905f272013-03-16 01:57:10 +0800949@Command('decode_hwid_v3',
950 _board_cmd_arg,
951 _hwdb_path_cmd_arg,
952 _hwid_cmd_arg)
953def DecodeHwidV3(options):
954 """Decodes the given v3 HWID and prints out decoded information.
955
956 If no HWID is given, the HWID stored on the device will be loaded and used
957 instead.
958 """
Ricky Liangeede7922013-06-19 10:18:41 +0800959 if not options.board:
960 options.board = common.ProbeBoard(options.hwid)
Ricky Liang7905f272013-03-16 01:57:10 +0800961 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
962 hwdb_path=options.hwdb_path).DecodeHwidV3(
963 options.hwid)
Ricky Liang59611a62013-06-11 13:47:33 +0800964 print yaml.dump(ParseDecodedHWID(decoded_hwid_context),
965 default_flow_style=False)
Ricky Liang7905f272013-03-16 01:57:10 +0800966
967
henryhsu44d793a2013-07-20 00:07:38 +0800968@Command('get_firmware_hash',
969 CmdArg('--file', metavar='FILE', help='Firmware File.'))
970def GetFirmwareHash(options):
971 if os.path.exists(options.file):
972 hashes = CalculateFirmwareHashes(options.file)
973 for section, value_dict in hashes.iteritems():
974 print "%s:" % section
975 for key, value in value_dict.iteritems():
976 print " %s: %s" % (key, value)
977 else:
978 raise Error('File does not exist: %s' % options.file)
979
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800980def Main():
981 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800982
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800983 options = ParseCmdline(
984 'Perform Google required factory tests.',
985 CmdArg('-l', '--log', metavar='PATH',
986 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800987 CmdArg('--suppress-event-logs', action='store_true',
988 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800989 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800990 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800991 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800992 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800993 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
994 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800995 logging.debug('gooftool options: %s', repr(options))
996 try:
997 logging.debug('GOOFTOOL command %r', options.command_name)
998 options.command(options)
999 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
1000 except Error, e:
1001 logging.exception(e)
1002 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
1003 except Exception, e:
1004 logging.exception(e)
1005 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
1006
1007
1008if __name__ == '__main__':
1009 Main()