blob: 240acf134a3990e67801a457efe588d43b86cb7e [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
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080021import threading
Hung-Te Lin6bd16472012-06-20 16:26:47 +080022import time
Jon Salza88b83b2013-05-27 20:00:35 +080023import xmlrpclib
Ricky Liang7905f272013-03-16 01:57:10 +080024import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080025
Andy Cheng2582d292012-12-04 17:38:28 +080026from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080027
Tammo Spalinka40293e2012-07-04 14:58:56 +080028import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080029
Andy Cheng0465d132013-03-20 12:12:06 +080030from cros.factory import event_log
Jon Salz0f8a6842012-09-25 11:28:22 +080031from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070032from cros.factory.common import YamlWrite
Andy Chengc531e2f2012-10-15 19:09:17 +080033from cros.factory.gooftool import Gooftool
Ricky Liang53390232013-03-08 15:37:57 +080034from cros.factory.gooftool import crosfw
Tammo Spalink01e11722012-07-24 10:17:54 -070035from cros.factory.gooftool import report_upload
Andy Cheng8ece7382012-08-22 16:25:42 +080036from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080037from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
henryhsu44d793a2013-07-20 00:07:38 +080038from cros.factory.gooftool.probe import CalculateFirmwareHashes
Jon Salz193d7c62013-03-07 13:40:19 +080039from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080040from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
41from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070042from cros.factory.hwdb import hwid_tool
Ricky Liangeede7922013-06-19 10:18:41 +080043from cros.factory.hwid import common
Ricky Liangc662be32013-12-24 11:50:23 +080044from cros.factory.hwid import hwid_utils
Jon Salzfe9036f2014-01-16 14:11:23 +080045from cros.factory.test.factory import FACTORY_LOG_PATH, DEVICE_STATEFUL_PATH
Jon Salzff88c022012-11-03 12:19:58 +080046from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080047from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080048
Tammo Spalink5c699832012-07-03 17:50:39 +080049
Tammo Spalink5c699832012-07-03 17:50:39 +080050# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
51# treat that specially (as a smoot exit, as opposed to the more
52# verbose output for generic Error).
53
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080054_global_gooftool = None
55_gooftool_lock = threading.Lock()
Tammo Spalink5c699832012-07-03 17:50:39 +080056
Ricky Lianga70a1202013-03-15 15:03:17 +080057def GetGooftool(options):
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080058 global _global_gooftool # pylint: disable=W0603
Ricky Lianga70a1202013-03-15 15:03:17 +080059
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080060 if _global_gooftool is None:
61 with _gooftool_lock:
62 if options.hwid_version == 2:
63 hwdb_path = getattr(options, 'hwdb_path', None)
64 component_db = (
65 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path
66 else None)
67 _global_gooftool = Gooftool(hwid_version=2, component_db=component_db)
68 elif options.hwid_version == 3:
69 board = getattr(options, 'board', None)
70 hwdb_path = getattr(options, 'hwdb_path', None)
71 _global_gooftool = Gooftool(hwid_version=3, board=board,
72 hwdb_path=hwdb_path)
73 else:
74 raise Error, 'Invalid HWID version: %r' % options.hwid_version
75
76 return _global_gooftool
Ricky Lianga70a1202013-03-15 15:03:17 +080077
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080078@Command('write_hwid',
79 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080080def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080081 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080082
Tammo Spalink95c43732012-07-25 15:57:14 -070083 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080084 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080085 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070086 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080087
88
Ricky Liang53390232013-03-08 15:37:57 +080089_board_cmd_arg = CmdArg(
90 '--board', metavar='BOARD',
91 default=None, help='Board name to test.')
92
Tammo Spalink8fab5312012-05-28 18:33:30 +080093_hwdb_path_cmd_arg = CmdArg(
94 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +080095 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +080096 help='Path to the HWID database.')
97
Tammo Spalink95c43732012-07-25 15:57:14 -070098_hwid_status_list_cmd_arg = CmdArg(
99 '--status', nargs='*', default=['supported'],
100 help='allow only HWIDs with these status values')
101
Jon Salzce124fb2012-10-02 17:42:03 +0800102_probe_results_cmd_arg = CmdArg(
103 '--probe_results', metavar='RESULTS.yaml',
Ricky Liangc662be32013-12-24 11:50:23 +0800104 help=('Output from "gooftool probe --include_vpd" (used instead of '
Jon Salzce124fb2012-10-02 17:42:03 +0800105 'probing this system).'))
106
Ricky Liang53390232013-03-08 15:37:57 +0800107_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +0800108 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +0800109 help='A dict of device info to use instead of fetching from shopfllor '
110 'server.')
111
Jon Salzce124fb2012-10-02 17:42:03 +0800112_hwid_cmd_arg = CmdArg(
113 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800114 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800115
Bernie Thompson3c11c872013-07-22 18:22:45 -0700116_rma_mode_cmd_arg = CmdArg(
117 '--rma_mode', action='store_true',
118 help='Enable RMA mode, do not check for deprecated components.')
Tammo Spalink95c43732012-07-25 15:57:14 -0700119
120@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800121 _hwdb_path_cmd_arg,
122 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700123 help='optional BOARD name, needed only if data is present '
124 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800125 CmdArg('--bom', metavar='BOM', help='BOM name'),
126 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800127 CmdArg('--optimistic', action='store_true',
128 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700129 CmdArg('--comps', nargs='*', default=[],
130 help='list of canonical component names'),
131 CmdArg('--missing', nargs='*', default=[],
132 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800133 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700134 help='consider only HWIDs within this list of status values'))
135def BestMatchHwids(options):
Ricky Liangc662be32013-12-24 11:50:23 +0800136 """Determine a list of possible HWIDs using provided args and probing.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800137
138 VOLATILE can always be determined by probing. To get a unique
139 result, VARIANT must be specified for all cases where the matching
140 BOM has more than one associated variant code, otherwise all HWID
141 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700142 alternatively be specified using the --stdin_comps argument, which
143 allows specifying a list of canonical names (one per line) on stdin,
144 one per line. Based on what is known from BOM and stdin_comps,
145 determine a list of components to probe for, and use those probe
146 results to resolve a list of matching HWIDs. If no boms,
147 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800148 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800149
150 Returns (on stdout): A list of HWIDs that match the available probe
151 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700152
153 Example:
154
155 // Three ways to specify a keyboard (assuming it is a variant component)
156 gooftool best_match_hwids --missing keyboard
157 gooftool best_match_hwids --variant A or
158 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800159 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800160
Tammo Spalink5c699832012-07-03 17:50:39 +0800161 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700162 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800163 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800164 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800165 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800166 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800167 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700168 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800169 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800170 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800171 device.VariantExists(options.variant)
172 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700173 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700174 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700175 % YamlWrite(sorted(
176 hwid_tool.ComponentSpecClasses(component_spec) &
177 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700178 component_spec = hwid_tool.CombineComponentSpecs(
179 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700180 if options.comps or options.missing:
181 map(comp_db.CompExists, options.comps)
182 map(comp_db.CompClassExists, options.missing)
183 extra_comp_spec = comp_db.CreateComponentSpec(
184 components=options.comps,
185 missing=options.missing)
186 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
187 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
188 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700189 % YamlWrite(sorted(
190 hwid_tool.ComponentSpecClasses(component_spec) &
191 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700192 component_spec = hwid_tool.CombineComponentSpecs(
193 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700194 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700195 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800196 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800197 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
198 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700199 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700200 'as inputs, and cannot be probed for:\n%s'
201 'This problem can often be addressed by specifying all of '
202 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800203 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700204 print 'probing for missing classes:'
205 print YamlWrite(list(missing_classes))
206 probe_results = Probe(target_comp_classes=list(missing_classes),
207 probe_volatile=False, probe_initial_config=False)
208 cooked_components = comp_db.MatchComponentProbeValues(
209 probe_results.found_probe_value_map)
210 if cooked_components.unmatched:
211 sys.exit('ERROR: some probed components are unrecognized:\n%s'
212 % YamlWrite(cooked_components.unmatched))
213 probed_comp_spec = comp_db.CreateComponentSpec(
214 components=cooked_components.matched,
215 missing=probe_results.missing_component_classes)
216 component_spec = hwid_tool.CombineComponentSpecs(
217 component_spec, probed_comp_spec)
218 print YamlWrite({'component data used for matching': {
219 'missing component classes': component_spec.classes_missing,
220 'found components': component_spec.components}})
221 component_data = hwid_tool.ComponentData(
222 extant_components=hwid_tool.ComponentSpecCompClassMap(
223 component_spec).keys(),
224 classes_missing=component_spec.classes_missing)
225 match_tree = device.BuildMatchTree(component_data)
226 if not match_tree:
227 sys.exit('FAILURE: NO matching BOMs found')
228 print 'potential BOMs/VARIANTs:'
229 potential_variants = set()
230 potential_volatiles = set()
231 for bom_name, variant_tree in match_tree.items():
232 print ' BOM: %-8s VARIANTS: %s' % (
233 bom_name, ', '.join(sorted(variant_tree)))
234 for variant_code in variant_tree:
235 potential_variants.add(variant_code)
236 for volatile_code in device.volatiles:
237 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
238 if status in options.status:
239 potential_volatiles.add(volatile_code)
240 print ''
241 if len(potential_variants) == 0:
242 sys.exit('FAILURE: no matching VARIANTs found')
243 if len(potential_volatiles) == 0:
244 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
245 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700246 if (options.optimistic and
247 len(match_tree) == 1 and
248 len(potential_variants) == 1 and
249 len(potential_volatiles) == 1):
250 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
251 potential_variants.pop(),
252 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800253 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700254 print ('probing VOLATILEs to resolve potential matches: %s\n' %
255 ', '.join(sorted(potential_volatiles)))
256 vol_probe_results = Probe(
257 target_comp_classes=[],
258 probe_volatile=True,
259 probe_initial_config=False)
260 cooked_volatiles = device.MatchVolatileValues(
261 vol_probe_results.found_volatile_values)
262 match_tree = device.BuildMatchTree(
263 component_data, cooked_volatiles.matched_tags)
264 matched_hwids = device.GetMatchTreeHwids(match_tree)
265 if matched_hwids:
266 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800267 if matched_hwids[hwid] in options.status:
268 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700269 return
270 print 'exact HWID matching failed, but the following BOMs match: %s' % (
271 ', '.join(sorted(match_tree)))
272 if options.optimistic and len(match_tree) == 1:
273 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800274 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700275 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800276 if len(variant_matches) == 1:
277 var_code = set(variant_matches).pop()
278 elif len(bom.variants) == 1:
279 var_code = set(bom.variants).pop()
280 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700281 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
282 'because there were too many variants to choose from for BOM %r'
283 % bom_name)
284 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
285 for vol_code in device.volatiles
286 if device.GetHwidStatus(bom_name, var_code, vol_code)
287 in options.status]
288 for hwid in hwids:
289 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800290 return
291 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700292 print ('optimistic matching not attempted because either it was '
293 'not requested, or because the number of BOMs was <> 1\n')
294 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800295
296
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800297@Command('probe',
298 CmdArg('--comps', nargs='*',
299 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800300 CmdArg('--fast_fw_probe', action='store_true',
301 help='Do a fast probe for EC and main firmware versions only. '
302 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800303 CmdArg('--no_vol', action='store_true',
304 help='Do not probe volatile data.'),
305 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800306 help='Do not probe initial_config data.'),
307 CmdArg('--include_vpd', action='store_true',
308 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800309def RunProbe(options):
310 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800311 print GetGooftool(options).Probe(
312 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800313 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800314 probe_volatile=not options.no_vol,
315 probe_initial_config=not options.no_ic,
316 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800317
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800318
Tammo Spalink214caf42012-05-28 10:45:00 +0800319@Command('verify_components',
320 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800321 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800322def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800323 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800324
Tammo Spalink5c699832012-07-03 17:50:39 +0800325 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800326 that a corresponding match exists in the component_db -- make sure
327 that these components are present, that they have been approved, but
328 do not check against any specific BOM/HWID configurations.
329 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800330
Andy Chengc531e2f2012-10-15 19:09:17 +0800331 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800332 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800333 options.target_comps)
334 except ValueError, e:
335 sys.exit(e)
336
Ricky Liang53390232013-03-08 15:37:57 +0800337 PrintVerifyComponentsResults(result)
338
339
340def PrintVerifyComponentsResults(result):
341 """Prints out the results of VerifyComponents method call.
342
343 Groups the results into two groups: 'matches' and 'errors', and prints out
344 their values.
345 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800346 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800347 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800348 errors = []
349 for result_list in result.values():
350 for component_name, _, error in result_list:
351 if component_name:
352 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800353 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800354 errors.append(error)
355
Andy Cheng228a8c92012-08-27 10:53:57 +0800356 if matches:
357 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800358 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800359 print '\nerrors:\n %s' % '\n '.join(errors)
360 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800361 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800362 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800363
364
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800365@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700366 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800367 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800368 _probe_results_cmd_arg,
369 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800370def VerifyHwid(options):
371 """Verify system HWID properties match probed device properties.
372
373 First probe components, volatile and initial_config parameters for
374 the DUT. Then use the available device data to produce a list of
375 candidate HWIDs. Then verify the HWID from the DUT is present in
376 that list. Then verify that the DUT initial config values match
377 those specified for its HWID. Finally, verify that VPD contains all
378 the necessary fields as specified by the board data, and when
379 possible verify that values are legitimate.
380 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800381
Ricky Liangf7857c12012-09-17 13:34:41 +0800382 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800383 for key in ro_vpd_keys:
384 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800385 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700386 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800387 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800388 if (known_valid_values is not None) and (value not in known_valid_values):
389 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800390 for key in rw_vpd_keys:
391 if key not in rw_vpd:
392 sys.exit('Missing required RW VPD field: %s' % key)
393 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
394 value = rw_vpd[key]
395 if (known_valid_values is not None) and (value not in known_valid_values):
396 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800397 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800398 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800399
Jon Salz81350812012-10-11 16:13:22 +0800400 if not options.hwid or not options.probe_results:
401 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800402
403 if options.hwid:
404 hwid_str = options.hwid
405 else:
406 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
407 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700408 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800409 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800410 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700411 device = hw_db.GetDevice(hwid.board)
412 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
413 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800414 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800415 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800416 if options.probe_results:
417 # Pull in probe results (including VPD data) from the given file
418 # rather than probing the current system.
419 probe_results = hwid_tool.ProbeResults.Decode(
420 open(options.probe_results).read())
421 ro_vpd = {}
422 rw_vpd = {}
423 for k, v in probe_results.found_volatile_values.items():
424 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
425 if match:
426 del probe_results.found_volatile_values[k]
427 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
428 else:
429 probe_results = Probe()
430 ro_vpd = ReadRoVpd(main_fw_file)
431 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700432 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
433 probe_results.found_probe_value_map)
434 cooked_volatiles = device.MatchVolatileValues(
435 probe_results.found_volatile_values)
436 cooked_initial_configs = device.MatchInitialConfigValues(
437 probe_results.initial_configs)
438 component_data = hwid_tool.ComponentData(
439 extant_components=cooked_components.matched,
440 classes_missing=probe_results.missing_component_classes)
441 match_tree = device.BuildMatchTree(
442 component_data, cooked_volatiles.matched_tags)
443 matched_hwids = device.GetMatchTreeHwids(match_tree)
444 print 'HWID status: %s\n' % hwid_status
445 print 'probed system components:'
446 print YamlWrite(cooked_components.__dict__)
447 print 'missing component classes:'
448 print YamlWrite(probe_results.missing_component_classes)
449 print 'probed volatiles:'
450 print YamlWrite(cooked_volatiles.__dict__)
451 print 'probed initial_configs:'
452 print YamlWrite(cooked_initial_configs)
453 print 'hwid match tree:'
454 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800455 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800456 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700457 found_components=cooked_components.__dict__,
458 missing_component_classes=probe_results.missing_component_classes,
459 volatiles=cooked_volatiles.__dict__,
460 initial_configs=cooked_initial_configs)
461 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800462 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700463 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800464 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700465 YamlWrite(cooked_components.unmatched))
466 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800467 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700468 component_data.Encode())
469 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800470 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700471 (', '.join(sorted(match_tree)), hwid.bom))
472 err_msg += 'target bom %r matches components' % hwid.bom
473 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
474 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800475 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700476 matched_variants = match_tree.get(hwid.bom, {})
477 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800478 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700479 hwid.variant)
480 matched_volatiles = matched_variants.get(hwid.variant, {})
481 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800482 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700483 hwid.volatile)
484 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800485 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800486 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800487 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700488 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800489
490
491@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700492def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800493 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800494
Ricky Lianga70a1202013-03-15 15:03:17 +0800495 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496
497
498@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700499def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800500 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800501
Ricky Lianga70a1202013-03-15 15:03:17 +0800502 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800503 logging.info('Firmware bitmap initial locale set to %d (%s).',
504 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800505
506
507@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700508def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800509 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800510
Ricky Lianga70a1202013-03-15 15:03:17 +0800511 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800512
513
514@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700515def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800516 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800517
Ricky Lianga70a1202013-03-15 15:03:17 +0800518 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800519
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800520@Command('verify_tpm')
521def VerifyTPM(options): # pylint: disable=W0613
522 """Verify TPM is cleared."""
523
524 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800525
526@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800527def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800528 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800529
Ricky Lianga70a1202013-03-15 15:03:17 +0800530 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800531
532
533@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700534def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800535 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800536
Ricky Lianga70a1202013-03-15 15:03:17 +0800537 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800538 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800539 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800540
541
542@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700543def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800544 """Enable then verify firmware write protection."""
545
Hung-Te Linb21c6682012-08-01 13:53:57 +0800546 def CalculateLegacyRange(fw_type, length, section_data,
547 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800548 ro_size = length / 2
549 ro_a = int(section_data[0] / ro_size)
550 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
551 if ro_a != ro_b:
552 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800553 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800554 ro_offset = ro_a * ro_size
555 return (ro_offset, ro_size)
556
557 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800558 """Calculate protection size, then invoke flashrom.
559
560 Our supported chips only allow write protecting half their total
561 size, so we parition the flash chipset space accordingly.
562 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800563
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800564 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800565 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800566 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800567 if image.has_section(wp_section):
568 section_data = image.get_section_area(wp_section)
569 ro_offset = section_data[0]
570 ro_size = section_data[1]
571 elif image.has_section(legacy_section):
572 section_data = image.get_section_area(legacy_section)
573 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800574 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800575 else:
576 raise Error('could not find %s firmware section %s or %s' %
577 (fw_type, wp_section, legacy_section))
578
579 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
580 ro_offset, ro_size)
581 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800582
583 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800584 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800585 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
586 if ec_fw_file is not None:
587 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800588 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800589 else:
590 logging.warning('EC not write protected (seems there is no EC flash).')
591
592
593@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800594def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800595 """Zero out the GBB flags, in preparation for transition to release state.
596
597 No GBB flags are set in release/shipping state, but they are useful
598 for factory/development. See "gbb_utility --flags" for details.
599 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800600
Ricky Lianga70a1202013-03-15 15:03:17 +0800601 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800602 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800603
604
Jon Salzaa3a30e2013-05-15 15:56:28 +0800605@Command('clear_factory_vpd_entries')
606def ClearFactoryVPDEntries(options): # pylint: disable=W0613
607 """Clears factory.* items in the RW VPD."""
608 entries = GetGooftool(options).ClearFactoryVPDEntries()
609 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
610
611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800612@Command('prepare_wipe',
613 CmdArg('--fast', action='store_true',
614 help='use non-secure but faster wipe method.'))
615def PrepareWipe(options):
616 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800617
Ricky Lianga70a1202013-03-15 15:03:17 +0800618 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800619
620@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800621 CmdArg('--no_write_protect', action='store_true',
622 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700623 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800624 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800625 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800626 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800627 _hwid_cmd_arg,
628 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800629def Verify(options):
630 """Verifies if whole factory process is ready for finalization.
631
632 This routine performs all the necessary checks to make sure the
633 device is ready to be finalized, but does not modify state. These
634 checks include dev switch, firmware write protection switch, hwid,
635 system time, keys, and root file system.
636 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800637
Hung-Te Lin6d827542012-07-19 11:50:41 +0800638 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800639 VerifyWPSwitch(options)
640 VerifyDevSwitch(options)
641 if options.hwid_version == 2:
642 VerifyHwid(options)
643 elif options.hwid_version == 3:
Ricky Liangc662be32013-12-24 11:50:23 +0800644 VerifyHWIDv3(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800645 else:
646 raise Error, 'Invalid HWID version: %r' % options.hwid_version
647 VerifySystemTime(options)
648 VerifyKeys(options)
649 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800650 VerifyTPM(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800651
Jon Salzfe9036f2014-01-16 14:11:23 +0800652@Command('untar_stateful_files')
653def UntarStatefulFiles(dummy_options):
654 """Untars stateful files from stateful_files.tar.xz on stateful partition.
655
656 If that file does not exist (which should only be R30 and earlier),
657 this is a no-op.
658 """
659 tar_file = os.path.join(DEVICE_STATEFUL_PATH, 'stateful_files.tar.xz')
660 if os.path.exists(tar_file):
661 Spawn(['tar', 'xf', tar_file], cwd=DEVICE_STATEFUL_PATH,
662 log=True, check_call=True)
663 else:
664 logging.warning('No stateful files at %s', tar_file)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800665
Tammo Spalink86a61c62012-05-25 15:10:35 +0800666@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700667def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800668 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800669
Andy Cheng0465d132013-03-20 12:12:06 +0800670 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800671 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800672
673
Jon Salza88b83b2013-05-27 20:00:35 +0800674def CreateReportArchiveBlob(*args, **kwargs):
675 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800676
Jon Salza88b83b2013-05-27 20:00:35 +0800677 Args:
678 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800679
Jon Salza88b83b2013-05-27 20:00:35 +0800680 Returns:
681 An xmlrpclib.Binary object containing a .tar.xz file.
682 """
683 with open(CreateReportArchive(*args, **kwargs)) as f:
684 return xmlrpclib.Binary(f.read())
685
686
687def CreateReportArchive(device_sn=None, add_file=None):
688 """Creates a report archive in a temporary directory.
689
690 Args:
691 device_sn: The device serial number (optional).
692 add_file: A list of files to add (optional).
693
694 Returns:
695 Path to the archive.
696 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800697 def NormalizeAsFileName(token):
698 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800699
700 target_name = '%s%s.tar.xz' % (
701 time.strftime('%Y%m%dT%H%M%SZ',
702 time.gmtime()),
703 ("" if device_sn is None else
704 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800705 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800706
Tammo Spalink86a61c62012-05-25 15:10:35 +0800707 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800708 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800709 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800710 if add_file:
711 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800712 # Require absolute paths since the tar command may change the
713 # directory.
714 if not f.startswith('/'):
715 raise Error('Not an absolute path: %s' % f)
716 if not os.path.exists(f):
717 raise Error('File does not exist: %s' % f)
718 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800719 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800720
721 if ((cmd_result.status == 1) and
722 all((x == '' or
723 'file changed as we read it' in x or
724 "Removing leading `/' from member names" in x)
725 for x in cmd_result.stderr.split('\n'))):
726 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800727 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800728 ignore_stdout=True)
729 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800730 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
731 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800732
Jon Salza88b83b2013-05-27 20:00:35 +0800733 return target_path
734
735_upload_method_cmd_arg = CmdArg(
736 '--upload_method', metavar='METHOD:PARAM',
737 help=('How to perform the upload. METHOD should be one of '
738 '{ftp, shopfloor, ftps, cpfe}.'))
739_add_file_cmd_arg = CmdArg(
740 '--add_file', metavar='FILE', action='append',
741 help='Extra file to include in report (must be an absolute path)')
742
743@Command('upload_report',
744 _upload_method_cmd_arg,
745 _add_file_cmd_arg)
746def UploadReport(options):
747 """Create a report containing key device details."""
748 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
749 device_sn = ro_vpd.get('serial_number', None)
750 if device_sn is None:
751 logging.warning('RO_VPD missing device serial number')
752 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
753 target_path = CreateReportArchive(device_sn)
754
Tammo Spalink86a61c62012-05-25 15:10:35 +0800755 if options.upload_method is None or options.upload_method == 'none':
756 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
757 return
758 method, param = options.upload_method.split(':', 1)
759 if method == 'shopfloor':
760 report_upload.ShopFloorUpload(target_path, param)
761 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700762 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800763 elif method == 'ftps':
764 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
765 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800766 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800767 else:
768 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800769
770
771@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800772 CmdArg('--no_write_protect', action='store_true',
773 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800774 CmdArg('--fast', action='store_true',
775 help='use non-secure but faster wipe method.'),
776 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700777 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800778 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800779 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800780 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800781 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800782 _hwid_cmd_arg,
783 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800784def Finalize(options):
785 """Verify system readiness and trigger transition into release state.
786
Jon Salzaa3a30e2013-05-15 15:56:28 +0800787 This routine does the following:
788 - Verifies system state (see verify command)
Jon Salzfe9036f2014-01-16 14:11:23 +0800789 - Untars stateful_files.tar.xz, if it exists, in the stateful partition, to
790 initialize files such as the CRX cache
Jon Salzaa3a30e2013-05-15 15:56:28 +0800791 - Modifies firmware bitmaps to match locale
792 - Clears all factory-friendly flags from the GBB
793 - Removes factory-specific entries from RW_VPD (factory.*)
794 - Enables firmware write protection (cannot rollback after this)
795 - Uploads system logs & reports
796 - Sets the necessary boot flags to cause wipe of the factory image on the
797 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800798 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800799 Verify(options)
Jon Salzfe9036f2014-01-16 14:11:23 +0800800 UntarStatefulFiles(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800801 SetFirmwareBitmapLocale(options)
802 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800803 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800804 if options.no_write_protect:
805 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800806 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800807 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800808 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800809 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800810 UploadReport(options)
811 PrepareWipe(options)
812
813
Ricky Liangc662be32013-12-24 11:50:23 +0800814def VerifyHWIDv3(options):
815 """A simple wrapper that calls out to HWID utils to verify version 3 HWID.
Ricky Liang53390232013-03-08 15:37:57 +0800816
Ricky Liangc662be32013-12-24 11:50:23 +0800817 This is mainly for Gooftool to verify v3 HWID during finalize. For testing
818 and development purposes, please use `hwid` command.
Ricky Liang53390232013-03-08 15:37:57 +0800819 """
Ricky Liangc662be32013-12-24 11:50:23 +0800820 db = GetGooftool(options).db
821 encoded_string = options.hwid or hwid_utils.GetHWIDString()
Ricky Liang7905f272013-03-16 01:57:10 +0800822 if options.probe_results:
Ricky Liangc662be32013-12-24 11:50:23 +0800823 probed_results = yaml.load(open(options.probe_results).read())
Ricky Liang7905f272013-03-16 01:57:10 +0800824 else:
Ricky Liangc662be32013-12-24 11:50:23 +0800825 probed_results = yaml.load(Probe(probe_vpd=True).Encode())
826 vpd = hwid_utils.GetVPD(probed_results)
Ricky Liang53390232013-03-08 15:37:57 +0800827
Ricky Liangc662be32013-12-24 11:50:23 +0800828 event_log.Log('probed_results', probed_results=probed_results)
829 event_log.Log('vpd', vpd=vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800830
Ricky Liangc662be32013-12-24 11:50:23 +0800831 hwid_utils.VerifyHWID(db, encoded_string, probed_results, vpd,
832 rma_mode=options.rma_mode)
Ricky Liang53390232013-03-08 15:37:57 +0800833
Ricky Liangc662be32013-12-24 11:50:23 +0800834 event_log.Log('verified_hwid', hwid=encoded_string)
Ricky Liang53390232013-03-08 15:37:57 +0800835
836
Ricky Liang59611a62013-06-11 13:47:33 +0800837def ParseDecodedHWID(hwid):
838 """Parse the HWID object into a more compact dict.
839
840 Args:
841 hwid: A decoded HWID object.
842
843 Returns:
844 A dict containing the board name, the binary string, and the list of
845 components.
846 """
847 results = {}
848 results['board'] = hwid.database.board
849 results['binary_string'] = hwid.binary_string
850 results['components'] = collections.defaultdict(list)
851 components = hwid.bom.components
852 for comp_cls in sorted(components):
853 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
854 if not probed_values:
855 db_components = hwid.database.components
856 probed_values = db_components.GetComponentAttributes(
857 comp_cls, comp_name).get('values')
858 results['components'][comp_cls].append(
859 {comp_name: probed_values if probed_values else None})
860 # Convert defaultdict to dict.
861 results['components'] = dict(results['components'])
862 return results
863
864
henryhsu44d793a2013-07-20 00:07:38 +0800865@Command('get_firmware_hash',
866 CmdArg('--file', metavar='FILE', help='Firmware File.'))
867def GetFirmwareHash(options):
henryhsuf6f835c2013-07-20 20:49:25 +0800868 """Get firmware hash from a file"""
henryhsu44d793a2013-07-20 00:07:38 +0800869 if os.path.exists(options.file):
870 hashes = CalculateFirmwareHashes(options.file)
871 for section, value_dict in hashes.iteritems():
872 print "%s:" % section
873 for key, value in value_dict.iteritems():
874 print " %s: %s" % (key, value)
875 else:
876 raise Error('File does not exist: %s' % options.file)
877
henryhsuf6f835c2013-07-20 20:49:25 +0800878
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800879def Main():
880 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800881
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800882 options = ParseCmdline(
Ricky Liangc662be32013-12-24 11:50:23 +0800883 ('Perform Google required factory tests. All the HWID-related functions '
884 'provided here are mainly for the deprecated HWID v2. To access HWID '
885 'v3-related utilities, please use `hwid` command.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800886 CmdArg('-l', '--log', metavar='PATH',
887 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800888 CmdArg('--suppress-event-logs', action='store_true',
889 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800890 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800891 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800892 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800893 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800894 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
895 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800896 logging.debug('gooftool options: %s', repr(options))
897 try:
898 logging.debug('GOOFTOOL command %r', options.command_name)
899 options.command(options)
900 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
901 except Error, e:
902 logging.exception(e)
903 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
904 except Exception, e:
905 logging.exception(e)
906 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
907
908
909if __name__ == '__main__':
910 Main()