blob: 674c73a65e9b9667b4a4a3e934d1bf38b325a1b5 [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:
Ricky Liang43b879b2014-02-24 11:36:55 +080062 hwid_version = getattr(options, 'hwid_version', 3)
63 if hwid_version == 2:
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080064 hwdb_path = getattr(options, 'hwdb_path', None)
65 component_db = (
66 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path
67 else None)
68 _global_gooftool = Gooftool(hwid_version=2, component_db=component_db)
Ricky Liang43b879b2014-02-24 11:36:55 +080069 elif hwid_version == 3:
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080070 board = getattr(options, 'board', None)
71 hwdb_path = getattr(options, 'hwdb_path', None)
72 _global_gooftool = Gooftool(hwid_version=3, board=board,
73 hwdb_path=hwdb_path)
74 else:
75 raise Error, 'Invalid HWID version: %r' % options.hwid_version
76
77 return _global_gooftool
Ricky Lianga70a1202013-03-15 15:03:17 +080078
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080079@Command('write_hwid',
80 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080081def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080082 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080083
Tammo Spalink95c43732012-07-25 15:57:14 -070084 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080085 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080086 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070087 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080088
89
Ricky Liang53390232013-03-08 15:37:57 +080090_board_cmd_arg = CmdArg(
91 '--board', metavar='BOARD',
92 default=None, help='Board name to test.')
93
Tammo Spalink8fab5312012-05-28 18:33:30 +080094_hwdb_path_cmd_arg = CmdArg(
95 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +080096 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +080097 help='Path to the HWID database.')
98
Tammo Spalink95c43732012-07-25 15:57:14 -070099_hwid_status_list_cmd_arg = CmdArg(
100 '--status', nargs='*', default=['supported'],
101 help='allow only HWIDs with these status values')
102
Jon Salzce124fb2012-10-02 17:42:03 +0800103_probe_results_cmd_arg = CmdArg(
104 '--probe_results', metavar='RESULTS.yaml',
Ricky Liangc662be32013-12-24 11:50:23 +0800105 help=('Output from "gooftool probe --include_vpd" (used instead of '
Jon Salzce124fb2012-10-02 17:42:03 +0800106 'probing this system).'))
107
Ricky Liang53390232013-03-08 15:37:57 +0800108_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +0800109 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +0800110 help='A dict of device info to use instead of fetching from shopfllor '
111 'server.')
112
Jon Salzce124fb2012-10-02 17:42:03 +0800113_hwid_cmd_arg = CmdArg(
114 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800115 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800116
Bernie Thompson3c11c872013-07-22 18:22:45 -0700117_rma_mode_cmd_arg = CmdArg(
118 '--rma_mode', action='store_true',
119 help='Enable RMA mode, do not check for deprecated components.')
Tammo Spalink95c43732012-07-25 15:57:14 -0700120
Ricky Liang43b879b2014-02-24 11:36:55 +0800121_hwid_version_cmd_arg = CmdArg(
122 '-i', '--hwid-version', default=3, choices=(2, 3), type=int,
123 help='Version of HWID to operate on. (default: %(default)s)')
124
125
Tammo Spalink95c43732012-07-25 15:57:14 -0700126@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800127 _hwdb_path_cmd_arg,
128 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700129 help='optional BOARD name, needed only if data is present '
130 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800131 CmdArg('--bom', metavar='BOM', help='BOM name'),
132 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800133 CmdArg('--optimistic', action='store_true',
134 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700135 CmdArg('--comps', nargs='*', default=[],
136 help='list of canonical component names'),
137 CmdArg('--missing', nargs='*', default=[],
138 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800139 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700140 help='consider only HWIDs within this list of status values'))
141def BestMatchHwids(options):
Ricky Liangc662be32013-12-24 11:50:23 +0800142 """Determine a list of possible HWIDs using provided args and probing.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800143
144 VOLATILE can always be determined by probing. To get a unique
145 result, VARIANT must be specified for all cases where the matching
146 BOM has more than one associated variant code, otherwise all HWID
147 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700148 alternatively be specified using the --stdin_comps argument, which
149 allows specifying a list of canonical names (one per line) on stdin,
150 one per line. Based on what is known from BOM and stdin_comps,
151 determine a list of components to probe for, and use those probe
152 results to resolve a list of matching HWIDs. If no boms,
153 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800154 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800155
156 Returns (on stdout): A list of HWIDs that match the available probe
157 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700158
159 Example:
160
161 // Three ways to specify a keyboard (assuming it is a variant component)
162 gooftool best_match_hwids --missing keyboard
163 gooftool best_match_hwids --variant A or
164 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800165 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800166
Tammo Spalink5c699832012-07-03 17:50:39 +0800167 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700168 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800169 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800170 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800171 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800172 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800173 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700174 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800175 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800176 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800177 device.VariantExists(options.variant)
178 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700179 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700180 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700181 % YamlWrite(sorted(
182 hwid_tool.ComponentSpecClasses(component_spec) &
183 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700184 component_spec = hwid_tool.CombineComponentSpecs(
185 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700186 if options.comps or options.missing:
187 map(comp_db.CompExists, options.comps)
188 map(comp_db.CompClassExists, options.missing)
189 extra_comp_spec = comp_db.CreateComponentSpec(
190 components=options.comps,
191 missing=options.missing)
192 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
193 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
194 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700195 % YamlWrite(sorted(
196 hwid_tool.ComponentSpecClasses(component_spec) &
197 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700198 component_spec = hwid_tool.CombineComponentSpecs(
199 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700200 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700201 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800202 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800203 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
204 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700205 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700206 'as inputs, and cannot be probed for:\n%s'
207 'This problem can often be addressed by specifying all of '
208 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800209 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700210 print 'probing for missing classes:'
211 print YamlWrite(list(missing_classes))
212 probe_results = Probe(target_comp_classes=list(missing_classes),
213 probe_volatile=False, probe_initial_config=False)
214 cooked_components = comp_db.MatchComponentProbeValues(
215 probe_results.found_probe_value_map)
216 if cooked_components.unmatched:
217 sys.exit('ERROR: some probed components are unrecognized:\n%s'
218 % YamlWrite(cooked_components.unmatched))
219 probed_comp_spec = comp_db.CreateComponentSpec(
220 components=cooked_components.matched,
221 missing=probe_results.missing_component_classes)
222 component_spec = hwid_tool.CombineComponentSpecs(
223 component_spec, probed_comp_spec)
224 print YamlWrite({'component data used for matching': {
225 'missing component classes': component_spec.classes_missing,
226 'found components': component_spec.components}})
227 component_data = hwid_tool.ComponentData(
228 extant_components=hwid_tool.ComponentSpecCompClassMap(
229 component_spec).keys(),
230 classes_missing=component_spec.classes_missing)
231 match_tree = device.BuildMatchTree(component_data)
232 if not match_tree:
233 sys.exit('FAILURE: NO matching BOMs found')
234 print 'potential BOMs/VARIANTs:'
235 potential_variants = set()
236 potential_volatiles = set()
237 for bom_name, variant_tree in match_tree.items():
238 print ' BOM: %-8s VARIANTS: %s' % (
239 bom_name, ', '.join(sorted(variant_tree)))
240 for variant_code in variant_tree:
241 potential_variants.add(variant_code)
242 for volatile_code in device.volatiles:
243 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
244 if status in options.status:
245 potential_volatiles.add(volatile_code)
246 print ''
247 if len(potential_variants) == 0:
248 sys.exit('FAILURE: no matching VARIANTs found')
249 if len(potential_volatiles) == 0:
250 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
251 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700252 if (options.optimistic and
253 len(match_tree) == 1 and
254 len(potential_variants) == 1 and
255 len(potential_volatiles) == 1):
256 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
257 potential_variants.pop(),
258 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800259 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700260 print ('probing VOLATILEs to resolve potential matches: %s\n' %
261 ', '.join(sorted(potential_volatiles)))
262 vol_probe_results = Probe(
263 target_comp_classes=[],
264 probe_volatile=True,
265 probe_initial_config=False)
266 cooked_volatiles = device.MatchVolatileValues(
267 vol_probe_results.found_volatile_values)
268 match_tree = device.BuildMatchTree(
269 component_data, cooked_volatiles.matched_tags)
270 matched_hwids = device.GetMatchTreeHwids(match_tree)
271 if matched_hwids:
272 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800273 if matched_hwids[hwid] in options.status:
274 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700275 return
276 print 'exact HWID matching failed, but the following BOMs match: %s' % (
277 ', '.join(sorted(match_tree)))
278 if options.optimistic and len(match_tree) == 1:
279 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800280 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700281 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800282 if len(variant_matches) == 1:
283 var_code = set(variant_matches).pop()
284 elif len(bom.variants) == 1:
285 var_code = set(bom.variants).pop()
286 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700287 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
288 'because there were too many variants to choose from for BOM %r'
289 % bom_name)
290 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
291 for vol_code in device.volatiles
292 if device.GetHwidStatus(bom_name, var_code, vol_code)
293 in options.status]
294 for hwid in hwids:
295 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800296 return
297 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700298 print ('optimistic matching not attempted because either it was '
299 'not requested, or because the number of BOMs was <> 1\n')
300 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800301
302
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800303@Command('probe',
304 CmdArg('--comps', nargs='*',
305 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800306 CmdArg('--fast_fw_probe', action='store_true',
307 help='Do a fast probe for EC and main firmware versions only. '
308 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800309 CmdArg('--no_vol', action='store_true',
310 help='Do not probe volatile data.'),
311 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800312 help='Do not probe initial_config data.'),
313 CmdArg('--include_vpd', action='store_true',
314 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800315def RunProbe(options):
316 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800317 print GetGooftool(options).Probe(
318 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800319 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800320 probe_volatile=not options.no_vol,
321 probe_initial_config=not options.no_ic,
322 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800323
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800324
Tammo Spalink214caf42012-05-28 10:45:00 +0800325@Command('verify_components',
326 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800327 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800328def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800329 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800330
Tammo Spalink5c699832012-07-03 17:50:39 +0800331 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800332 that a corresponding match exists in the component_db -- make sure
333 that these components are present, that they have been approved, but
334 do not check against any specific BOM/HWID configurations.
335 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800336
Andy Chengc531e2f2012-10-15 19:09:17 +0800337 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800338 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800339 options.target_comps)
340 except ValueError, e:
341 sys.exit(e)
342
Ricky Liang53390232013-03-08 15:37:57 +0800343 PrintVerifyComponentsResults(result)
344
345
346def PrintVerifyComponentsResults(result):
347 """Prints out the results of VerifyComponents method call.
348
349 Groups the results into two groups: 'matches' and 'errors', and prints out
350 their values.
351 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800352 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800353 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800354 errors = []
355 for result_list in result.values():
356 for component_name, _, error in result_list:
357 if component_name:
358 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800359 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800360 errors.append(error)
361
Andy Cheng228a8c92012-08-27 10:53:57 +0800362 if matches:
363 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800364 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800365 print '\nerrors:\n %s' % '\n '.join(errors)
366 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800367 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800368 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800369
370
Ricky Liang43b879b2014-02-24 11:36:55 +0800371@Command('verify_hwid_v2',
Tammo Spalink95c43732012-07-25 15:57:14 -0700372 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800373 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800374 _probe_results_cmd_arg,
375 _hwid_cmd_arg)
Ricky Liang43b879b2014-02-24 11:36:55 +0800376def VerifyHWIDv2(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800377 """Verify system HWID properties match probed device properties.
378
379 First probe components, volatile and initial_config parameters for
380 the DUT. Then use the available device data to produce a list of
381 candidate HWIDs. Then verify the HWID from the DUT is present in
382 that list. Then verify that the DUT initial config values match
383 those specified for its HWID. Finally, verify that VPD contains all
384 the necessary fields as specified by the board data, and when
385 possible verify that values are legitimate.
386 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800387 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800388 for key in ro_vpd_keys:
389 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800390 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700391 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800392 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800393 if (known_valid_values is not None) and (value not in known_valid_values):
394 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800395 for key in rw_vpd_keys:
396 if key not in rw_vpd:
397 sys.exit('Missing required RW VPD field: %s' % key)
398 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
399 value = rw_vpd[key]
400 if (known_valid_values is not None) and (value not in known_valid_values):
401 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800402 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800403 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800404
Jon Salz81350812012-10-11 16:13:22 +0800405 if not options.hwid or not options.probe_results:
406 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800407
408 if options.hwid:
409 hwid_str = options.hwid
410 else:
411 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
412 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700413 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800414 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800415 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700416 device = hw_db.GetDevice(hwid.board)
417 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
418 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800419 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800420 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800421 if options.probe_results:
422 # Pull in probe results (including VPD data) from the given file
423 # rather than probing the current system.
424 probe_results = hwid_tool.ProbeResults.Decode(
425 open(options.probe_results).read())
426 ro_vpd = {}
427 rw_vpd = {}
428 for k, v in probe_results.found_volatile_values.items():
429 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
430 if match:
431 del probe_results.found_volatile_values[k]
432 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
433 else:
434 probe_results = Probe()
435 ro_vpd = ReadRoVpd(main_fw_file)
436 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700437 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
438 probe_results.found_probe_value_map)
439 cooked_volatiles = device.MatchVolatileValues(
440 probe_results.found_volatile_values)
441 cooked_initial_configs = device.MatchInitialConfigValues(
442 probe_results.initial_configs)
443 component_data = hwid_tool.ComponentData(
444 extant_components=cooked_components.matched,
445 classes_missing=probe_results.missing_component_classes)
446 match_tree = device.BuildMatchTree(
447 component_data, cooked_volatiles.matched_tags)
448 matched_hwids = device.GetMatchTreeHwids(match_tree)
449 print 'HWID status: %s\n' % hwid_status
450 print 'probed system components:'
451 print YamlWrite(cooked_components.__dict__)
452 print 'missing component classes:'
453 print YamlWrite(probe_results.missing_component_classes)
454 print 'probed volatiles:'
455 print YamlWrite(cooked_volatiles.__dict__)
456 print 'probed initial_configs:'
457 print YamlWrite(cooked_initial_configs)
458 print 'hwid match tree:'
459 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800460 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800461 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700462 found_components=cooked_components.__dict__,
463 missing_component_classes=probe_results.missing_component_classes,
464 volatiles=cooked_volatiles.__dict__,
465 initial_configs=cooked_initial_configs)
466 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800467 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700468 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800469 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700470 YamlWrite(cooked_components.unmatched))
471 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800472 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700473 component_data.Encode())
474 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800475 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700476 (', '.join(sorted(match_tree)), hwid.bom))
477 err_msg += 'target bom %r matches components' % hwid.bom
478 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
479 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800480 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700481 matched_variants = match_tree.get(hwid.bom, {})
482 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800483 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700484 hwid.variant)
485 matched_volatiles = matched_variants.get(hwid.variant, {})
486 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800487 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700488 hwid.volatile)
489 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800490 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800491 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800492 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700493 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800494
495
496@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700497def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800498 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800499
Ricky Lianga70a1202013-03-15 15:03:17 +0800500 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800501
502
503@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700504def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800505 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800506
Ricky Lianga70a1202013-03-15 15:03:17 +0800507 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800508 logging.info('Firmware bitmap initial locale set to %d (%s).',
509 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800510
511
512@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700513def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800514 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800515
Ricky Lianga70a1202013-03-15 15:03:17 +0800516 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800517
518
519@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700520def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800521 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800522
Ricky Lianga70a1202013-03-15 15:03:17 +0800523 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800524
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800525@Command('verify_tpm')
526def VerifyTPM(options): # pylint: disable=W0613
527 """Verify TPM is cleared."""
528
529 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800530
531@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800532def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800533 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800534
Ricky Lianga70a1202013-03-15 15:03:17 +0800535 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800536
537
538@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700539def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800540 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800541
Ricky Lianga70a1202013-03-15 15:03:17 +0800542 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800543 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800544 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800545
546
Jon Salzadd90d32014-04-29 16:16:27 +0800547@Command('verify_branding')
548def VerifyBranding(options): # pylint: disable=W0613
549 """Verify that branding fields are properly set.
550
551 customization_id, if set in the RO VPD, must be of the correct format.
552
553 rlz_brand_code must be set either in the RO VPD or OEM partition, and must
554 be of the correct format.
555 """
556 return GetGooftool(options).VerifyBranding()
557
558
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800559@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700560def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800561 """Enable then verify firmware write protection."""
562
Hung-Te Linb21c6682012-08-01 13:53:57 +0800563 def CalculateLegacyRange(fw_type, length, section_data,
564 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800565 ro_size = length / 2
566 ro_a = int(section_data[0] / ro_size)
567 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
568 if ro_a != ro_b:
569 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800570 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800571 ro_offset = ro_a * ro_size
572 return (ro_offset, ro_size)
573
574 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800575 """Calculate protection size, then invoke flashrom.
576
577 Our supported chips only allow write protecting half their total
578 size, so we parition the flash chipset space accordingly.
579 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800580
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800581 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800582 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800583 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800584 if image.has_section(wp_section):
585 section_data = image.get_section_area(wp_section)
586 ro_offset = section_data[0]
587 ro_size = section_data[1]
588 elif image.has_section(legacy_section):
589 section_data = image.get_section_area(legacy_section)
590 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800591 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800592 else:
593 raise Error('could not find %s firmware section %s or %s' %
594 (fw_type, wp_section, legacy_section))
595
596 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
597 ro_offset, ro_size)
598 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800599
600 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800601 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800602 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
603 if ec_fw_file is not None:
604 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800605 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800606 else:
607 logging.warning('EC not write protected (seems there is no EC flash).')
608
609
610@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800611def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800612 """Zero out the GBB flags, in preparation for transition to release state.
613
614 No GBB flags are set in release/shipping state, but they are useful
615 for factory/development. See "gbb_utility --flags" for details.
616 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800617
Ricky Lianga70a1202013-03-15 15:03:17 +0800618 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800619 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800620
621
Jon Salzaa3a30e2013-05-15 15:56:28 +0800622@Command('clear_factory_vpd_entries')
623def ClearFactoryVPDEntries(options): # pylint: disable=W0613
624 """Clears factory.* items in the RW VPD."""
625 entries = GetGooftool(options).ClearFactoryVPDEntries()
626 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
627
628
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800629@Command('prepare_wipe',
630 CmdArg('--fast', action='store_true',
631 help='use non-secure but faster wipe method.'))
632def PrepareWipe(options):
633 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800634
Ricky Lianga70a1202013-03-15 15:03:17 +0800635 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800636
637@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800638 CmdArg('--no_write_protect', action='store_true',
639 help='Do not check write protection switch state.'),
Ricky Liang43b879b2014-02-24 11:36:55 +0800640 _hwid_version_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700641 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800642 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800643 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800644 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800645 _hwid_cmd_arg,
646 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800647def Verify(options):
648 """Verifies if whole factory process is ready for finalization.
649
650 This routine performs all the necessary checks to make sure the
651 device is ready to be finalized, but does not modify state. These
652 checks include dev switch, firmware write protection switch, hwid,
653 system time, keys, and root file system.
654 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800655
Hung-Te Lin6d827542012-07-19 11:50:41 +0800656 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800657 VerifyWPSwitch(options)
658 VerifyDevSwitch(options)
659 if options.hwid_version == 2:
Ricky Liang43b879b2014-02-24 11:36:55 +0800660 VerifyHWIDv2(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800661 elif options.hwid_version == 3:
Ricky Liangc662be32013-12-24 11:50:23 +0800662 VerifyHWIDv3(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800663 else:
664 raise Error, 'Invalid HWID version: %r' % options.hwid_version
665 VerifySystemTime(options)
666 VerifyKeys(options)
667 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800668 VerifyTPM(options)
Jon Salzadd90d32014-04-29 16:16:27 +0800669 VerifyBranding(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800670
Jon Salzfe9036f2014-01-16 14:11:23 +0800671@Command('untar_stateful_files')
Hung-Te Lin388bce22014-06-03 19:56:40 +0800672def UntarStatefulFiles(unused_options):
Jon Salzfe9036f2014-01-16 14:11:23 +0800673 """Untars stateful files from stateful_files.tar.xz on stateful partition.
674
675 If that file does not exist (which should only be R30 and earlier),
676 this is a no-op.
677 """
678 tar_file = os.path.join(DEVICE_STATEFUL_PATH, 'stateful_files.tar.xz')
679 if os.path.exists(tar_file):
680 Spawn(['tar', 'xf', tar_file], cwd=DEVICE_STATEFUL_PATH,
681 log=True, check_call=True)
682 else:
683 logging.warning('No stateful files at %s', tar_file)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800684
Tammo Spalink86a61c62012-05-25 15:10:35 +0800685@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700686def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800687 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800688
Ricky Liang43b879b2014-02-24 11:36:55 +0800689 event_log.Log('system_details', **GetGooftool(options).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800690
691
Jon Salza88b83b2013-05-27 20:00:35 +0800692def CreateReportArchiveBlob(*args, **kwargs):
693 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800694
Jon Salza88b83b2013-05-27 20:00:35 +0800695 Args:
696 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800697
Jon Salza88b83b2013-05-27 20:00:35 +0800698 Returns:
699 An xmlrpclib.Binary object containing a .tar.xz file.
700 """
701 with open(CreateReportArchive(*args, **kwargs)) as f:
702 return xmlrpclib.Binary(f.read())
703
704
705def CreateReportArchive(device_sn=None, add_file=None):
706 """Creates a report archive in a temporary directory.
707
708 Args:
709 device_sn: The device serial number (optional).
710 add_file: A list of files to add (optional).
711
712 Returns:
713 Path to the archive.
714 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800715 def NormalizeAsFileName(token):
716 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800717
718 target_name = '%s%s.tar.xz' % (
719 time.strftime('%Y%m%dT%H%M%SZ',
720 time.gmtime()),
721 ("" if device_sn is None else
722 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800723 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800724
Tammo Spalink86a61c62012-05-25 15:10:35 +0800725 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800726 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800727 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800728 if add_file:
729 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800730 # Require absolute paths since the tar command may change the
731 # directory.
732 if not f.startswith('/'):
733 raise Error('Not an absolute path: %s' % f)
734 if not os.path.exists(f):
735 raise Error('File does not exist: %s' % f)
736 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800737 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800738
739 if ((cmd_result.status == 1) and
740 all((x == '' or
741 'file changed as we read it' in x or
742 "Removing leading `/' from member names" in x)
743 for x in cmd_result.stderr.split('\n'))):
744 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800745 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800746 ignore_stdout=True)
747 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800748 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
749 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800750
Jon Salza88b83b2013-05-27 20:00:35 +0800751 return target_path
752
753_upload_method_cmd_arg = CmdArg(
754 '--upload_method', metavar='METHOD:PARAM',
755 help=('How to perform the upload. METHOD should be one of '
756 '{ftp, shopfloor, ftps, cpfe}.'))
757_add_file_cmd_arg = CmdArg(
758 '--add_file', metavar='FILE', action='append',
759 help='Extra file to include in report (must be an absolute path)')
760
761@Command('upload_report',
762 _upload_method_cmd_arg,
763 _add_file_cmd_arg)
764def UploadReport(options):
765 """Create a report containing key device details."""
766 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
767 device_sn = ro_vpd.get('serial_number', None)
768 if device_sn is None:
769 logging.warning('RO_VPD missing device serial number')
770 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
771 target_path = CreateReportArchive(device_sn)
772
Tammo Spalink86a61c62012-05-25 15:10:35 +0800773 if options.upload_method is None or options.upload_method == 'none':
774 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
775 return
776 method, param = options.upload_method.split(':', 1)
777 if method == 'shopfloor':
778 report_upload.ShopFloorUpload(target_path, param)
779 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700780 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800781 elif method == 'ftps':
782 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
783 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800784 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800785 else:
786 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800787
788
789@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800790 CmdArg('--no_write_protect', action='store_true',
791 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800792 CmdArg('--fast', action='store_true',
793 help='use non-secure but faster wipe method.'),
Ricky Liang43b879b2014-02-24 11:36:55 +0800794 _hwid_version_cmd_arg,
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800795 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700796 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800797 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800798 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800799 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800800 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800801 _hwid_cmd_arg,
802 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800803def Finalize(options):
804 """Verify system readiness and trigger transition into release state.
805
Jon Salzaa3a30e2013-05-15 15:56:28 +0800806 This routine does the following:
807 - Verifies system state (see verify command)
Jon Salzfe9036f2014-01-16 14:11:23 +0800808 - Untars stateful_files.tar.xz, if it exists, in the stateful partition, to
809 initialize files such as the CRX cache
Jon Salzaa3a30e2013-05-15 15:56:28 +0800810 - Modifies firmware bitmaps to match locale
811 - Clears all factory-friendly flags from the GBB
812 - Removes factory-specific entries from RW_VPD (factory.*)
813 - Enables firmware write protection (cannot rollback after this)
814 - Uploads system logs & reports
815 - Sets the necessary boot flags to cause wipe of the factory image on the
816 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800817 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800818 Verify(options)
Jon Salzfe9036f2014-01-16 14:11:23 +0800819 UntarStatefulFiles(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800820 SetFirmwareBitmapLocale(options)
821 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800822 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800823 if options.no_write_protect:
824 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800825 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800826 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800827 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800828 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800829 UploadReport(options)
830 PrepareWipe(options)
831
832
Ricky Liangc662be32013-12-24 11:50:23 +0800833def VerifyHWIDv3(options):
834 """A simple wrapper that calls out to HWID utils to verify version 3 HWID.
Ricky Liang53390232013-03-08 15:37:57 +0800835
Ricky Liangc662be32013-12-24 11:50:23 +0800836 This is mainly for Gooftool to verify v3 HWID during finalize. For testing
837 and development purposes, please use `hwid` command.
Ricky Liang53390232013-03-08 15:37:57 +0800838 """
Ricky Liangc662be32013-12-24 11:50:23 +0800839 db = GetGooftool(options).db
840 encoded_string = options.hwid or hwid_utils.GetHWIDString()
Ricky Liang7905f272013-03-16 01:57:10 +0800841 if options.probe_results:
Ricky Liangc662be32013-12-24 11:50:23 +0800842 probed_results = yaml.load(open(options.probe_results).read())
Ricky Liang7905f272013-03-16 01:57:10 +0800843 else:
Ricky Liangc662be32013-12-24 11:50:23 +0800844 probed_results = yaml.load(Probe(probe_vpd=True).Encode())
845 vpd = hwid_utils.GetVPD(probed_results)
Ricky Liang53390232013-03-08 15:37:57 +0800846
Ricky Liangc662be32013-12-24 11:50:23 +0800847 event_log.Log('probed_results', probed_results=probed_results)
848 event_log.Log('vpd', vpd=vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800849
Ricky Liangc662be32013-12-24 11:50:23 +0800850 hwid_utils.VerifyHWID(db, encoded_string, probed_results, vpd,
851 rma_mode=options.rma_mode)
Ricky Liang53390232013-03-08 15:37:57 +0800852
Ricky Liangc662be32013-12-24 11:50:23 +0800853 event_log.Log('verified_hwid', hwid=encoded_string)
Ricky Liang53390232013-03-08 15:37:57 +0800854
855
Ricky Liang59611a62013-06-11 13:47:33 +0800856def ParseDecodedHWID(hwid):
857 """Parse the HWID object into a more compact dict.
858
859 Args:
860 hwid: A decoded HWID object.
861
862 Returns:
863 A dict containing the board name, the binary string, and the list of
864 components.
865 """
866 results = {}
867 results['board'] = hwid.database.board
868 results['binary_string'] = hwid.binary_string
869 results['components'] = collections.defaultdict(list)
870 components = hwid.bom.components
871 for comp_cls in sorted(components):
872 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
873 if not probed_values:
874 db_components = hwid.database.components
875 probed_values = db_components.GetComponentAttributes(
876 comp_cls, comp_name).get('values')
877 results['components'][comp_cls].append(
878 {comp_name: probed_values if probed_values else None})
879 # Convert defaultdict to dict.
880 results['components'] = dict(results['components'])
881 return results
882
883
henryhsu44d793a2013-07-20 00:07:38 +0800884@Command('get_firmware_hash',
885 CmdArg('--file', metavar='FILE', help='Firmware File.'))
886def GetFirmwareHash(options):
henryhsuf6f835c2013-07-20 20:49:25 +0800887 """Get firmware hash from a file"""
henryhsu44d793a2013-07-20 00:07:38 +0800888 if os.path.exists(options.file):
889 hashes = CalculateFirmwareHashes(options.file)
890 for section, value_dict in hashes.iteritems():
891 print "%s:" % section
892 for key, value in value_dict.iteritems():
893 print " %s: %s" % (key, value)
894 else:
895 raise Error('File does not exist: %s' % options.file)
896
henryhsuf6f835c2013-07-20 20:49:25 +0800897
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800898def Main():
899 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800900
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800901 options = ParseCmdline(
Ricky Liangc662be32013-12-24 11:50:23 +0800902 ('Perform Google required factory tests. All the HWID-related functions '
903 'provided here are mainly for the deprecated HWID v2. To access HWID '
904 'v3-related utilities, please use `hwid` command.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800905 CmdArg('-l', '--log', metavar='PATH',
906 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800907 CmdArg('--suppress-event-logs', action='store_true',
908 help='Suppress event logging.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800909 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800910 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800911 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
912 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800913 logging.debug('gooftool options: %s', repr(options))
914 try:
915 logging.debug('GOOFTOOL command %r', options.command_name)
916 options.command(options)
917 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
918 except Error, e:
919 logging.exception(e)
920 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
921 except Exception, e:
922 logging.exception(e)
923 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
924
925
926if __name__ == '__main__':
927 Main()