blob: e5bc1d787a3fbdf6e2f8ec0334c17a047e285fdc [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
15
16import 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
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080022
Tammo Spalink8fab5312012-05-28 18:33:30 +080023from tempfile import gettempdir, NamedTemporaryFile
Tammo Spalink86a61c62012-05-25 15:10:35 +080024
Tammo Spalinka40293e2012-07-04 14:58:56 +080025import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080026
Jon Salz0f8a6842012-09-25 11:28:22 +080027from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070028from cros.factory.common import YamlWrite
Tammo Spalink01e11722012-07-24 10:17:54 -070029from cros.factory.gooftool import crosfw
Andy Chengc531e2f2012-10-15 19:09:17 +080030from cros.factory.gooftool import Gooftool
Tammo Spalink01e11722012-07-24 10:17:54 -070031from cros.factory.gooftool import report_upload
32from cros.factory.gooftool.bmpblk import unpack_bmpblock
Andy Cheng8ece7382012-08-22 16:25:42 +080033from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080034from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
Jon Salz05aba9d2012-10-05 17:25:38 +080035from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA, FilterVPD
Tammo Spalinka40293e2012-07-04 14:58:56 +080036from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
37from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070038from cros.factory.hwdb import hwid_tool
Jon Salz83591782012-06-26 11:09:58 +080039from cros.factory.event_log import EventLog, EVENT_LOG_DIR
40from cros.factory.event_log import TimedUuid
cychiang7fe09372012-07-04 14:31:23 +080041from cros.factory.test.factory import FACTORY_LOG_PATH
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
49def GetPrimaryDevicePath(partition=None):
50 def IsFixed(dev):
51 sysfs_path = '/sys/block/%s/removable' % dev
52 return (os.path.exists(sysfs_path) and
53 open(sysfs_path).read().strip() == '0')
54 alpha_re = re.compile(r'^/dev/([a-zA-Z]+)[0-9]+$')
55 alnum_re = re.compile(r'^/dev/([a-zA-Z]+[0-9]+)p[0-9]+$')
cychiangde1dee22012-05-22 09:42:09 +080056 matched_alnum = False
57 dev_set = set()
58 for path in Shell('cgpt find -t rootfs').stdout.strip().split():
59 for dev in alpha_re.findall(path):
60 if IsFixed(dev):
61 dev_set.add(dev)
62 matched_alnum = False
63 for dev in alnum_re.findall(path):
64 if IsFixed(dev):
65 dev_set.add(dev)
66 matched_alnum = True
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080067 if len(dev_set) != 1:
68 raise Error('zero or multiple primary devs: %s' % dev_set)
69 dev_path = os.path.join('/dev', dev_set.pop())
70 if partition is None:
71 return dev_path
cychiangde1dee22012-05-22 09:42:09 +080072 fmt_str = '%sp%d' if matched_alnum else '%s%d'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080073 return fmt_str % (dev_path, partition)
74
75
76def GetReleaseRootPartitionPath():
77 return GetPrimaryDevicePath(5)
78
79
80def GetReleaseKernelPartitionPath():
81 return GetPrimaryDevicePath(4)
82
83
84def FindScript(script_name):
Hung-Te Linb7313ca2012-07-31 15:27:57 +080085 # __file__ is in /usr/local/factory/py/gooftool/gooftool.py
86 # scripts should be in /usr/local/factory/sh/*
87 factory_base = os.path.realpath(os.path.join(
88 os.path.dirname(os.path.realpath(__file__)), '..', '..'))
89 script_path = os.path.join(factory_base, 'sh', script_name)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080090 if not os.path.exists(script_path):
91 raise Error('Needed script %s does not exist.' % script_path)
92 return script_path
93
94
Tammo Spalink5c699832012-07-03 17:50:39 +080095# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
96# treat that specially (as a smoot exit, as opposed to the more
97# verbose output for generic Error).
98
99
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800100@Command('write_hwid',
101 CmdArg('hwid', metavar='HWID', help='HWID string'))
102def WriteHwid(options):
103 """Write specified HWID value into the system BB."""
Tammo Spalink95c43732012-07-25 15:57:14 -0700104 logging.info('writing hwid string %r', options.hwid)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800105 main_fw = crosfw.LoadMainFirmware()
106 Shell('gbb_utility --set --hwid="%s" "%s"' %
107 (options.hwid, main_fw.GetFileName()))
108 main_fw.Write(sections=['GBB'])
Tammo Spalink86a61c62012-05-25 15:10:35 +0800109 _event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700110 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800111
112
Tammo Spalink8fab5312012-05-28 18:33:30 +0800113_hwdb_path_cmd_arg = CmdArg(
114 '--hwdb_path', metavar='PATH',
115 default=hwid_tool.DEFAULT_HWID_DATA_PATH,
116 help='Path to the HWID database.')
117
Tammo Spalink95c43732012-07-25 15:57:14 -0700118_hwid_status_list_cmd_arg = CmdArg(
119 '--status', nargs='*', default=['supported'],
120 help='allow only HWIDs with these status values')
121
Jon Salzce124fb2012-10-02 17:42:03 +0800122_probe_results_cmd_arg = CmdArg(
123 '--probe_results', metavar='RESULTS.yaml',
124 help=('Output from "gooftool probe" (used instead of '
125 'probing this system).'))
126
127_hwid_cmd_arg = CmdArg(
128 '--hwid', metavar='HWID',
129 help=('HWID to verify (instead of the currently set HWID of '
130 'this system)'))
131
Tammo Spalink95c43732012-07-25 15:57:14 -0700132
133@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800134 _hwdb_path_cmd_arg,
135 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700136 help='optional BOARD name, needed only if data is present '
137 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800138 CmdArg('--bom', metavar='BOM', help='BOM name'),
139 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800140 CmdArg('--optimistic', action='store_true',
141 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700142 CmdArg('--comps', nargs='*', default=[],
143 help='list of canonical component names'),
144 CmdArg('--missing', nargs='*', default=[],
145 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800146 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700147 help='consider only HWIDs within this list of status values'))
148def BestMatchHwids(options):
Tammo Spalink8fab5312012-05-28 18:33:30 +0800149 """Determine a list of possible HWIDs using provided args and probeing.
150
151 VOLATILE can always be determined by probing. To get a unique
152 result, VARIANT must be specified for all cases where the matching
153 BOM has more than one associated variant code, otherwise all HWID
154 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700155 alternatively be specified using the --stdin_comps argument, which
156 allows specifying a list of canonical names (one per line) on stdin,
157 one per line. Based on what is known from BOM and stdin_comps,
158 determine a list of components to probe for, and use those probe
159 results to resolve a list of matching HWIDs. If no boms,
160 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800161 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800162
163 Returns (on stdout): A list of HWIDs that match the available probe
164 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700165
166 Example:
167
168 // Three ways to specify a keyboard (assuming it is a variant component)
169 gooftool best_match_hwids --missing keyboard
170 gooftool best_match_hwids --variant A or
171 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800172 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800173 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700174 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800175 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800176 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800177 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800178 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800179 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700180 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800181 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800182 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800183 device.VariantExists(options.variant)
184 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700185 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700186 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700187 % YamlWrite(sorted(
188 hwid_tool.ComponentSpecClasses(component_spec) &
189 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700190 component_spec = hwid_tool.CombineComponentSpecs(
191 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700192 if options.comps or options.missing:
193 map(comp_db.CompExists, options.comps)
194 map(comp_db.CompClassExists, options.missing)
195 extra_comp_spec = comp_db.CreateComponentSpec(
196 components=options.comps,
197 missing=options.missing)
198 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
199 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
200 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700201 % YamlWrite(sorted(
202 hwid_tool.ComponentSpecClasses(component_spec) &
203 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700204 component_spec = hwid_tool.CombineComponentSpecs(
205 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700206 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700207 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800208 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800209 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
210 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700211 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700212 'as inputs, and cannot be probed for:\n%s'
213 'This problem can often be addressed by specifying all of '
214 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800215 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700216 print 'probing for missing classes:'
217 print YamlWrite(list(missing_classes))
218 probe_results = Probe(target_comp_classes=list(missing_classes),
219 probe_volatile=False, probe_initial_config=False)
220 cooked_components = comp_db.MatchComponentProbeValues(
221 probe_results.found_probe_value_map)
222 if cooked_components.unmatched:
223 sys.exit('ERROR: some probed components are unrecognized:\n%s'
224 % YamlWrite(cooked_components.unmatched))
225 probed_comp_spec = comp_db.CreateComponentSpec(
226 components=cooked_components.matched,
227 missing=probe_results.missing_component_classes)
228 component_spec = hwid_tool.CombineComponentSpecs(
229 component_spec, probed_comp_spec)
230 print YamlWrite({'component data used for matching': {
231 'missing component classes': component_spec.classes_missing,
232 'found components': component_spec.components}})
233 component_data = hwid_tool.ComponentData(
234 extant_components=hwid_tool.ComponentSpecCompClassMap(
235 component_spec).keys(),
236 classes_missing=component_spec.classes_missing)
237 match_tree = device.BuildMatchTree(component_data)
238 if not match_tree:
239 sys.exit('FAILURE: NO matching BOMs found')
240 print 'potential BOMs/VARIANTs:'
241 potential_variants = set()
242 potential_volatiles = set()
243 for bom_name, variant_tree in match_tree.items():
244 print ' BOM: %-8s VARIANTS: %s' % (
245 bom_name, ', '.join(sorted(variant_tree)))
246 for variant_code in variant_tree:
247 potential_variants.add(variant_code)
248 for volatile_code in device.volatiles:
249 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
250 if status in options.status:
251 potential_volatiles.add(volatile_code)
252 print ''
253 if len(potential_variants) == 0:
254 sys.exit('FAILURE: no matching VARIANTs found')
255 if len(potential_volatiles) == 0:
256 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
257 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700258 if (options.optimistic and
259 len(match_tree) == 1 and
260 len(potential_variants) == 1 and
261 len(potential_volatiles) == 1):
262 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
263 potential_variants.pop(),
264 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800265 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700266 print ('probing VOLATILEs to resolve potential matches: %s\n' %
267 ', '.join(sorted(potential_volatiles)))
268 vol_probe_results = Probe(
269 target_comp_classes=[],
270 probe_volatile=True,
271 probe_initial_config=False)
272 cooked_volatiles = device.MatchVolatileValues(
273 vol_probe_results.found_volatile_values)
274 match_tree = device.BuildMatchTree(
275 component_data, cooked_volatiles.matched_tags)
276 matched_hwids = device.GetMatchTreeHwids(match_tree)
277 if matched_hwids:
278 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800279 if matched_hwids[hwid] in options.status:
280 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700281 return
282 print 'exact HWID matching failed, but the following BOMs match: %s' % (
283 ', '.join(sorted(match_tree)))
284 if options.optimistic and len(match_tree) == 1:
285 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800286 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700287 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800288 if len(variant_matches) == 1:
289 var_code = set(variant_matches).pop()
290 elif len(bom.variants) == 1:
291 var_code = set(bom.variants).pop()
292 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700293 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
294 'because there were too many variants to choose from for BOM %r'
295 % bom_name)
296 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
297 for vol_code in device.volatiles
298 if device.GetHwidStatus(bom_name, var_code, vol_code)
299 in options.status]
300 for hwid in hwids:
301 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800302 return
303 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700304 print ('optimistic matching not attempted because either it was '
305 'not requested, or because the number of BOMs was <> 1\n')
306 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800307
308
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800309@Command('probe',
310 CmdArg('--comps', nargs='*',
311 help='List of keys from the component_db registry.'),
312 CmdArg('--no_vol', action='store_true',
313 help='Do not probe volatile data.'),
314 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800315 help='Do not probe initial_config data.'),
316 CmdArg('--include_vpd', action='store_true',
317 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800318def RunProbe(options):
319 """Print yaml-formatted breakdown of probed device properties."""
Tammo Spalink01e11722012-07-24 10:17:54 -0700320 probe_results = Probe(target_comp_classes=options.comps,
Jon Salz0f8a6842012-09-25 11:28:22 +0800321 probe_volatile=not options.no_vol,
322 probe_initial_config=not options.no_ic,
323 probe_vpd=options.include_vpd)
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800324 print probe_results.Encode()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800325
326
Tammo Spalink214caf42012-05-28 10:45:00 +0800327@Command('verify_components',
328 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800329 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800330def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800331 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800332
Tammo Spalink5c699832012-07-03 17:50:39 +0800333 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800334 that a corresponding match exists in the component_db -- make sure
335 that these components are present, that they have been approved, but
336 do not check against any specific BOM/HWID configurations.
337 """
Tammo Spalink5c699832012-07-03 17:50:39 +0800338 comp_db = hwid_tool.HardwareDb(options.hwdb_path).comp_db
Andy Chengc531e2f2012-10-15 19:09:17 +0800339 try:
340 result = Gooftool(component_db=comp_db).VerifyComponents(
341 options.target_comps)
342 except ValueError, e:
343 sys.exit(e)
344
345 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800346 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800347 errors = []
348 for result_list in result.values():
349 for component_name, _, error in result_list:
350 if component_name:
351 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800352 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800353 errors.append(error)
354
Andy Cheng228a8c92012-08-27 10:53:57 +0800355 if matches:
356 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800357 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800358 print '\nerrors:\n %s' % '\n '.join(errors)
359 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800360 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800361 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800362
363
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800364@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700365 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800366 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800367 _probe_results_cmd_arg,
368 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800369def VerifyHwid(options):
370 """Verify system HWID properties match probed device properties.
371
372 First probe components, volatile and initial_config parameters for
373 the DUT. Then use the available device data to produce a list of
374 candidate HWIDs. Then verify the HWID from the DUT is present in
375 that list. Then verify that the DUT initial config values match
376 those specified for its HWID. Finally, verify that VPD contains all
377 the necessary fields as specified by the board data, and when
378 possible verify that values are legitimate.
379 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800380 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800381 for key in ro_vpd_keys:
382 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800383 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700384 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800385 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800386 if (known_valid_values is not None) and (value not in known_valid_values):
387 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800388 for key in rw_vpd_keys:
389 if key not in rw_vpd:
390 sys.exit('Missing required RW VPD field: %s' % key)
391 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
392 value = rw_vpd[key]
393 if (known_valid_values is not None) and (value not in known_valid_values):
394 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Jon Salz05aba9d2012-10-05 17:25:38 +0800395 _event_log.Log('vpd', ro_vpd=FilterVPD(ro_vpd), rw_vpd=FilterVPD(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800396 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800397
Jon Salz81350812012-10-11 16:13:22 +0800398 if not options.hwid or not options.probe_results:
399 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800400
401 if options.hwid:
402 hwid_str = options.hwid
403 else:
404 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
405 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700406 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800407 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800408 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700409 device = hw_db.GetDevice(hwid.board)
410 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
411 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800412 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800413 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800414 if options.probe_results:
415 # Pull in probe results (including VPD data) from the given file
416 # rather than probing the current system.
417 probe_results = hwid_tool.ProbeResults.Decode(
418 open(options.probe_results).read())
419 ro_vpd = {}
420 rw_vpd = {}
421 for k, v in probe_results.found_volatile_values.items():
422 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
423 if match:
424 del probe_results.found_volatile_values[k]
425 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
426 else:
427 probe_results = Probe()
428 ro_vpd = ReadRoVpd(main_fw_file)
429 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700430 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
431 probe_results.found_probe_value_map)
432 cooked_volatiles = device.MatchVolatileValues(
433 probe_results.found_volatile_values)
434 cooked_initial_configs = device.MatchInitialConfigValues(
435 probe_results.initial_configs)
436 component_data = hwid_tool.ComponentData(
437 extant_components=cooked_components.matched,
438 classes_missing=probe_results.missing_component_classes)
439 match_tree = device.BuildMatchTree(
440 component_data, cooked_volatiles.matched_tags)
441 matched_hwids = device.GetMatchTreeHwids(match_tree)
442 print 'HWID status: %s\n' % hwid_status
443 print 'probed system components:'
444 print YamlWrite(cooked_components.__dict__)
445 print 'missing component classes:'
446 print YamlWrite(probe_results.missing_component_classes)
447 print 'probed volatiles:'
448 print YamlWrite(cooked_volatiles.__dict__)
449 print 'probed initial_configs:'
450 print YamlWrite(cooked_initial_configs)
451 print 'hwid match tree:'
452 print YamlWrite(match_tree)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800453 _event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800454 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700455 found_components=cooked_components.__dict__,
456 missing_component_classes=probe_results.missing_component_classes,
457 volatiles=cooked_volatiles.__dict__,
458 initial_configs=cooked_initial_configs)
459 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800460 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700461 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800462 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700463 YamlWrite(cooked_components.unmatched))
464 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800465 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700466 component_data.Encode())
467 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800468 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700469 (', '.join(sorted(match_tree)), hwid.bom))
470 err_msg += 'target bom %r matches components' % hwid.bom
471 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
472 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800473 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700474 matched_variants = match_tree.get(hwid.bom, {})
475 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800476 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700477 hwid.variant)
478 matched_volatiles = matched_variants.get(hwid.variant, {})
479 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800480 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700481 hwid.volatile)
482 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800483 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800484 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Tammo Spalink5c699832012-07-03 17:50:39 +0800485 _event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700486 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800487
488
489@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700490def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800491 """Verify keys in firmware and SSD match."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800492 script = FindScript('verify_keys.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800493 kernel_device = GetReleaseKernelPartitionPath()
494 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
495 result = Shell('%s %s %s' % (script, kernel_device, main_fw_file))
496 if not result.success:
497 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
498
499
500@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700501def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800502 """Use VPD locale value to set firmware bitmap default language."""
503 image_file = crosfw.LoadMainFirmware().GetFileName()
504 locale = ReadRoVpd(image_file).get('initial_locale', None)
505 if locale is None:
506 raise Error, 'Missing initial_locale VPD.'
507 bitmap_locales = []
508 with NamedTemporaryFile() as f:
509 Shell('gbb_utility -g --bmpfv=%s %s' % (f.name, image_file))
Tammo Spalink01e11722012-07-24 10:17:54 -0700510 bmpblk_data = unpack_bmpblock(f.read())
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800511 bitmap_locales = bmpblk_data.get('locales', bitmap_locales)
512 # Some locale values are just a language code and others are a
513 # hyphen-separated language code and country code pair. We care
514 # only about the language code part.
515 language_code = locale.partition('-')[0]
516 if language_code not in bitmap_locales:
517 raise Error, ('Firmware bitmaps do not contain support for the specified '
518 'initial locale language %r' % language_code)
519 else:
520 locale_index = bitmap_locales.index(language_code)
521 logging.info('Firmware bitmap initial locale set to %d (%s).',
522 locale_index, bitmap_locales[locale_index])
523 Shell('crossystem loc_idx=%d' % locale_index)
524
525
526@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700527def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800528 """Verify system time is later than release filesystem creation time."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800529 script = FindScript('verify_system_time.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800530 rootfs_device = GetReleaseRootPartitionPath()
531 result = Shell('%s %s' % (script, rootfs_device))
532 if not result.success:
533 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
534
535
536@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700537def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800538 """Verify rootfs on SSD is valid by checking hash."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800539 script = FindScript('verify_rootfs.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800540 rootfs_device = GetReleaseRootPartitionPath()
541 result = Shell('%s %s' % (script, rootfs_device))
542 if not result.success:
Jon Salzb52ae702012-09-20 13:57:52 +0800543 raise Error, '%r failed, stdout: %r, stderr: %r' % (
544 script, result.stdout, result.stderr)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800545
546
547@Command('verify_switch_wp')
Tammo Spalink01e11722012-07-24 10:17:54 -0700548def VerifyWpSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800549 """Verify hardware write protection switch is enabled."""
550 if Shell('crossystem wpsw_cur').stdout.strip() != '1':
Hung-Te Lin6d827542012-07-19 11:50:41 +0800551 raise Error, 'write protection switch is disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800552
553
554@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700555def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800556 """Verify developer switch is disabled."""
Hung-Te Lind7d34722012-07-26 16:48:35 +0800557 VBSD_HONOR_VIRT_DEV_SWITCH = 0x400
558 flags = int(Shell('crossystem vdat_flags').stdout.strip(), 0)
559 if (flags & VBSD_HONOR_VIRT_DEV_SWITCH) != 0:
560 # System is using virtual developer switch. That will be handled in
561 # prepare_wipe.sh by setting "crossystem disable_dev_request=1" -- although
562 # we can't verify that until next reboot, because the real values are stored
563 # in TPM.
564 logging.warn('VerifyDevSwitch: No physical switch.')
565 _event_log.Log('switch_dev', type='virtual switch')
566 return
567 if Shell('crossystem devsw_cur').stdout.strip() != '0':
568 raise Error, 'developer mode is not disabled'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800569
570
571@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700572def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800573 """Enable then verify firmware write protection."""
574
Hung-Te Linb21c6682012-08-01 13:53:57 +0800575 def CalculateLegacyRange(fw_type, length, section_data,
576 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800577 ro_size = length / 2
578 ro_a = int(section_data[0] / ro_size)
579 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
580 if ro_a != ro_b:
581 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800582 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800583 ro_offset = ro_a * ro_size
584 return (ro_offset, ro_size)
585
586 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800587 """Calculate protection size, then invoke flashrom.
588
589 Our supported chips only allow write protecting half their total
590 size, so we parition the flash chipset space accordingly.
591 """
592 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800593 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800594 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800595 if image.has_section(wp_section):
596 section_data = image.get_section_area(wp_section)
597 ro_offset = section_data[0]
598 ro_size = section_data[1]
599 elif image.has_section(legacy_section):
600 section_data = image.get_section_area(legacy_section)
601 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800602 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800603 else:
604 raise Error('could not find %s firmware section %s or %s' %
605 (fw_type, wp_section, legacy_section))
606
607 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
608 ro_offset, ro_size)
609 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800610
611 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800612 _event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800613 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
614 if ec_fw_file is not None:
615 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Tammo Spalink86a61c62012-05-25 15:10:35 +0800616 _event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800617 else:
618 logging.warning('EC not write protected (seems there is no EC flash).')
619
620
621@Command('clear_gbb_flags')
Tammo Spalink01e11722012-07-24 10:17:54 -0700622def ClearGbbFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800623 """Zero out the GBB flags, in preparation for transition to release state.
624
625 No GBB flags are set in release/shipping state, but they are useful
626 for factory/development. See "gbb_utility --flags" for details.
627 """
Tammo Spalink461ddce2012-05-10 19:28:55 +0800628 script = FindScript('clear_gbb_flags.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800629 result = Shell(script)
630 if not result.success:
631 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800632 _event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800633
634
635@Command('prepare_wipe',
636 CmdArg('--fast', action='store_true',
637 help='use non-secure but faster wipe method.'))
638def PrepareWipe(options):
639 """Prepare system for transition to release state in next reboot."""
Tammo Spalink461ddce2012-05-10 19:28:55 +0800640 script = FindScript('prepare_wipe.sh')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800641 tag = 'fast' if options.fast else ''
642 rootfs_device = GetReleaseRootPartitionPath()
643 result = Shell('FACTORY_WIPE_TAGS=%s %s %s' % (tag, script, rootfs_device))
644 if not result.success:
645 raise Error, '%r failed, stderr: %r' % (script, result.stderr)
646
647
648@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800649 CmdArg('--no_write_protect', action='store_true',
650 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700651 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800652 _hwdb_path_cmd_arg,
653 _probe_results_cmd_arg,
654 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800655def Verify(options):
656 """Verifies if whole factory process is ready for finalization.
657
658 This routine performs all the necessary checks to make sure the
659 device is ready to be finalized, but does not modify state. These
660 checks include dev switch, firmware write protection switch, hwid,
661 system time, keys, and root file system.
662 """
Hung-Te Lin6d827542012-07-19 11:50:41 +0800663 if not options.no_write_protect:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800664 VerifyWpSwitch({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800665 VerifyDevSwitch({})
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800666 VerifyHwid(options)
667 VerifySystemTime({})
668 VerifyKeys({})
669 VerifyRootFs({})
670
671
Tammo Spalink86a61c62012-05-25 15:10:35 +0800672@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700673def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800674 """Write miscellaneous system details to the event log."""
675 raw_cs_data = Shell('crossystem').stdout.strip().splitlines()
676 # The crossytem output contains many lines like:
677 # 'key = value # description'
678 # Use regexps to pull out the key-value pairs and build a dict.
679 cs_data = dict((k, v.strip()) for k, v in
680 map(lambda x: re.findall(r'\A(\S+)\s+=\s+(.*)#.*\Z', x)[0],
681 raw_cs_data))
682 _event_log.Log(
683 'system_details',
684 platform_name=Shell('mosys platform name').stdout.strip(),
685 crossystem=cs_data,
686 modem_status=Shell('modem status').stdout.splitlines(),
687 ec_wp_status=Shell(
688 'flashrom -p internal:bus=lpc --get-size 2>/dev/null && '
689 'flashrom -p internal:bus=lpc --wp-status || '
690 'echo "EC is not available."').stdout,
691 bios_wp_status = Shell(
692 'flashrom -p internal:bus=spi --wp-status').stdout)
693
694
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800695_upload_method_cmd_arg = CmdArg(
696 '--upload_method', metavar='METHOD:PARAM',
697 help=('How to perform the upload. METHOD should be one of '
cychiang3b15bd52012-09-08 13:58:18 +0800698 '{ftp, shopfloor, ftps, cpfe}.'))
Jon Salz65266432012-07-30 19:02:49 +0800699_add_file_cmd_arg = CmdArg(
700 '--add_file', metavar='FILE', action='append',
701 help='Extra file to include in report (must be an absolute path)')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800702
703@Command('upload_report',
Jon Salz65266432012-07-30 19:02:49 +0800704 _upload_method_cmd_arg,
705 _add_file_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800706def UploadReport(options):
707 """Create and a report containing key device details."""
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800708 def NormalizeAsFileName(token):
709 return re.sub(r'\W+', '', token).strip()
Tammo Spalink86a61c62012-05-25 15:10:35 +0800710 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
711 device_sn = ro_vpd.get('serial_number', None)
712 if device_sn is None:
713 logging.warning('RO_VPD missing device serial number')
714 device_sn = 'MISSING_SN_' + TimedUuid()
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800715 target_name = '%s_%s.tbz2' % (time.strftime('%Y%m%dT%H%M%SZ', time.gmtime()),
716 NormalizeAsFileName(device_sn))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800717 target_path = os.path.join(gettempdir(), target_name)
718 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
719 tar_cmd = 'cd %s ; tar cjf %s *' % (EVENT_LOG_DIR, target_path)
720 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salz65266432012-07-30 19:02:49 +0800721 if options.add_file:
722 for f in options.add_file:
723 # Require absolute paths since the tar command may change the
724 # directory.
725 if not f.startswith('/'):
726 raise Error('Not an absolute path: %s' % f)
727 if not os.path.exists(f):
728 raise Error('File does not exist: %s' % f)
729 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800730 cmd_result = Shell(tar_cmd)
731 if not cmd_result.success:
732 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
733 (tar_cmd, cmd_result.stderr))
734 if options.upload_method is None or options.upload_method == 'none':
735 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
736 return
737 method, param = options.upload_method.split(':', 1)
738 if method == 'shopfloor':
739 report_upload.ShopFloorUpload(target_path, param)
740 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700741 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800742 elif method == 'ftps':
743 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
744 elif method == 'cpfe':
745 report_upload.CpfeUpload(target_path, param)
746 else:
747 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800748
749
750@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800751 CmdArg('--no_write_protect', action='store_true',
752 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800753 CmdArg('--fast', action='store_true',
754 help='use non-secure but faster wipe method.'),
755 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700756 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800757 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800758 _add_file_cmd_arg,
759 _probe_results_cmd_arg,
760 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800761def Finalize(options):
762 """Verify system readiness and trigger transition into release state.
763
Hung-Te Lin6d827542012-07-19 11:50:41 +0800764 This routine first verifies system state (see verify command), modifies
765 firmware bitmaps to match locale, and then clears all of the factory-friendly
766 flags from the GBB. If everything is fine, it enables firmware write
767 protection (cannot rollback after this stage), uploads system logs & reports,
768 and sets the necessary boot flags to cause wipe of the factory image on the
769 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800770 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800771 Verify(options)
772 SetFirmwareBitmapLocale({})
Hung-Te Lin6d827542012-07-19 11:50:41 +0800773 ClearGbbFlags({})
774 if options.no_write_protect:
775 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
776 _event_log.Log('wp', fw='both', status='skipped')
777 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800778 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800779 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800780 UploadReport(options)
781 PrepareWipe(options)
782
783
784def Main():
785 """Run sub-command specified by the command line args."""
786 options = ParseCmdline(
787 'Perform Google required factory tests.',
788 CmdArg('-l', '--log', metavar='PATH',
789 help='Write logs to this file.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800790 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800791 SetupLogging(options.verbosity, options.log)
792 logging.debug('gooftool options: %s', repr(options))
793 try:
794 logging.debug('GOOFTOOL command %r', options.command_name)
795 options.command(options)
796 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
797 except Error, e:
798 logging.exception(e)
799 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
800 except Exception, e:
801 logging.exception(e)
802 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
803
804
805if __name__ == '__main__':
806 Main()