blob: 5c5637d05552fc5906e23e353fc17a9a23aa68e0 [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Tammo Spalink01e11722012-07-24 10:17:54 -07002# pylint: disable=E1101
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08003#
4# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Google Factory Tool.
9
10This tool is indended to be used on factory assembly lines. It
11provides all of the Google required test functionality and must be run
12on each device as part of the assembly process.
13"""
14
Ricky Liang5b4568d2013-04-23 17:15:23 +080015import collections
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080016import logging
17import os
Jon Salz65266432012-07-30 19:02:49 +080018import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080019import re
20import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080021import time
Jon Salza88b83b2013-05-27 20:00:35 +080022import xmlrpclib
Ricky Liang7905f272013-03-16 01:57:10 +080023import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080024
Andy Cheng2582d292012-12-04 17:38:28 +080025from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080026
Tammo Spalinka40293e2012-07-04 14:58:56 +080027import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080028
Andy Cheng0465d132013-03-20 12:12:06 +080029from cros.factory import event_log
Jon Salz0f8a6842012-09-25 11:28:22 +080030from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070031from cros.factory.common import YamlWrite
Andy Chengc531e2f2012-10-15 19:09:17 +080032from cros.factory.gooftool import Gooftool
Ricky Liang53390232013-03-08 15:37:57 +080033from cros.factory.gooftool import crosfw
Tammo Spalink01e11722012-07-24 10:17:54 -070034from cros.factory.gooftool import report_upload
Andy Cheng8ece7382012-08-22 16:25:42 +080035from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080036from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
Jon Salz193d7c62013-03-07 13:40:19 +080037from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080038from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
39from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070040from cros.factory.hwdb import hwid_tool
cychiang7fe09372012-07-04 14:31:23 +080041from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080042from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080043from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080044
Tammo Spalink5c699832012-07-03 17:50:39 +080045
Tammo Spalink5c699832012-07-03 17:50:39 +080046# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
47# treat that specially (as a smoot exit, as opposed to the more
48# verbose output for generic Error).
49
50
Ricky Lianga70a1202013-03-15 15:03:17 +080051def GetGooftool(options):
52 if options.hwid_version == 2:
53 hwdb_path = getattr(options, 'hwdb_path', None)
54 component_db = (
55 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
56 return Gooftool(hwid_version=2, component_db=component_db)
57 elif options.hwid_version == 3:
58 board = getattr(options, 'board', None)
59 hwdb_path = getattr(options, 'hwdb_path', None)
60 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
61 else:
62 raise Error, 'Invalid HWID version: %r' % options.hwid_version
63
64
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080065@Command('write_hwid',
66 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080067def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080068 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080069
Tammo Spalink95c43732012-07-25 15:57:14 -070070 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080071 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080072 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070073 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080074
75
Ricky Liang53390232013-03-08 15:37:57 +080076_board_cmd_arg = CmdArg(
77 '--board', metavar='BOARD',
78 default=None, help='Board name to test.')
79
Tammo Spalink8fab5312012-05-28 18:33:30 +080080_hwdb_path_cmd_arg = CmdArg(
81 '--hwdb_path', metavar='PATH',
82 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
83 help='Path to the HWID database.')
84
Tammo Spalink95c43732012-07-25 15:57:14 -070085_hwid_status_list_cmd_arg = CmdArg(
86 '--status', nargs='*', default=['supported'],
87 help='allow only HWIDs with these status values')
88
Jon Salzce124fb2012-10-02 17:42:03 +080089_probe_results_cmd_arg = CmdArg(
90 '--probe_results', metavar='RESULTS.yaml',
91 help=('Output from "gooftool probe" (used instead of '
92 'probing this system).'))
93
Ricky Liang53390232013-03-08 15:37:57 +080094_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080095 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +080096 help='A dict of device info to use instead of fetching from shopfllor '
97 'server.')
98
Jon Salzce124fb2012-10-02 17:42:03 +080099_hwid_cmd_arg = CmdArg(
100 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800101 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800102
Tammo Spalink95c43732012-07-25 15:57:14 -0700103
104@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800105 _hwdb_path_cmd_arg,
106 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700107 help='optional BOARD name, needed only if data is present '
108 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800109 CmdArg('--bom', metavar='BOM', help='BOM name'),
110 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800111 CmdArg('--optimistic', action='store_true',
112 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700113 CmdArg('--comps', nargs='*', default=[],
114 help='list of canonical component names'),
115 CmdArg('--missing', nargs='*', default=[],
116 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800117 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700118 help='consider only HWIDs within this list of status values'))
119def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800120 """Determine a list of possible HWIDs using provided args and probeing.
121
122 VOLATILE can always be determined by probing. To get a unique
123 result, VARIANT must be specified for all cases where the matching
124 BOM has more than one associated variant code, otherwise all HWID
125 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700126 alternatively be specified using the --stdin_comps argument, which
127 allows specifying a list of canonical names (one per line) on stdin,
128 one per line. Based on what is known from BOM and stdin_comps,
129 determine a list of components to probe for, and use those probe
130 results to resolve a list of matching HWIDs. If no boms,
131 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800132 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800133
134 Returns (on stdout): A list of HWIDs that match the available probe
135 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700136
137 Example:
138
139 // Three ways to specify a keyboard (assuming it is a variant component)
140 gooftool best_match_hwids --missing keyboard
141 gooftool best_match_hwids --variant A or
142 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800143 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800144
Tammo Spalink5c699832012-07-03 17:50:39 +0800145 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700146 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800147 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800148 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800149 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800150 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800151 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700152 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800153 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800154 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800155 device.VariantExists(options.variant)
156 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700157 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700158 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700159 % YamlWrite(sorted(
160 hwid_tool.ComponentSpecClasses(component_spec) &
161 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700162 component_spec = hwid_tool.CombineComponentSpecs(
163 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700164 if options.comps or options.missing:
165 map(comp_db.CompExists, options.comps)
166 map(comp_db.CompClassExists, options.missing)
167 extra_comp_spec = comp_db.CreateComponentSpec(
168 components=options.comps,
169 missing=options.missing)
170 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
171 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
172 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700173 % YamlWrite(sorted(
174 hwid_tool.ComponentSpecClasses(component_spec) &
175 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700176 component_spec = hwid_tool.CombineComponentSpecs(
177 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700178 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700179 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800180 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800181 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
182 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700183 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700184 'as inputs, and cannot be probed for:\n%s'
185 'This problem can often be addressed by specifying all of '
186 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800187 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700188 print 'probing for missing classes:'
189 print YamlWrite(list(missing_classes))
190 probe_results = Probe(target_comp_classes=list(missing_classes),
191 probe_volatile=False, probe_initial_config=False)
192 cooked_components = comp_db.MatchComponentProbeValues(
193 probe_results.found_probe_value_map)
194 if cooked_components.unmatched:
195 sys.exit('ERROR: some probed components are unrecognized:\n%s'
196 % YamlWrite(cooked_components.unmatched))
197 probed_comp_spec = comp_db.CreateComponentSpec(
198 components=cooked_components.matched,
199 missing=probe_results.missing_component_classes)
200 component_spec = hwid_tool.CombineComponentSpecs(
201 component_spec, probed_comp_spec)
202 print YamlWrite({'component data used for matching': {
203 'missing component classes': component_spec.classes_missing,
204 'found components': component_spec.components}})
205 component_data = hwid_tool.ComponentData(
206 extant_components=hwid_tool.ComponentSpecCompClassMap(
207 component_spec).keys(),
208 classes_missing=component_spec.classes_missing)
209 match_tree = device.BuildMatchTree(component_data)
210 if not match_tree:
211 sys.exit('FAILURE: NO matching BOMs found')
212 print 'potential BOMs/VARIANTs:'
213 potential_variants = set()
214 potential_volatiles = set()
215 for bom_name, variant_tree in match_tree.items():
216 print ' BOM: %-8s VARIANTS: %s' % (
217 bom_name, ', '.join(sorted(variant_tree)))
218 for variant_code in variant_tree:
219 potential_variants.add(variant_code)
220 for volatile_code in device.volatiles:
221 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
222 if status in options.status:
223 potential_volatiles.add(volatile_code)
224 print ''
225 if len(potential_variants) == 0:
226 sys.exit('FAILURE: no matching VARIANTs found')
227 if len(potential_volatiles) == 0:
228 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
229 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700230 if (options.optimistic and
231 len(match_tree) == 1 and
232 len(potential_variants) == 1 and
233 len(potential_volatiles) == 1):
234 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
235 potential_variants.pop(),
236 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800237 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700238 print ('probing VOLATILEs to resolve potential matches: %s\n' %
239 ', '.join(sorted(potential_volatiles)))
240 vol_probe_results = Probe(
241 target_comp_classes=[],
242 probe_volatile=True,
243 probe_initial_config=False)
244 cooked_volatiles = device.MatchVolatileValues(
245 vol_probe_results.found_volatile_values)
246 match_tree = device.BuildMatchTree(
247 component_data, cooked_volatiles.matched_tags)
248 matched_hwids = device.GetMatchTreeHwids(match_tree)
249 if matched_hwids:
250 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800251 if matched_hwids[hwid] in options.status:
252 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700253 return
254 print 'exact HWID matching failed, but the following BOMs match: %s' % (
255 ', '.join(sorted(match_tree)))
256 if options.optimistic and len(match_tree) == 1:
257 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800258 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700259 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800260 if len(variant_matches) == 1:
261 var_code = set(variant_matches).pop()
262 elif len(bom.variants) == 1:
263 var_code = set(bom.variants).pop()
264 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700265 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
266 'because there were too many variants to choose from for BOM %r'
267 % bom_name)
268 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
269 for vol_code in device.volatiles
270 if device.GetHwidStatus(bom_name, var_code, vol_code)
271 in options.status]
272 for hwid in hwids:
273 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800274 return
275 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700276 print ('optimistic matching not attempted because either it was '
277 'not requested, or because the number of BOMs was <> 1\n')
278 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800279
280
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800281@Command('probe',
282 CmdArg('--comps', nargs='*',
283 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800284 CmdArg('--fast_fw_probe', action='store_true',
285 help='Do a fast probe for EC and main firmware versions only. '
286 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800287 CmdArg('--no_vol', action='store_true',
288 help='Do not probe volatile data.'),
289 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800290 help='Do not probe initial_config data.'),
291 CmdArg('--include_vpd', action='store_true',
292 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800293def RunProbe(options):
294 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800295 print GetGooftool(options).Probe(
296 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800297 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800298 probe_volatile=not options.no_vol,
299 probe_initial_config=not options.no_ic,
300 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800301
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800302
Tammo Spalink214caf42012-05-28 10:45:00 +0800303@Command('verify_components',
304 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800305 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800306def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800307 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800308
Tammo Spalink5c699832012-07-03 17:50:39 +0800309 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800310 that a corresponding match exists in the component_db -- make sure
311 that these components are present, that they have been approved, but
312 do not check against any specific BOM/HWID configurations.
313 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800314
Andy Chengc531e2f2012-10-15 19:09:17 +0800315 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800316 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800317 options.target_comps)
318 except ValueError, e:
319 sys.exit(e)
320
Ricky Liang53390232013-03-08 15:37:57 +0800321 PrintVerifyComponentsResults(result)
322
323
324def PrintVerifyComponentsResults(result):
325 """Prints out the results of VerifyComponents method call.
326
327 Groups the results into two groups: 'matches' and 'errors', and prints out
328 their values.
329 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800330 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800331 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800332 errors = []
333 for result_list in result.values():
334 for component_name, _, error in result_list:
335 if component_name:
336 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800337 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800338 errors.append(error)
339
Andy Cheng228a8c92012-08-27 10:53:57 +0800340 if matches:
341 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800342 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800343 print '\nerrors:\n %s' % '\n '.join(errors)
344 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800345 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800346 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800347
348
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800349@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700350 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800351 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800352 _probe_results_cmd_arg,
353 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800354def VerifyHwid(options):
355 """Verify system HWID properties match probed device properties.
356
357 First probe components, volatile and initial_config parameters for
358 the DUT. Then use the available device data to produce a list of
359 candidate HWIDs. Then verify the HWID from the DUT is present in
360 that list. Then verify that the DUT initial config values match
361 those specified for its HWID. Finally, verify that VPD contains all
362 the necessary fields as specified by the board data, and when
363 possible verify that values are legitimate.
364 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800365
Ricky Liangf7857c12012-09-17 13:34:41 +0800366 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800367 for key in ro_vpd_keys:
368 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800369 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700370 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800371 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800372 if (known_valid_values is not None) and (value not in known_valid_values):
373 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800374 for key in rw_vpd_keys:
375 if key not in rw_vpd:
376 sys.exit('Missing required RW VPD field: %s' % key)
377 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
378 value = rw_vpd[key]
379 if (known_valid_values is not None) and (value not in known_valid_values):
380 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800381 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800382 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800383
Jon Salz81350812012-10-11 16:13:22 +0800384 if not options.hwid or not options.probe_results:
385 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800386
387 if options.hwid:
388 hwid_str = options.hwid
389 else:
390 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
391 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700392 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800393 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800394 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700395 device = hw_db.GetDevice(hwid.board)
396 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
397 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800398 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800399 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800400 if options.probe_results:
401 # Pull in probe results (including VPD data) from the given file
402 # rather than probing the current system.
403 probe_results = hwid_tool.ProbeResults.Decode(
404 open(options.probe_results).read())
405 ro_vpd = {}
406 rw_vpd = {}
407 for k, v in probe_results.found_volatile_values.items():
408 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
409 if match:
410 del probe_results.found_volatile_values[k]
411 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
412 else:
413 probe_results = Probe()
414 ro_vpd = ReadRoVpd(main_fw_file)
415 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700416 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
417 probe_results.found_probe_value_map)
418 cooked_volatiles = device.MatchVolatileValues(
419 probe_results.found_volatile_values)
420 cooked_initial_configs = device.MatchInitialConfigValues(
421 probe_results.initial_configs)
422 component_data = hwid_tool.ComponentData(
423 extant_components=cooked_components.matched,
424 classes_missing=probe_results.missing_component_classes)
425 match_tree = device.BuildMatchTree(
426 component_data, cooked_volatiles.matched_tags)
427 matched_hwids = device.GetMatchTreeHwids(match_tree)
428 print 'HWID status: %s\n' % hwid_status
429 print 'probed system components:'
430 print YamlWrite(cooked_components.__dict__)
431 print 'missing component classes:'
432 print YamlWrite(probe_results.missing_component_classes)
433 print 'probed volatiles:'
434 print YamlWrite(cooked_volatiles.__dict__)
435 print 'probed initial_configs:'
436 print YamlWrite(cooked_initial_configs)
437 print 'hwid match tree:'
438 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800439 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800440 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700441 found_components=cooked_components.__dict__,
442 missing_component_classes=probe_results.missing_component_classes,
443 volatiles=cooked_volatiles.__dict__,
444 initial_configs=cooked_initial_configs)
445 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800446 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700447 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800448 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700449 YamlWrite(cooked_components.unmatched))
450 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800451 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700452 component_data.Encode())
453 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800454 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700455 (', '.join(sorted(match_tree)), hwid.bom))
456 err_msg += 'target bom %r matches components' % hwid.bom
457 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
458 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800459 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700460 matched_variants = match_tree.get(hwid.bom, {})
461 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800462 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700463 hwid.variant)
464 matched_volatiles = matched_variants.get(hwid.variant, {})
465 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800466 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700467 hwid.volatile)
468 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800469 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800470 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800471 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700472 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800473
474
475@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700476def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800477 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800478
Ricky Lianga70a1202013-03-15 15:03:17 +0800479 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800480
481
482@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700483def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800484 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800485
Ricky Lianga70a1202013-03-15 15:03:17 +0800486 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800487 logging.info('Firmware bitmap initial locale set to %d (%s).',
488 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800489
490
491@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700492def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800493 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800494
Ricky Lianga70a1202013-03-15 15:03:17 +0800495 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496
497
498@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700499def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800500 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800501
Ricky Lianga70a1202013-03-15 15:03:17 +0800502 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503
504
505@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800506def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800507 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800508
Ricky Lianga70a1202013-03-15 15:03:17 +0800509 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800510
511
512@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700513def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800514 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800515
Ricky Lianga70a1202013-03-15 15:03:17 +0800516 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800517 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800518 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800519
520
521@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700522def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800523 """Enable then verify firmware write protection."""
524
Hung-Te Linb21c6682012-08-01 13:53:57 +0800525 def CalculateLegacyRange(fw_type, length, section_data,
526 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800527 ro_size = length / 2
528 ro_a = int(section_data[0] / ro_size)
529 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
530 if ro_a != ro_b:
531 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800532 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800533 ro_offset = ro_a * ro_size
534 return (ro_offset, ro_size)
535
536 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800537 """Calculate protection size, then invoke flashrom.
538
539 Our supported chips only allow write protecting half their total
540 size, so we parition the flash chipset space accordingly.
541 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800542
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800543 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800544 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800545 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800546 if image.has_section(wp_section):
547 section_data = image.get_section_area(wp_section)
548 ro_offset = section_data[0]
549 ro_size = section_data[1]
550 elif image.has_section(legacy_section):
551 section_data = image.get_section_area(legacy_section)
552 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800553 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800554 else:
555 raise Error('could not find %s firmware section %s or %s' %
556 (fw_type, wp_section, legacy_section))
557
558 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
559 ro_offset, ro_size)
560 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800561
562 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800563 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800564 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
565 if ec_fw_file is not None:
566 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800567 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800568 else:
569 logging.warning('EC not write protected (seems there is no EC flash).')
570
571
572@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800573def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800574 """Zero out the GBB flags, in preparation for transition to release state.
575
576 No GBB flags are set in release/shipping state, but they are useful
577 for factory/development. See "gbb_utility --flags" for details.
578 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800579
Ricky Lianga70a1202013-03-15 15:03:17 +0800580 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800581 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800582
583
Jon Salzaa3a30e2013-05-15 15:56:28 +0800584@Command('clear_factory_vpd_entries')
585def ClearFactoryVPDEntries(options): # pylint: disable=W0613
586 """Clears factory.* items in the RW VPD."""
587 entries = GetGooftool(options).ClearFactoryVPDEntries()
588 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
589
590
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800591@Command('prepare_wipe',
592 CmdArg('--fast', action='store_true',
593 help='use non-secure but faster wipe method.'))
594def PrepareWipe(options):
595 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800596
Ricky Lianga70a1202013-03-15 15:03:17 +0800597 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800598
599@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800600 CmdArg('--no_write_protect', action='store_true',
601 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700602 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800603 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800604 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800605 _probe_results_cmd_arg,
606 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800607def Verify(options):
608 """Verifies if whole factory process is ready for finalization.
609
610 This routine performs all the necessary checks to make sure the
611 device is ready to be finalized, but does not modify state. These
612 checks include dev switch, firmware write protection switch, hwid,
613 system time, keys, and root file system.
614 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800615
Hung-Te Lin6d827542012-07-19 11:50:41 +0800616 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800617 VerifyWPSwitch(options)
618 VerifyDevSwitch(options)
619 if options.hwid_version == 2:
620 VerifyHwid(options)
621 elif options.hwid_version == 3:
622 VerifyHwidV3(options)
623 else:
624 raise Error, 'Invalid HWID version: %r' % options.hwid_version
625 VerifySystemTime(options)
626 VerifyKeys(options)
627 VerifyRootFs(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800628
629
Tammo Spalink86a61c62012-05-25 15:10:35 +0800630@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700631def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800632 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800633
Andy Cheng0465d132013-03-20 12:12:06 +0800634 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800635 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800636
637
Jon Salza88b83b2013-05-27 20:00:35 +0800638def CreateReportArchiveBlob(*args, **kwargs):
639 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800640
Jon Salza88b83b2013-05-27 20:00:35 +0800641 Args:
642 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800643
Jon Salza88b83b2013-05-27 20:00:35 +0800644 Returns:
645 An xmlrpclib.Binary object containing a .tar.xz file.
646 """
647 with open(CreateReportArchive(*args, **kwargs)) as f:
648 return xmlrpclib.Binary(f.read())
649
650
651def CreateReportArchive(device_sn=None, add_file=None):
652 """Creates a report archive in a temporary directory.
653
654 Args:
655 device_sn: The device serial number (optional).
656 add_file: A list of files to add (optional).
657
658 Returns:
659 Path to the archive.
660 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800661 def NormalizeAsFileName(token):
662 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800663
664 target_name = '%s%s.tar.xz' % (
665 time.strftime('%Y%m%dT%H%M%SZ',
666 time.gmtime()),
667 ("" if device_sn is None else
668 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800669 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800670
Tammo Spalink86a61c62012-05-25 15:10:35 +0800671 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800672 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800673 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800674 if add_file:
675 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800676 # Require absolute paths since the tar command may change the
677 # directory.
678 if not f.startswith('/'):
679 raise Error('Not an absolute path: %s' % f)
680 if not os.path.exists(f):
681 raise Error('File does not exist: %s' % f)
682 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800683 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800684
685 if ((cmd_result.status == 1) and
686 all((x == '' or
687 'file changed as we read it' in x or
688 "Removing leading `/' from member names" in x)
689 for x in cmd_result.stderr.split('\n'))):
690 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800691 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800692 ignore_stdout=True)
693 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800694 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
695 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800696
Jon Salza88b83b2013-05-27 20:00:35 +0800697 return target_path
698
699_upload_method_cmd_arg = CmdArg(
700 '--upload_method', metavar='METHOD:PARAM',
701 help=('How to perform the upload. METHOD should be one of '
702 '{ftp, shopfloor, ftps, cpfe}.'))
703_add_file_cmd_arg = CmdArg(
704 '--add_file', metavar='FILE', action='append',
705 help='Extra file to include in report (must be an absolute path)')
706
707@Command('upload_report',
708 _upload_method_cmd_arg,
709 _add_file_cmd_arg)
710def UploadReport(options):
711 """Create a report containing key device details."""
712 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
713 device_sn = ro_vpd.get('serial_number', None)
714 if device_sn is None:
715 logging.warning('RO_VPD missing device serial number')
716 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
717 target_path = CreateReportArchive(device_sn)
718
Tammo Spalink86a61c62012-05-25 15:10:35 +0800719 if options.upload_method is None or options.upload_method == 'none':
720 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
721 return
722 method, param = options.upload_method.split(':', 1)
723 if method == 'shopfloor':
724 report_upload.ShopFloorUpload(target_path, param)
725 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700726 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800727 elif method == 'ftps':
728 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
729 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800730 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800731 else:
732 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800733
734
735@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800736 CmdArg('--no_write_protect', action='store_true',
737 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800738 CmdArg('--fast', action='store_true',
739 help='use non-secure but faster wipe method.'),
740 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700741 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800742 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800743 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800744 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800745 _probe_results_cmd_arg,
746 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800747def Finalize(options):
748 """Verify system readiness and trigger transition into release state.
749
Jon Salzaa3a30e2013-05-15 15:56:28 +0800750 This routine does the following:
751 - Verifies system state (see verify command)
752 - Modifies firmware bitmaps to match locale
753 - Clears all factory-friendly flags from the GBB
754 - Removes factory-specific entries from RW_VPD (factory.*)
755 - Enables firmware write protection (cannot rollback after this)
756 - Uploads system logs & reports
757 - Sets the necessary boot flags to cause wipe of the factory image on the
758 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800759 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800760 Verify(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800761 SetFirmwareBitmapLocale(options)
762 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800763 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800764 if options.no_write_protect:
765 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800766 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800767 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800768 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800769 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800770 UploadReport(options)
771 PrepareWipe(options)
772
773
Ricky Liang53390232013-03-08 15:37:57 +0800774@Command('verify_components_v3',
775 _board_cmd_arg,
776 _hwdb_path_cmd_arg,
777 CmdArg('target_comps', nargs='*'))
778def VerifyComponentsV3(options):
779 """Verify that probeable components all match entries in the component_db.
780
781 This method uses the HWIDv3 component database to verify components.
782
783 Probe for each component class in the target_comps and verify
784 that a corresponding match exists in the component_db -- make sure
785 that these components are present, that they have been approved, but
786 do not check against any specific BOM/HWID configurations.
787 """
788
Ricky Lianga70a1202013-03-15 15:03:17 +0800789 result = GetGooftool(options).VerifyComponentsV3(options.target_comps)
Ricky Liang53390232013-03-08 15:37:57 +0800790 PrintVerifyComponentsResults(result)
791
792
793@Command('generate_hwid_v3',
794 _board_cmd_arg,
795 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800796 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800797 _device_info_cmd_arg)
798def GenerateHwidV3(options):
799 """Generates the HWID of the DUT.
800
801 The HWID is generated based on the given device info and the probe results
802 retrieved by probing the DUT. If there are conflits of component information
803 between device info and probe result, priority is given to device info.
804 """
805 try:
Ricky Liang7905f272013-03-16 01:57:10 +0800806 with open(options.device_info) as f:
807 device_info = yaml.load(f.read())
Ricky Liang53390232013-03-08 15:37:57 +0800808 except Exception, e:
809 raise Error, 'Invalid device_info: %s' % e
Ricky Liang7905f272013-03-16 01:57:10 +0800810 if options.probe_results:
811 with open(options.probe_results) as f:
812 probe_results = hwid_tool.ProbeResults.Decode(f.read())
813 else:
814 probe_results = Probe()
Ricky Liang53390232013-03-08 15:37:57 +0800815 print 'device_info:'
816 print device_info
Ricky Liang5b4568d2013-04-23 17:15:23 +0800817 print 'probe results:'
Ricky Liang53390232013-03-08 15:37:57 +0800818 print probe_results.Encode()
819
820 # Do not log device_info for now until we're sure that it does not contain
821 # any sensitive infomation.
822 # TODO(jcliang): Add logging for device_info when appropriate.
823
Andy Cheng0465d132013-03-20 12:12:06 +0800824 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800825 'probe',
826 found_components=probe_results.found_probe_value_map,
827 missing_component_classes=probe_results.missing_component_classes,
828 volatiles=probe_results.found_volatile_values,
829 initial_configs=probe_results.initial_configs)
830
Ricky Lianga70a1202013-03-15 15:03:17 +0800831 hwid_object = GetGooftool(options).GenerateHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800832 device_info, probe_results)
Ricky Liang53390232013-03-08 15:37:57 +0800833
834 final_bom = {}
835 for component_class, component_values in (
836 hwid_object.bom.components.iteritems()):
Ricky Liang5b4568d2013-04-23 17:15:23 +0800837 final_bom[component_class] = [v.probed_values for v in component_values]
Andy Cheng0465d132013-03-20 12:12:06 +0800838 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800839 'final_bom',
840 final_bom=final_bom)
Andy Cheng0465d132013-03-20 12:12:06 +0800841 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800842 'generated_hwid',
843 encoded_string=hwid_object.encoded_string,
844 binary_string=hwid_object.binary_string)
845 print 'Encoded HWID string:', hwid_object.encoded_string
846 print 'Binary HWID string:', hwid_object.binary_string
847
848
849@Command('verify_hwid_v3',
850 _board_cmd_arg,
851 _hwdb_path_cmd_arg,
Ricky Liang7905f272013-03-16 01:57:10 +0800852 _probe_results_cmd_arg,
Ricky Liang53390232013-03-08 15:37:57 +0800853 _hwid_cmd_arg)
854def VerifyHwidV3(options):
855 """Verify system HWID properties match probed device properties.
856
857 First probe components, volatile and initial_config parameters for
858 the DUT. Then use the available device data to produce a list of
859 candidate HWIDs. Then verify the HWID from the DUT is present in
860 that list. Then verify that the DUT initial config values match
861 those specified for its HWID. Finally, verify that VPD contains all
862 the necessary fields as specified by the board data, and when
863 possible verify that values are legitimate.
864 """
Ricky Liang7905f272013-03-16 01:57:10 +0800865 if not options.probe_results:
866 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Ricky Liang53390232013-03-08 15:37:57 +0800867 if options.hwid:
868 hwid_str = options.hwid
869 else:
870 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
871 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
872 print 'Verifying HWID: %r\n' % hwid_str
Ricky Liang7905f272013-03-16 01:57:10 +0800873 if options.probe_results:
874 # Pull in probe results (including VPD data) from the given file
875 # rather than probing the current system.
876 with open(options.probe_results) as f:
877 probe_results = hwid_tool.ProbeResults.Decode(f.read())
878 probed_ro_vpd = {}
879 probed_rw_vpd = {}
880 for k, v in probe_results.found_volatile_values.items():
881 # Use items(), not iteritems(), since we will be modifying the dict in the
882 # loop.
883 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
884 if match:
885 del probe_results.found_volatile_values[k]
886 (probed_ro_vpd if match.group(1) == 'ro'
887 else probed_rw_vpd)[match.group(2)] = v
888 else:
889 probe_results = Probe()
890 probed_ro_vpd = ReadRoVpd(main_fw_file)
891 probed_rw_vpd = ReadRwVpd(main_fw_file)
Ricky Liang53390232013-03-08 15:37:57 +0800892 print 'probe result:'
893 print probe_results.Encode()
Andy Cheng0465d132013-03-20 12:12:06 +0800894 event_log.Log(
Ricky Liang53390232013-03-08 15:37:57 +0800895 'probe',
896 found_components=probe_results.found_probe_value_map,
897 missing_component_classes=probe_results.missing_component_classes,
898 volatiles=probe_results.found_volatile_values,
899 initial_configs=probe_results.initial_configs)
Andy Cheng0465d132013-03-20 12:12:06 +0800900 event_log.Log('vpd', probed_ro_vpd=FilterDict(probed_ro_vpd),
Ricky Liang53390232013-03-08 15:37:57 +0800901 probed_rw_vpd=FilterDict(probed_rw_vpd))
902
Ricky Lianga70a1202013-03-15 15:03:17 +0800903 GetGooftool(options).VerifyHwidV3(
Ricky Liangab9d0b82013-03-19 02:15:32 +0800904 hwid_str, probe_results, probed_ro_vpd, probed_rw_vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800905
Andy Cheng0465d132013-03-20 12:12:06 +0800906 event_log.Log('verified_hwid', hwid=hwid_str)
Ricky Liang53390232013-03-08 15:37:57 +0800907 print 'Verification SUCCESS!'
908
909
Ricky Liang59611a62013-06-11 13:47:33 +0800910def ParseDecodedHWID(hwid):
911 """Parse the HWID object into a more compact dict.
912
913 Args:
914 hwid: A decoded HWID object.
915
916 Returns:
917 A dict containing the board name, the binary string, and the list of
918 components.
919 """
920 results = {}
921 results['board'] = hwid.database.board
922 results['binary_string'] = hwid.binary_string
923 results['components'] = collections.defaultdict(list)
924 components = hwid.bom.components
925 for comp_cls in sorted(components):
926 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
927 if not probed_values:
928 db_components = hwid.database.components
929 probed_values = db_components.GetComponentAttributes(
930 comp_cls, comp_name).get('values')
931 results['components'][comp_cls].append(
932 {comp_name: probed_values if probed_values else None})
933 # Convert defaultdict to dict.
934 results['components'] = dict(results['components'])
935 return results
936
937
Ricky Liang7905f272013-03-16 01:57:10 +0800938@Command('decode_hwid_v3',
939 _board_cmd_arg,
940 _hwdb_path_cmd_arg,
941 _hwid_cmd_arg)
942def DecodeHwidV3(options):
943 """Decodes the given v3 HWID and prints out decoded information.
944
945 If no HWID is given, the HWID stored on the device will be loaded and used
946 instead.
947 """
948 decoded_hwid_context = Gooftool(hwid_version=3, board=options.board,
949 hwdb_path=options.hwdb_path).DecodeHwidV3(
950 options.hwid)
Ricky Liang59611a62013-06-11 13:47:33 +0800951 print yaml.dump(ParseDecodedHWID(decoded_hwid_context),
952 default_flow_style=False)
Ricky Liang7905f272013-03-16 01:57:10 +0800953
954
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800955def Main():
956 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800957
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800958 options = ParseCmdline(
959 'Perform Google required factory tests.',
960 CmdArg('-l', '--log', metavar='PATH',
961 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800962 CmdArg('--suppress-event-logs', action='store_true',
963 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800964 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800965 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800966 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800967 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800968 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
969 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800970 logging.debug('gooftool options: %s', repr(options))
971 try:
972 logging.debug('GOOFTOOL command %r', options.command_name)
973 options.command(options)
974 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
975 except Error, e:
976 logging.exception(e)
977 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
978 except Exception, e:
979 logging.exception(e)
980 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
981
982
983if __name__ == '__main__':
984 Main()