blob: cd93ce2df9d55dcc9698439e5f24fb8ee2f9fc5e [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
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080015import logging
16import os
Jon Salz65266432012-07-30 19:02:49 +080017import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080018import re
19import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080020import time
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080021
Tammo Spalink8fab5312012-05-28 18:33:30 +080022from tempfile import gettempdir, NamedTemporaryFile
Tammo Spalink86a61c62012-05-25 15:10:35 +080023
Tammo Spalinka40293e2012-07-04 14:58:56 +080024import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080025
Jon Salz0f8a6842012-09-25 11:28:22 +080026from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070027from cros.factory.common import YamlWrite
Tammo Spalink01e11722012-07-24 10:17:54 -070028from cros.factory.gooftool import crosfw
Andy Chengc531e2f2012-10-15 19:09:17 +080029from cros.factory.gooftool import Gooftool
Tammo Spalink01e11722012-07-24 10:17:54 -070030from cros.factory.gooftool import report_upload
31from cros.factory.gooftool.bmpblk import unpack_bmpblock
Andy Cheng8ece7382012-08-22 16:25:42 +080032from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080033from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
Jon Salz05aba9d2012-10-05 17:25:38 +080034from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA, FilterVPD
Tammo Spalinka40293e2012-07-04 14:58:56 +080035from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
36from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070037from cros.factory.hwdb import hwid_tool
Jon Salz83591782012-06-26 11:09:58 +080038from cros.factory.event_log import EventLog, EVENT_LOG_DIR
39from cros.factory.event_log import TimedUuid
cychiang7fe09372012-07-04 14:31:23 +080040from cros.factory.test.factory import FACTORY_LOG_PATH
Jon Salzff88c022012-11-03 12:19:58 +080041from cros.factory.utils.process_utils import Spawn
Tammo Spalink86a61c62012-05-25 15:10:35 +080042
Tammo Spalink5c699832012-07-03 17:50:39 +080043
Tammo Spalink86a61c62012-05-25 15:10:35 +080044# Use a global event log, so that only a single log is created when
45# gooftool is called programmatically.
46_event_log = EventLog('gooftool')
47
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080048
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080049def FindScript(script_name):
Hung-Te Linb7313ca2012-07-31 15:27:57 +080050 # __file__ is in /usr/local/factory/py/gooftool/gooftool.py
51 # scripts should be in /usr/local/factory/sh/*
52 factory_base = os.path.realpath(os.path.join(
53 os.path.dirname(os.path.realpath(__file__)), '..', '..'))
54 script_path = os.path.join(factory_base, 'sh', script_name)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080055 if not os.path.exists(script_path):
56 raise Error('Needed script %s does not exist.' % script_path)
57 return script_path
58
59
Tammo Spalink5c699832012-07-03 17:50:39 +080060# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
61# treat that specially (as a smoot exit, as opposed to the more
62# verbose output for generic Error).
63
64
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080065@Command('write_hwid',
66 CmdArg('hwid', metavar='HWID', help='HWID string'))
67def WriteHwid(options):
68 """Write specified HWID value into the system BB."""
Tammo Spalink95c43732012-07-25 15:57:14 -070069 logging.info('writing hwid string %r', options.hwid)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080070 main_fw = crosfw.LoadMainFirmware()
71 Shell('gbb_utility --set --hwid="%s" "%s"' %
72 (options.hwid, main_fw.GetFileName()))
73 main_fw.Write(sections=['GBB'])
Tammo Spalink86a61c62012-05-25 15:10:35 +080074 _event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070075 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080076
77
Tammo Spalink8fab5312012-05-28 18:33:30 +080078_hwdb_path_cmd_arg = CmdArg(
79 '--hwdb_path', metavar='PATH',
80 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
81 help='Path to the HWID database.')
82
Tammo Spalink95c43732012-07-25 15:57:14 -070083_hwid_status_list_cmd_arg = CmdArg(
84 '--status', nargs='*', default=['supported'],
85 help='allow only HWIDs with these status values')
86
Jon Salzce124fb2012-10-02 17:42:03 +080087_probe_results_cmd_arg = CmdArg(
88 '--probe_results', metavar='RESULTS.yaml',
89 help=('Output from "gooftool probe" (used instead of '
90 'probing this system).'))
91
92_hwid_cmd_arg = CmdArg(
93 '--hwid', metavar='HWID',
94 help=('HWID to verify (instead of the currently set HWID of '
95 'this system)'))
96
Tammo Spalink95c43732012-07-25 15:57:14 -070097
98@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +080099 _hwdb_path_cmd_arg,
100 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700101 help='optional BOARD name, needed only if data is present '
102 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800103 CmdArg('--bom', metavar='BOM', help='BOM name'),
104 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800105 CmdArg('--optimistic', action='store_true',
106 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700107 CmdArg('--comps', nargs='*', default=[],
108 help='list of canonical component names'),
109 CmdArg('--missing', nargs='*', default=[],
110 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800111 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700112 help='consider only HWIDs within this list of status values'))
113def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800114 """Determine a list of possible HWIDs using provided args and probeing.
115
116 VOLATILE can always be determined by probing. To get a unique
117 result, VARIANT must be specified for all cases where the matching
118 BOM has more than one associated variant code, otherwise all HWID
119 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700120 alternatively be specified using the --stdin_comps argument, which
121 allows specifying a list of canonical names (one per line) on stdin,
122 one per line. Based on what is known from BOM and stdin_comps,
123 determine a list of components to probe for, and use those probe
124 results to resolve a list of matching HWIDs. If no boms,
125 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800126 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800127
128 Returns (on stdout): A list of HWIDs that match the available probe
129 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700130
131 Example:
132
133 // Three ways to specify a keyboard (assuming it is a variant component)
134 gooftool best_match_hwids --missing keyboard
135 gooftool best_match_hwids --variant A or
136 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800137 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800138 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700139 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800140 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800141 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800142 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800143 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800144 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700145 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800146 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800147 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800148 device.VariantExists(options.variant)
149 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700150 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700151 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700152 % YamlWrite(sorted(
153 hwid_tool.ComponentSpecClasses(component_spec) &
154 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700155 component_spec = hwid_tool.CombineComponentSpecs(
156 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700157 if options.comps or options.missing:
158 map(comp_db.CompExists, options.comps)
159 map(comp_db.CompClassExists, options.missing)
160 extra_comp_spec = comp_db.CreateComponentSpec(
161 components=options.comps,
162 missing=options.missing)
163 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
164 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
165 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700166 % YamlWrite(sorted(
167 hwid_tool.ComponentSpecClasses(component_spec) &
168 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700169 component_spec = hwid_tool.CombineComponentSpecs(
170 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700171 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700172 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800173 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800174 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
175 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700176 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700177 'as inputs, and cannot be probed for:\n%s'
178 'This problem can often be addressed by specifying all of '
179 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800180 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700181 print 'probing for missing classes:'
182 print YamlWrite(list(missing_classes))
183 probe_results = Probe(target_comp_classes=list(missing_classes),
184 probe_volatile=False, probe_initial_config=False)
185 cooked_components = comp_db.MatchComponentProbeValues(
186 probe_results.found_probe_value_map)
187 if cooked_components.unmatched:
188 sys.exit('ERROR: some probed components are unrecognized:\n%s'
189 % YamlWrite(cooked_components.unmatched))
190 probed_comp_spec = comp_db.CreateComponentSpec(
191 components=cooked_components.matched,
192 missing=probe_results.missing_component_classes)
193 component_spec = hwid_tool.CombineComponentSpecs(
194 component_spec, probed_comp_spec)
195 print YamlWrite({'component data used for matching': {
196 'missing component classes': component_spec.classes_missing,
197 'found components': component_spec.components}})
198 component_data = hwid_tool.ComponentData(
199 extant_components=hwid_tool.ComponentSpecCompClassMap(
200 component_spec).keys(),
201 classes_missing=component_spec.classes_missing)
202 match_tree = device.BuildMatchTree(component_data)
203 if not match_tree:
204 sys.exit('FAILURE: NO matching BOMs found')
205 print 'potential BOMs/VARIANTs:'
206 potential_variants = set()
207 potential_volatiles = set()
208 for bom_name, variant_tree in match_tree.items():
209 print ' BOM: %-8s VARIANTS: %s' % (
210 bom_name, ', '.join(sorted(variant_tree)))
211 for variant_code in variant_tree:
212 potential_variants.add(variant_code)
213 for volatile_code in device.volatiles:
214 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
215 if status in options.status:
216 potential_volatiles.add(volatile_code)
217 print ''
218 if len(potential_variants) == 0:
219 sys.exit('FAILURE: no matching VARIANTs found')
220 if len(potential_volatiles) == 0:
221 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
222 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700223 if (options.optimistic and
224 len(match_tree) == 1 and
225 len(potential_variants) == 1 and
226 len(potential_volatiles) == 1):
227 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
228 potential_variants.pop(),
229 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800230 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700231 print ('probing VOLATILEs to resolve potential matches: %s\n' %
232 ', '.join(sorted(potential_volatiles)))
233 vol_probe_results = Probe(
234 target_comp_classes=[],
235 probe_volatile=True,
236 probe_initial_config=False)
237 cooked_volatiles = device.MatchVolatileValues(
238 vol_probe_results.found_volatile_values)
239 match_tree = device.BuildMatchTree(
240 component_data, cooked_volatiles.matched_tags)
241 matched_hwids = device.GetMatchTreeHwids(match_tree)
242 if matched_hwids:
243 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800244 if matched_hwids[hwid] in options.status:
245 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700246 return
247 print 'exact HWID matching failed, but the following BOMs match: %s' % (
248 ', '.join(sorted(match_tree)))
249 if options.optimistic and len(match_tree) == 1:
250 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800251 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700252 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800253 if len(variant_matches) == 1:
254 var_code = set(variant_matches).pop()
255 elif len(bom.variants) == 1:
256 var_code = set(bom.variants).pop()
257 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700258 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
259 'because there were too many variants to choose from for BOM %r'
260 % bom_name)
261 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
262 for vol_code in device.volatiles
263 if device.GetHwidStatus(bom_name, var_code, vol_code)
264 in options.status]
265 for hwid in hwids:
266 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800267 return
268 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700269 print ('optimistic matching not attempted because either it was '
270 'not requested, or because the number of BOMs was <> 1\n')
271 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800272
273
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800274@Command('probe',
275 CmdArg('--comps', nargs='*',
276 help='List of keys from the component_db registry.'),
277 CmdArg('--no_vol', action='store_true',
278 help='Do not probe volatile data.'),
279 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800280 help='Do not probe initial_config data.'),
281 CmdArg('--include_vpd', action='store_true',
282 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800283def RunProbe(options):
284 """Print yaml-formatted breakdown of probed device properties."""
Tammo Spalink01e11722012-07-24 10:17:54 -0700285 probe_results = Probe(target_comp_classes=options.comps,
Jon Salz0f8a6842012-09-25 11:28:22 +0800286 probe_volatile=not options.no_vol,
287 probe_initial_config=not options.no_ic,
288 probe_vpd=options.include_vpd)
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800289 print probe_results.Encode()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800290
291
Tammo Spalink214caf42012-05-28 10:45:00 +0800292@Command('verify_components',
293 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800294 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800295def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800296 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800297
Tammo Spalink5c699832012-07-03 17:50:39 +0800298 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800299 that a corresponding match exists in the component_db -- make sure
300 that these components are present, that they have been approved, but
301 do not check against any specific BOM/HWID configurations.
302 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800303 comp_db = hwid_tool.HardwareDb(options.hwdb_path).comp_db
Andy Chengc531e2f2012-10-15 19:09:17 +0800304 try:
305 result = Gooftool(component_db=comp_db).VerifyComponents(
306 options.target_comps)
307 except ValueError, e:
308 sys.exit(e)
309
310 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800311 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800312 errors = []
313 for result_list in result.values():
314 for component_name, _, error in result_list:
315 if component_name:
316 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800317 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800318 errors.append(error)
319
Andy Cheng228a8c92012-08-27 10:53:57 +0800320 if matches:
321 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800322 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800323 print '\nerrors:\n %s' % '\n '.join(errors)
324 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800325 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800326 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800327
328
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800329@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700330 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800331 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800332 _probe_results_cmd_arg,
333 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800334def VerifyHwid(options):
335 """Verify system HWID properties match probed device properties.
336
337 First probe components, volatile and initial_config parameters for
338 the DUT. Then use the available device data to produce a list of
339 candidate HWIDs. Then verify the HWID from the DUT is present in
340 that list. Then verify that the DUT initial config values match
341 those specified for its HWID. Finally, verify that VPD contains all
342 the necessary fields as specified by the board data, and when
343 possible verify that values are legitimate.
344 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800345 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800346 for key in ro_vpd_keys:
347 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800348 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700349 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800350 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800351 if (known_valid_values is not None) and (value not in known_valid_values):
352 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800353 for key in rw_vpd_keys:
354 if key not in rw_vpd:
355 sys.exit('Missing required RW VPD field: %s' % key)
356 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
357 value = rw_vpd[key]
358 if (known_valid_values is not None) and (value not in known_valid_values):
359 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Jon Salz05aba9d2012-10-05 17:25:38 +0800360 _event_log.Log('vpd', ro_vpd=FilterVPD(ro_vpd), rw_vpd=FilterVPD(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800361 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800362
Jon Salz81350812012-10-11 16:13:22 +0800363 if not options.hwid or not options.probe_results:
364 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800365
366 if options.hwid:
367 hwid_str = options.hwid
368 else:
369 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
370 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700371 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800372 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800373 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700374 device = hw_db.GetDevice(hwid.board)
375 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
376 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800377 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800378 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800379 if options.probe_results:
380 # Pull in probe results (including VPD data) from the given file
381 # rather than probing the current system.
382 probe_results = hwid_tool.ProbeResults.Decode(
383 open(options.probe_results).read())
384 ro_vpd = {}
385 rw_vpd = {}
386 for k, v in probe_results.found_volatile_values.items():
387 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
388 if match:
389 del probe_results.found_volatile_values[k]
390 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
391 else:
392 probe_results = Probe()
393 ro_vpd = ReadRoVpd(main_fw_file)
394 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700395 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
396 probe_results.found_probe_value_map)
397 cooked_volatiles = device.MatchVolatileValues(
398 probe_results.found_volatile_values)
399 cooked_initial_configs = device.MatchInitialConfigValues(
400 probe_results.initial_configs)
401 component_data = hwid_tool.ComponentData(
402 extant_components=cooked_components.matched,
403 classes_missing=probe_results.missing_component_classes)
404 match_tree = device.BuildMatchTree(
405 component_data, cooked_volatiles.matched_tags)
406 matched_hwids = device.GetMatchTreeHwids(match_tree)
407 print 'HWID status: %s\n' % hwid_status
408 print 'probed system components:'
409 print YamlWrite(cooked_components.__dict__)
410 print 'missing component classes:'
411 print YamlWrite(probe_results.missing_component_classes)
412 print 'probed volatiles:'
413 print YamlWrite(cooked_volatiles.__dict__)
414 print 'probed initial_configs:'
415 print YamlWrite(cooked_initial_configs)
416 print 'hwid match tree:'
417 print YamlWrite(match_tree)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800418 _event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800419 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700420 found_components=cooked_components.__dict__,
421 missing_component_classes=probe_results.missing_component_classes,
422 volatiles=cooked_volatiles.__dict__,
423 initial_configs=cooked_initial_configs)
424 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800425 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700426 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800427 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700428 YamlWrite(cooked_components.unmatched))
429 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800430 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700431 component_data.Encode())
432 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800433 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700434 (', '.join(sorted(match_tree)), hwid.bom))
435 err_msg += 'target bom %r matches components' % hwid.bom
436 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
437 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800438 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700439 matched_variants = match_tree.get(hwid.bom, {})
440 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800441 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700442 hwid.variant)
443 matched_volatiles = matched_variants.get(hwid.variant, {})
444 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800445 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700446 hwid.volatile)
447 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800448 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800449 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Tammo Spalink5c699832012-07-03 17:50:39 +0800450 _event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700451 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800452
453
454@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700455def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800456 """Verify keys in firmware and SSD match."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800457 script = FindScript('verify_keys.sh')
Andy Cheng025eedc2012-11-13 18:23:22 +0800458 kernel_device = Gooftool().GetReleaseKernelPartitionPath()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800459 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
460 result = Shell('%s %s %s' % (script, kernel_device, main_fw_file))
461 if not result.success:
462 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
463
464
465@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700466def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800467 """Use VPD locale value to set firmware bitmap default language."""
468 image_file = crosfw.LoadMainFirmware().GetFileName()
469 locale = ReadRoVpd(image_file).get('initial_locale', None)
470 if locale is None:
471 raise Error, 'Missing initial_locale VPD.'
472 bitmap_locales = []
473 with NamedTemporaryFile() as f:
474 Shell('gbb_utility -g --bmpfv=%s %s' % (f.name, image_file))
Tammo Spalink01e11722012-07-24 10:17:54 -0700475 bmpblk_data = unpack_bmpblock(f.read())
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800476 bitmap_locales = bmpblk_data.get('locales', bitmap_locales)
477 # Some locale values are just a language code and others are a
478 # hyphen-separated language code and country code pair. We care
479 # only about the language code part.
480 language_code = locale.partition('-')[0]
481 if language_code not in bitmap_locales:
482 raise Error, ('Firmware bitmaps do not contain support for the specified '
483 'initial locale language %r' % language_code)
484 else:
485 locale_index = bitmap_locales.index(language_code)
486 logging.info('Firmware bitmap initial locale set to %d (%s).',
487 locale_index, bitmap_locales[locale_index])
488 Shell('crossystem loc_idx=%d' % locale_index)
489
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."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800494 script = FindScript('verify_system_time.sh')
Andy Cheng025eedc2012-11-13 18:23:22 +0800495 rootfs_device = Gooftool().GetReleaseRootPartitionPath()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496 result = Shell('%s %s' % (script, rootfs_device))
497 if not result.success:
498 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
499
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."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800504 script = FindScript('verify_rootfs.sh')
Andy Cheng025eedc2012-11-13 18:23:22 +0800505 rootfs_device = Gooftool().GetReleaseRootPartitionPath()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800506 result = Shell('%s %s' % (script, rootfs_device))
507 if not result.success:
Jon Salzb52ae702012-09-20 13:57:52 +0800508 raise Error, '%r failed, stdout: %r, stderr: %r' % (
509 script, result.stdout, result.stderr)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800510
511
512@Command('verify_switch_wp')
Tammo Spalink01e11722012-07-24 10:17:54 -0700513def VerifyWpSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800514 """Verify hardware write protection switch is enabled."""
515 if Shell('crossystem wpsw_cur').stdout.strip() != '1':
Hung-Te Lin6d827542012-07-19 11:50:41 +0800516 raise Error, 'write protection switch is disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800517
518
519@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700520def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800521 """Verify developer switch is disabled."""
Hung-Te Lind7d34722012-07-26 16:48:35 +0800522 VBSD_HONOR_VIRT_DEV_SWITCH = 0x400
523 flags = int(Shell('crossystem vdat_flags').stdout.strip(), 0)
524 if (flags & VBSD_HONOR_VIRT_DEV_SWITCH) != 0:
525 # System is using virtual developer switch. That will be handled in
526 # prepare_wipe.sh by setting "crossystem disable_dev_request=1" -- although
527 # we can't verify that until next reboot, because the real values are stored
528 # in TPM.
529 logging.warn('VerifyDevSwitch: No physical switch.')
530 _event_log.Log('switch_dev', type='virtual switch')
531 return
532 if Shell('crossystem devsw_cur').stdout.strip() != '0':
533 raise Error, 'developer mode is not disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800534
535
536@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700537def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800538 """Enable then verify firmware write protection."""
539
Hung-Te Linb21c6682012-08-01 13:53:57 +0800540 def CalculateLegacyRange(fw_type, length, section_data,
541 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800542 ro_size = length / 2
543 ro_a = int(section_data[0] / ro_size)
544 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
545 if ro_a != ro_b:
546 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800547 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800548 ro_offset = ro_a * ro_size
549 return (ro_offset, ro_size)
550
551 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800552 """Calculate protection size, then invoke flashrom.
553
554 Our supported chips only allow write protecting half their total
555 size, so we parition the flash chipset space accordingly.
556 """
557 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800558 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800559 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800560 if image.has_section(wp_section):
561 section_data = image.get_section_area(wp_section)
562 ro_offset = section_data[0]
563 ro_size = section_data[1]
564 elif image.has_section(legacy_section):
565 section_data = image.get_section_area(legacy_section)
566 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800567 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800568 else:
569 raise Error('could not find %s firmware section %s or %s' %
570 (fw_type, wp_section, legacy_section))
571
572 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
573 ro_offset, ro_size)
574 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800575
576 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800577 _event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800578 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
579 if ec_fw_file is not None:
580 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800581 _event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800582 else:
583 logging.warning('EC not write protected (seems there is no EC flash).')
584
585
586@Command('clear_gbb_flags')
Tammo Spalink01e11722012-07-24 10:17:54 -0700587def ClearGbbFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800588 """Zero out the GBB flags, in preparation for transition to release state.
589
590 No GBB flags are set in release/shipping state, but they are useful
591 for factory/development. See "gbb_utility --flags" for details.
592 """
Tammo Spalink461ddce2012-05-10 19:28:55 +0800593 script = FindScript('clear_gbb_flags.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800594 result = Shell(script)
595 if not result.success:
596 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800597 _event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800598
599
600@Command('prepare_wipe',
601 CmdArg('--fast', action='store_true',
602 help='use non-secure but faster wipe method.'))
603def PrepareWipe(options):
604 """Prepare system for transition to release state in next reboot."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800605 script = FindScript('prepare_wipe.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800606 tag = 'fast' if options.fast else ''
Andy Cheng025eedc2012-11-13 18:23:22 +0800607 rootfs_device = Gooftool().GetReleaseRootPartitionPath()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800608 result = Shell('FACTORY_WIPE_TAGS=%s %s %s' % (tag, script, rootfs_device))
609 if not result.success:
610 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
611
612
613@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800614 CmdArg('--no_write_protect', action='store_true',
615 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700616 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800617 _hwdb_path_cmd_arg,
618 _probe_results_cmd_arg,
619 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800620def Verify(options):
621 """Verifies if whole factory process is ready for finalization.
622
623 This routine performs all the necessary checks to make sure the
624 device is ready to be finalized, but does not modify state. These
625 checks include dev switch, firmware write protection switch, hwid,
626 system time, keys, and root file system.
627 """
Hung-Te Lin6d827542012-07-19 11:50:41 +0800628 if not options.no_write_protect:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800629 VerifyWpSwitch({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800630 VerifyDevSwitch({})
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800631 VerifyHwid(options)
632 VerifySystemTime({})
633 VerifyKeys({})
634 VerifyRootFs({})
635
636
Tammo Spalink86a61c62012-05-25 15:10:35 +0800637@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700638def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800639 """Write miscellaneous system details to the event log."""
640 raw_cs_data = Shell('crossystem').stdout.strip().splitlines()
641 # The crossytem output contains many lines like:
642 # 'key = value # description'
643 # Use regexps to pull out the key-value pairs and build a dict.
644 cs_data = dict((k, v.strip()) for k, v in
645 map(lambda x: re.findall(r'\A(\S+)\s+=\s+(.*)#.*\Z', x)[0],
646 raw_cs_data))
647 _event_log.Log(
648 'system_details',
649 platform_name=Shell('mosys platform name').stdout.strip(),
650 crossystem=cs_data,
651 modem_status=Shell('modem status').stdout.splitlines(),
652 ec_wp_status=Shell(
653 'flashrom -p internal:bus=lpc --get-size 2>/dev/null && '
654 'flashrom -p internal:bus=lpc --wp-status || '
655 'echo "EC is not available."').stdout,
656 bios_wp_status = Shell(
657 'flashrom -p internal:bus=spi --wp-status').stdout)
658
659
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800660_upload_method_cmd_arg = CmdArg(
661 '--upload_method', metavar='METHOD:PARAM',
662 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800663 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800664_add_file_cmd_arg = CmdArg(
665 '--add_file', metavar='FILE', action='append',
666 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800667
668@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800669 _upload_method_cmd_arg,
670 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800671def UploadReport(options):
672 """Create and a report containing key device details."""
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800673 def NormalizeAsFileName(token):
674 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800675 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
676 device_sn = ro_vpd.get('serial_number', None)
677 if device_sn is None:
678 logging.warning('RO_VPD missing device serial number')
679 device_sn = 'MISSING_SN_' + TimedUuid()
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800680 target_name = '%s_%s.tbz2' % (time.strftime('%Y%m%dT%H%M%SZ', time.gmtime()),
681 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800682 target_path = os.path.join(gettempdir(), target_name)
683 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
684 tar_cmd = 'cd %s ; tar cjf %s *' % (EVENT_LOG_DIR, target_path)
685 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800686 if options.add_file:
687 for f in options.add_file:
688 # Require absolute paths since the tar command may change the
689 # directory.
690 if not f.startswith('/'):
691 raise Error('Not an absolute path: %s' % f)
692 if not os.path.exists(f):
693 raise Error('File does not exist: %s' % f)
694 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800695 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800696
697 if ((cmd_result.status == 1) and
698 all((x == '' or
699 'file changed as we read it' in x or
700 "Removing leading `/' from member names" in x)
701 for x in cmd_result.stderr.split('\n'))):
702 # That's OK. Make sure it's valid though.
703 Spawn(['tar', 'tfj', target_path], check_call=True, log=True,
704 ignore_stdout=True)
705 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800706 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
707 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800708
Tammo Spalink86a61c62012-05-25 15:10:35 +0800709 if options.upload_method is None or options.upload_method == 'none':
710 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
711 return
712 method, param = options.upload_method.split(':', 1)
713 if method == 'shopfloor':
714 report_upload.ShopFloorUpload(target_path, param)
715 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700716 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800717 elif method == 'ftps':
718 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
719 elif method == 'cpfe':
720 report_upload.CpfeUpload(target_path, param)
721 else:
722 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800723
724
725@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800726 CmdArg('--no_write_protect', action='store_true',
727 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800728 CmdArg('--fast', action='store_true',
729 help='use non-secure but faster wipe method.'),
730 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700731 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800732 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800733 _add_file_cmd_arg,
734 _probe_results_cmd_arg,
735 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800736def Finalize(options):
737 """Verify system readiness and trigger transition into release state.
738
Hung-Te Lin6d827542012-07-19 11:50:41 +0800739 This routine first verifies system state (see verify command), modifies
740 firmware bitmaps to match locale, and then clears all of the factory-friendly
741 flags from the GBB. If everything is fine, it enables firmware write
742 protection (cannot rollback after this stage), uploads system logs & reports,
743 and sets the necessary boot flags to cause wipe of the factory image on the
744 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800745 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800746 Verify(options)
747 SetFirmwareBitmapLocale({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800748 ClearGbbFlags({})
749 if options.no_write_protect:
750 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
751 _event_log.Log('wp', fw='both', status='skipped')
752 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800753 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800754 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800755 UploadReport(options)
756 PrepareWipe(options)
757
758
759def Main():
760 """Run sub-command specified by the command line args."""
761 options = ParseCmdline(
762 'Perform Google required factory tests.',
763 CmdArg('-l', '--log', metavar='PATH',
764 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800765 CmdArg('--suppress-event-logs', action='store_true',
766 help='Suppress event logging.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800767 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800768 SetupLogging(options.verbosity, options.log)
Jon Salza4bea382012-10-29 13:00:34 +0800769 _event_log.suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800770 logging.debug('gooftool options: %s', repr(options))
771 try:
772 logging.debug('GOOFTOOL command %r', options.command_name)
773 options.command(options)
774 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
775 except Error, e:
776 logging.exception(e)
777 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
778 except Exception, e:
779 logging.exception(e)
780 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
781
782
783if __name__ == '__main__':
784 Main()