blob: 38869702bf0b4f5707f5e0e24b9f648f8474d4e4 [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Tammo Spalink01e11722012-07-24 10:17:54 -07002# pylint: disable=E1101
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08003#
4# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Google Factory Tool.
9
10This tool is indended to be used on factory assembly lines. It
11provides all of the Google required test functionality and must be run
12on each device as part of the assembly process.
13"""
14
Ricky Liang5b4568d2013-04-23 17:15:23 +080015import collections
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080016import logging
17import os
Jon Salz65266432012-07-30 19:02:49 +080018import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080019import re
20import sys
Hung-Te Lin6bd16472012-06-20 16:26:47 +080021import time
Jon Salza88b83b2013-05-27 20:00:35 +080022import xmlrpclib
Ricky Liang7905f272013-03-16 01:57:10 +080023import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080024
Andy Cheng2582d292012-12-04 17:38:28 +080025from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080026
Tammo Spalinka40293e2012-07-04 14:58:56 +080027import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080028
Andy Cheng0465d132013-03-20 12:12:06 +080029from cros.factory import event_log
Jon Salz0f8a6842012-09-25 11:28:22 +080030from cros.factory.common import Error, SetupLogging, Shell
Tammo Spalink394e4492012-08-01 10:20:30 -070031from cros.factory.common import YamlWrite
Andy Chengc531e2f2012-10-15 19:09:17 +080032from cros.factory.gooftool import Gooftool
Ricky Liang53390232013-03-08 15:37:57 +080033from cros.factory.gooftool import crosfw
Tammo Spalink01e11722012-07-24 10:17:54 -070034from cros.factory.gooftool import report_upload
Andy Cheng8ece7382012-08-22 16:25:42 +080035from cros.factory.gooftool.probe import Probe, PROBEABLE_COMPONENT_CLASSES
Jon Salz0f8a6842012-09-25 11:28:22 +080036from cros.factory.gooftool.probe import ReadRoVpd, ReadRwVpd
henryhsu44d793a2013-07-20 00:07:38 +080037from cros.factory.gooftool.probe import CalculateFirmwareHashes
Jon Salz193d7c62013-03-07 13:40:19 +080038from cros.factory.gooftool.vpd_data import KNOWN_VPD_FIELD_DATA
Tammo Spalinka40293e2012-07-04 14:58:56 +080039from cros.factory.hacked_argparse import CmdArg, Command, ParseCmdline
40from cros.factory.hacked_argparse import verbosity_cmd_arg
Tammo Spalink01e11722012-07-24 10:17:54 -070041from cros.factory.hwdb import hwid_tool
Ricky Liangeede7922013-06-19 10:18:41 +080042from cros.factory.hwid import common
Ricky Liangc662be32013-12-24 11:50:23 +080043from cros.factory.hwid import hwid_utils
Jon Salzfe9036f2014-01-16 14:11:23 +080044from cros.factory.test import shopfloor
45from 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
54
Ricky Lianga70a1202013-03-15 15:03:17 +080055def GetGooftool(options):
56 if options.hwid_version == 2:
57 hwdb_path = getattr(options, 'hwdb_path', None)
58 component_db = (
59 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path else None)
60 return Gooftool(hwid_version=2, component_db=component_db)
61 elif options.hwid_version == 3:
62 board = getattr(options, 'board', None)
63 hwdb_path = getattr(options, 'hwdb_path', None)
64 return Gooftool(hwid_version=3, board=board, hwdb_path=hwdb_path)
65 else:
66 raise Error, 'Invalid HWID version: %r' % options.hwid_version
67
68
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080069@Command('write_hwid',
70 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080071def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080072 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080073
Tammo Spalink95c43732012-07-25 15:57:14 -070074 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080075 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080076 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070077 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080078
79
Ricky Liang53390232013-03-08 15:37:57 +080080_board_cmd_arg = CmdArg(
81 '--board', metavar='BOARD',
82 default=None, help='Board name to test.')
83
Tammo Spalink8fab5312012-05-28 18:33:30 +080084_hwdb_path_cmd_arg = CmdArg(
85 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +080086 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +080087 help='Path to the HWID database.')
88
Tammo Spalink95c43732012-07-25 15:57:14 -070089_hwid_status_list_cmd_arg = CmdArg(
90 '--status', nargs='*', default=['supported'],
91 help='allow only HWIDs with these status values')
92
Jon Salzce124fb2012-10-02 17:42:03 +080093_probe_results_cmd_arg = CmdArg(
94 '--probe_results', metavar='RESULTS.yaml',
Ricky Liangc662be32013-12-24 11:50:23 +080095 help=('Output from "gooftool probe --include_vpd" (used instead of '
Jon Salzce124fb2012-10-02 17:42:03 +080096 'probing this system).'))
97
Ricky Liang53390232013-03-08 15:37:57 +080098_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +080099 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +0800100 help='A dict of device info to use instead of fetching from shopfllor '
101 'server.')
102
Jon Salzce124fb2012-10-02 17:42:03 +0800103_hwid_cmd_arg = CmdArg(
104 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800105 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800106
Bernie Thompson3c11c872013-07-22 18:22:45 -0700107_rma_mode_cmd_arg = CmdArg(
108 '--rma_mode', action='store_true',
109 help='Enable RMA mode, do not check for deprecated components.')
Tammo Spalink95c43732012-07-25 15:57:14 -0700110
111@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800112 _hwdb_path_cmd_arg,
113 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700114 help='optional BOARD name, needed only if data is present '
115 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800116 CmdArg('--bom', metavar='BOM', help='BOM name'),
117 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800118 CmdArg('--optimistic', action='store_true',
119 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700120 CmdArg('--comps', nargs='*', default=[],
121 help='list of canonical component names'),
122 CmdArg('--missing', nargs='*', default=[],
123 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800124 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700125 help='consider only HWIDs within this list of status values'))
126def BestMatchHwids(options):
Ricky Liangc662be32013-12-24 11:50:23 +0800127 """Determine a list of possible HWIDs using provided args and probing.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800128
129 VOLATILE can always be determined by probing. To get a unique
130 result, VARIANT must be specified for all cases where the matching
131 BOM has more than one associated variant code, otherwise all HWID
132 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700133 alternatively be specified using the --stdin_comps argument, which
134 allows specifying a list of canonical names (one per line) on stdin,
135 one per line. Based on what is known from BOM and stdin_comps,
136 determine a list of components to probe for, and use those probe
137 results to resolve a list of matching HWIDs. If no boms,
138 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800139 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800140
141 Returns (on stdout): A list of HWIDs that match the available probe
142 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700143
144 Example:
145
146 // Three ways to specify a keyboard (assuming it is a variant component)
147 gooftool best_match_hwids --missing keyboard
148 gooftool best_match_hwids --variant A or
149 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800150 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800151
Tammo Spalink5c699832012-07-03 17:50:39 +0800152 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700153 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800154 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800155 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800156 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800157 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800158 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700159 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800160 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800161 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800162 device.VariantExists(options.variant)
163 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700164 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700165 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700166 % YamlWrite(sorted(
167 hwid_tool.ComponentSpecClasses(component_spec) &
168 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700169 component_spec = hwid_tool.CombineComponentSpecs(
170 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700171 if options.comps or options.missing:
172 map(comp_db.CompExists, options.comps)
173 map(comp_db.CompClassExists, options.missing)
174 extra_comp_spec = comp_db.CreateComponentSpec(
175 components=options.comps,
176 missing=options.missing)
177 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
178 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
179 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700180 % YamlWrite(sorted(
181 hwid_tool.ComponentSpecClasses(component_spec) &
182 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700183 component_spec = hwid_tool.CombineComponentSpecs(
184 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700185 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700186 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800187 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800188 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
189 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700190 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700191 'as inputs, and cannot be probed for:\n%s'
192 'This problem can often be addressed by specifying all of '
193 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800194 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700195 print 'probing for missing classes:'
196 print YamlWrite(list(missing_classes))
197 probe_results = Probe(target_comp_classes=list(missing_classes),
198 probe_volatile=False, probe_initial_config=False)
199 cooked_components = comp_db.MatchComponentProbeValues(
200 probe_results.found_probe_value_map)
201 if cooked_components.unmatched:
202 sys.exit('ERROR: some probed components are unrecognized:\n%s'
203 % YamlWrite(cooked_components.unmatched))
204 probed_comp_spec = comp_db.CreateComponentSpec(
205 components=cooked_components.matched,
206 missing=probe_results.missing_component_classes)
207 component_spec = hwid_tool.CombineComponentSpecs(
208 component_spec, probed_comp_spec)
209 print YamlWrite({'component data used for matching': {
210 'missing component classes': component_spec.classes_missing,
211 'found components': component_spec.components}})
212 component_data = hwid_tool.ComponentData(
213 extant_components=hwid_tool.ComponentSpecCompClassMap(
214 component_spec).keys(),
215 classes_missing=component_spec.classes_missing)
216 match_tree = device.BuildMatchTree(component_data)
217 if not match_tree:
218 sys.exit('FAILURE: NO matching BOMs found')
219 print 'potential BOMs/VARIANTs:'
220 potential_variants = set()
221 potential_volatiles = set()
222 for bom_name, variant_tree in match_tree.items():
223 print ' BOM: %-8s VARIANTS: %s' % (
224 bom_name, ', '.join(sorted(variant_tree)))
225 for variant_code in variant_tree:
226 potential_variants.add(variant_code)
227 for volatile_code in device.volatiles:
228 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
229 if status in options.status:
230 potential_volatiles.add(volatile_code)
231 print ''
232 if len(potential_variants) == 0:
233 sys.exit('FAILURE: no matching VARIANTs found')
234 if len(potential_volatiles) == 0:
235 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
236 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700237 if (options.optimistic and
238 len(match_tree) == 1 and
239 len(potential_variants) == 1 and
240 len(potential_volatiles) == 1):
241 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
242 potential_variants.pop(),
243 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800244 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700245 print ('probing VOLATILEs to resolve potential matches: %s\n' %
246 ', '.join(sorted(potential_volatiles)))
247 vol_probe_results = Probe(
248 target_comp_classes=[],
249 probe_volatile=True,
250 probe_initial_config=False)
251 cooked_volatiles = device.MatchVolatileValues(
252 vol_probe_results.found_volatile_values)
253 match_tree = device.BuildMatchTree(
254 component_data, cooked_volatiles.matched_tags)
255 matched_hwids = device.GetMatchTreeHwids(match_tree)
256 if matched_hwids:
257 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800258 if matched_hwids[hwid] in options.status:
259 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700260 return
261 print 'exact HWID matching failed, but the following BOMs match: %s' % (
262 ', '.join(sorted(match_tree)))
263 if options.optimistic and len(match_tree) == 1:
264 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800265 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700266 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800267 if len(variant_matches) == 1:
268 var_code = set(variant_matches).pop()
269 elif len(bom.variants) == 1:
270 var_code = set(bom.variants).pop()
271 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700272 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
273 'because there were too many variants to choose from for BOM %r'
274 % bom_name)
275 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
276 for vol_code in device.volatiles
277 if device.GetHwidStatus(bom_name, var_code, vol_code)
278 in options.status]
279 for hwid in hwids:
280 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800281 return
282 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700283 print ('optimistic matching not attempted because either it was '
284 'not requested, or because the number of BOMs was <> 1\n')
285 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800286
287
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800288@Command('probe',
289 CmdArg('--comps', nargs='*',
290 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800291 CmdArg('--fast_fw_probe', action='store_true',
292 help='Do a fast probe for EC and main firmware versions only. '
293 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800294 CmdArg('--no_vol', action='store_true',
295 help='Do not probe volatile data.'),
296 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800297 help='Do not probe initial_config data.'),
298 CmdArg('--include_vpd', action='store_true',
299 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800300def RunProbe(options):
301 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800302 print GetGooftool(options).Probe(
303 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800304 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800305 probe_volatile=not options.no_vol,
306 probe_initial_config=not options.no_ic,
307 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800308
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800309
Tammo Spalink214caf42012-05-28 10:45:00 +0800310@Command('verify_components',
311 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800312 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800313def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800314 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800315
Tammo Spalink5c699832012-07-03 17:50:39 +0800316 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800317 that a corresponding match exists in the component_db -- make sure
318 that these components are present, that they have been approved, but
319 do not check against any specific BOM/HWID configurations.
320 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800321
Andy Chengc531e2f2012-10-15 19:09:17 +0800322 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800323 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800324 options.target_comps)
325 except ValueError, e:
326 sys.exit(e)
327
Ricky Liang53390232013-03-08 15:37:57 +0800328 PrintVerifyComponentsResults(result)
329
330
331def PrintVerifyComponentsResults(result):
332 """Prints out the results of VerifyComponents method call.
333
334 Groups the results into two groups: 'matches' and 'errors', and prints out
335 their values.
336 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800337 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800338 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800339 errors = []
340 for result_list in result.values():
341 for component_name, _, error in result_list:
342 if component_name:
343 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800344 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800345 errors.append(error)
346
Andy Cheng228a8c92012-08-27 10:53:57 +0800347 if matches:
348 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800349 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800350 print '\nerrors:\n %s' % '\n '.join(errors)
351 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800352 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800353 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800354
355
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800356@Command('verify_hwid',
Tammo Spalink95c43732012-07-25 15:57:14 -0700357 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800358 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800359 _probe_results_cmd_arg,
360 _hwid_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800361def VerifyHwid(options):
362 """Verify system HWID properties match probed device properties.
363
364 First probe components, volatile and initial_config parameters for
365 the DUT. Then use the available device data to produce a list of
366 candidate HWIDs. Then verify the HWID from the DUT is present in
367 that list. Then verify that the DUT initial config values match
368 those specified for its HWID. Finally, verify that VPD contains all
369 the necessary fields as specified by the board data, and when
370 possible verify that values are legitimate.
371 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800372
Ricky Liangf7857c12012-09-17 13:34:41 +0800373 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800374 for key in ro_vpd_keys:
375 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800376 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700377 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800378 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800379 if (known_valid_values is not None) and (value not in known_valid_values):
380 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800381 for key in rw_vpd_keys:
382 if key not in rw_vpd:
383 sys.exit('Missing required RW VPD field: %s' % key)
384 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
385 value = rw_vpd[key]
386 if (known_valid_values is not None) and (value not in known_valid_values):
387 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800388 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800389 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800390
Jon Salz81350812012-10-11 16:13:22 +0800391 if not options.hwid or not options.probe_results:
392 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800393
394 if options.hwid:
395 hwid_str = options.hwid
396 else:
397 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
398 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700399 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800400 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800401 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700402 device = hw_db.GetDevice(hwid.board)
403 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
404 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800405 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800406 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800407 if options.probe_results:
408 # Pull in probe results (including VPD data) from the given file
409 # rather than probing the current system.
410 probe_results = hwid_tool.ProbeResults.Decode(
411 open(options.probe_results).read())
412 ro_vpd = {}
413 rw_vpd = {}
414 for k, v in probe_results.found_volatile_values.items():
415 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
416 if match:
417 del probe_results.found_volatile_values[k]
418 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
419 else:
420 probe_results = Probe()
421 ro_vpd = ReadRoVpd(main_fw_file)
422 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700423 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
424 probe_results.found_probe_value_map)
425 cooked_volatiles = device.MatchVolatileValues(
426 probe_results.found_volatile_values)
427 cooked_initial_configs = device.MatchInitialConfigValues(
428 probe_results.initial_configs)
429 component_data = hwid_tool.ComponentData(
430 extant_components=cooked_components.matched,
431 classes_missing=probe_results.missing_component_classes)
432 match_tree = device.BuildMatchTree(
433 component_data, cooked_volatiles.matched_tags)
434 matched_hwids = device.GetMatchTreeHwids(match_tree)
435 print 'HWID status: %s\n' % hwid_status
436 print 'probed system components:'
437 print YamlWrite(cooked_components.__dict__)
438 print 'missing component classes:'
439 print YamlWrite(probe_results.missing_component_classes)
440 print 'probed volatiles:'
441 print YamlWrite(cooked_volatiles.__dict__)
442 print 'probed initial_configs:'
443 print YamlWrite(cooked_initial_configs)
444 print 'hwid match tree:'
445 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800446 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800447 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700448 found_components=cooked_components.__dict__,
449 missing_component_classes=probe_results.missing_component_classes,
450 volatiles=cooked_volatiles.__dict__,
451 initial_configs=cooked_initial_configs)
452 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800453 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700454 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800455 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700456 YamlWrite(cooked_components.unmatched))
457 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800458 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700459 component_data.Encode())
460 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800461 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700462 (', '.join(sorted(match_tree)), hwid.bom))
463 err_msg += 'target bom %r matches components' % hwid.bom
464 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
465 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800466 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700467 matched_variants = match_tree.get(hwid.bom, {})
468 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800469 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700470 hwid.variant)
471 matched_volatiles = matched_variants.get(hwid.variant, {})
472 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800473 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700474 hwid.volatile)
475 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800476 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800477 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800478 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700479 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800480
481
482@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700483def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800484 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800485
Ricky Lianga70a1202013-03-15 15:03:17 +0800486 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800487
488
489@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700490def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800491 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800492
Ricky Lianga70a1202013-03-15 15:03:17 +0800493 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800494 logging.info('Firmware bitmap initial locale set to %d (%s).',
495 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496
497
498@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700499def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800500 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800501
Ricky Lianga70a1202013-03-15 15:03:17 +0800502 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503
504
505@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700506def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800507 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800508
Ricky Lianga70a1202013-03-15 15:03:17 +0800509 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800510
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800511@Command('verify_tpm')
512def VerifyTPM(options): # pylint: disable=W0613
513 """Verify TPM is cleared."""
514
515 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800516
517@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800518def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800519 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800520
Ricky Lianga70a1202013-03-15 15:03:17 +0800521 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800522
523
524@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700525def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800526 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800527
Ricky Lianga70a1202013-03-15 15:03:17 +0800528 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800529 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800530 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800531
532
533@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700534def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800535 """Enable then verify firmware write protection."""
536
Hung-Te Linb21c6682012-08-01 13:53:57 +0800537 def CalculateLegacyRange(fw_type, length, section_data,
538 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800539 ro_size = length / 2
540 ro_a = int(section_data[0] / ro_size)
541 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
542 if ro_a != ro_b:
543 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800544 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800545 ro_offset = ro_a * ro_size
546 return (ro_offset, ro_size)
547
548 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800549 """Calculate protection size, then invoke flashrom.
550
551 Our supported chips only allow write protecting half their total
552 size, so we parition the flash chipset space accordingly.
553 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800554
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800555 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800556 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800557 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800558 if image.has_section(wp_section):
559 section_data = image.get_section_area(wp_section)
560 ro_offset = section_data[0]
561 ro_size = section_data[1]
562 elif image.has_section(legacy_section):
563 section_data = image.get_section_area(legacy_section)
564 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800565 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800566 else:
567 raise Error('could not find %s firmware section %s or %s' %
568 (fw_type, wp_section, legacy_section))
569
570 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
571 ro_offset, ro_size)
572 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800573
574 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800575 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800576 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
577 if ec_fw_file is not None:
578 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800579 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800580 else:
581 logging.warning('EC not write protected (seems there is no EC flash).')
582
583
584@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800585def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800586 """Zero out the GBB flags, in preparation for transition to release state.
587
588 No GBB flags are set in release/shipping state, but they are useful
589 for factory/development. See "gbb_utility --flags" for details.
590 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800591
Ricky Lianga70a1202013-03-15 15:03:17 +0800592 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800593 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800594
595
Jon Salzaa3a30e2013-05-15 15:56:28 +0800596@Command('clear_factory_vpd_entries')
597def ClearFactoryVPDEntries(options): # pylint: disable=W0613
598 """Clears factory.* items in the RW VPD."""
599 entries = GetGooftool(options).ClearFactoryVPDEntries()
600 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
601
602
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800603@Command('prepare_wipe',
604 CmdArg('--fast', action='store_true',
605 help='use non-secure but faster wipe method.'))
606def PrepareWipe(options):
607 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800608
Ricky Lianga70a1202013-03-15 15:03:17 +0800609 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800610
611@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800612 CmdArg('--no_write_protect', action='store_true',
613 help='Do not check write protection switch state.'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700614 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800615 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800616 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800617 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800618 _hwid_cmd_arg,
619 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800620def Verify(options):
621 """Verifies if whole factory process is ready for finalization.
622
623 This routine performs all the necessary checks to make sure the
624 device is ready to be finalized, but does not modify state. These
625 checks include dev switch, firmware write protection switch, hwid,
626 system time, keys, and root file system.
627 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800628
Hung-Te Lin6d827542012-07-19 11:50:41 +0800629 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800630 VerifyWPSwitch(options)
631 VerifyDevSwitch(options)
632 if options.hwid_version == 2:
633 VerifyHwid(options)
634 elif options.hwid_version == 3:
Ricky Liangc662be32013-12-24 11:50:23 +0800635 VerifyHWIDv3(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800636 else:
637 raise Error, 'Invalid HWID version: %r' % options.hwid_version
638 VerifySystemTime(options)
639 VerifyKeys(options)
640 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800641 VerifyTPM(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800642
Jon Salzfe9036f2014-01-16 14:11:23 +0800643@Command('untar_stateful_files')
644def UntarStatefulFiles(dummy_options):
645 """Untars stateful files from stateful_files.tar.xz on stateful partition.
646
647 If that file does not exist (which should only be R30 and earlier),
648 this is a no-op.
649 """
650 tar_file = os.path.join(DEVICE_STATEFUL_PATH, 'stateful_files.tar.xz')
651 if os.path.exists(tar_file):
652 Spawn(['tar', 'xf', tar_file], cwd=DEVICE_STATEFUL_PATH,
653 log=True, check_call=True)
654 else:
655 logging.warning('No stateful files at %s', tar_file)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800656
Tammo Spalink86a61c62012-05-25 15:10:35 +0800657@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700658def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800659 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800660
Andy Cheng0465d132013-03-20 12:12:06 +0800661 event_log.Log('system_details', **Gooftool(
Ricky Lianga70a1202013-03-15 15:03:17 +0800662 hwid_version=options.hwid_version).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800663
664
Jon Salza88b83b2013-05-27 20:00:35 +0800665def CreateReportArchiveBlob(*args, **kwargs):
666 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800667
Jon Salza88b83b2013-05-27 20:00:35 +0800668 Args:
669 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800670
Jon Salza88b83b2013-05-27 20:00:35 +0800671 Returns:
672 An xmlrpclib.Binary object containing a .tar.xz file.
673 """
674 with open(CreateReportArchive(*args, **kwargs)) as f:
675 return xmlrpclib.Binary(f.read())
676
677
678def CreateReportArchive(device_sn=None, add_file=None):
679 """Creates a report archive in a temporary directory.
680
681 Args:
682 device_sn: The device serial number (optional).
683 add_file: A list of files to add (optional).
684
685 Returns:
686 Path to the archive.
687 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800688 def NormalizeAsFileName(token):
689 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800690
691 target_name = '%s%s.tar.xz' % (
692 time.strftime('%Y%m%dT%H%M%SZ',
693 time.gmtime()),
694 ("" if device_sn is None else
695 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800696 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800697
Tammo Spalink86a61c62012-05-25 15:10:35 +0800698 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800699 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800700 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800701 if add_file:
702 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800703 # Require absolute paths since the tar command may change the
704 # directory.
705 if not f.startswith('/'):
706 raise Error('Not an absolute path: %s' % f)
707 if not os.path.exists(f):
708 raise Error('File does not exist: %s' % f)
709 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800710 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800711
712 if ((cmd_result.status == 1) and
713 all((x == '' or
714 'file changed as we read it' in x or
715 "Removing leading `/' from member names" in x)
716 for x in cmd_result.stderr.split('\n'))):
717 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800718 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800719 ignore_stdout=True)
720 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800721 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
722 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800723
Jon Salza88b83b2013-05-27 20:00:35 +0800724 return target_path
725
726_upload_method_cmd_arg = CmdArg(
727 '--upload_method', metavar='METHOD:PARAM',
728 help=('How to perform the upload. METHOD should be one of '
729 '{ftp, shopfloor, ftps, cpfe}.'))
730_add_file_cmd_arg = CmdArg(
731 '--add_file', metavar='FILE', action='append',
732 help='Extra file to include in report (must be an absolute path)')
733
734@Command('upload_report',
735 _upload_method_cmd_arg,
736 _add_file_cmd_arg)
737def UploadReport(options):
738 """Create a report containing key device details."""
739 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
740 device_sn = ro_vpd.get('serial_number', None)
741 if device_sn is None:
742 logging.warning('RO_VPD missing device serial number')
743 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
744 target_path = CreateReportArchive(device_sn)
745
Tammo Spalink86a61c62012-05-25 15:10:35 +0800746 if options.upload_method is None or options.upload_method == 'none':
747 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
748 return
749 method, param = options.upload_method.split(':', 1)
750 if method == 'shopfloor':
751 report_upload.ShopFloorUpload(target_path, param)
752 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700753 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800754 elif method == 'ftps':
755 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
756 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800757 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800758 else:
759 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800760
761
762@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800763 CmdArg('--no_write_protect', action='store_true',
764 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800765 CmdArg('--fast', action='store_true',
766 help='use non-secure but faster wipe method.'),
767 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700768 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800769 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800770 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800771 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800772 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800773 _hwid_cmd_arg,
774 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800775def Finalize(options):
776 """Verify system readiness and trigger transition into release state.
777
Jon Salzaa3a30e2013-05-15 15:56:28 +0800778 This routine does the following:
779 - Verifies system state (see verify command)
Jon Salzfe9036f2014-01-16 14:11:23 +0800780 - Untars stateful_files.tar.xz, if it exists, in the stateful partition, to
781 initialize files such as the CRX cache
Jon Salzaa3a30e2013-05-15 15:56:28 +0800782 - Modifies firmware bitmaps to match locale
783 - Clears all factory-friendly flags from the GBB
784 - Removes factory-specific entries from RW_VPD (factory.*)
785 - Enables firmware write protection (cannot rollback after this)
786 - Uploads system logs & reports
787 - Sets the necessary boot flags to cause wipe of the factory image on the
788 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800789 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800790 Verify(options)
Jon Salzfe9036f2014-01-16 14:11:23 +0800791 UntarStatefulFiles(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800792 SetFirmwareBitmapLocale(options)
793 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800794 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800795 if options.no_write_protect:
796 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800797 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800798 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800799 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800800 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800801 UploadReport(options)
802 PrepareWipe(options)
803
804
Ricky Liangc662be32013-12-24 11:50:23 +0800805def VerifyHWIDv3(options):
806 """A simple wrapper that calls out to HWID utils to verify version 3 HWID.
Ricky Liang53390232013-03-08 15:37:57 +0800807
Ricky Liangc662be32013-12-24 11:50:23 +0800808 This is mainly for Gooftool to verify v3 HWID during finalize. For testing
809 and development purposes, please use `hwid` command.
Ricky Liang53390232013-03-08 15:37:57 +0800810 """
Ricky Liangc662be32013-12-24 11:50:23 +0800811 db = GetGooftool(options).db
812 encoded_string = options.hwid or hwid_utils.GetHWIDString()
Ricky Liang7905f272013-03-16 01:57:10 +0800813 if options.probe_results:
Ricky Liangc662be32013-12-24 11:50:23 +0800814 probed_results = yaml.load(open(options.probe_results).read())
Ricky Liang7905f272013-03-16 01:57:10 +0800815 else:
Ricky Liangc662be32013-12-24 11:50:23 +0800816 probed_results = yaml.load(Probe(probe_vpd=True).Encode())
817 vpd = hwid_utils.GetVPD(probed_results)
Ricky Liang53390232013-03-08 15:37:57 +0800818
Ricky Liangc662be32013-12-24 11:50:23 +0800819 event_log.Log('probed_results', probed_results=probed_results)
820 event_log.Log('vpd', vpd=vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800821
Ricky Liangc662be32013-12-24 11:50:23 +0800822 hwid_utils.VerifyHWID(db, encoded_string, probed_results, vpd,
823 rma_mode=options.rma_mode)
Ricky Liang53390232013-03-08 15:37:57 +0800824
Ricky Liangc662be32013-12-24 11:50:23 +0800825 event_log.Log('verified_hwid', hwid=encoded_string)
Ricky Liang53390232013-03-08 15:37:57 +0800826
827
Ricky Liang59611a62013-06-11 13:47:33 +0800828def ParseDecodedHWID(hwid):
829 """Parse the HWID object into a more compact dict.
830
831 Args:
832 hwid: A decoded HWID object.
833
834 Returns:
835 A dict containing the board name, the binary string, and the list of
836 components.
837 """
838 results = {}
839 results['board'] = hwid.database.board
840 results['binary_string'] = hwid.binary_string
841 results['components'] = collections.defaultdict(list)
842 components = hwid.bom.components
843 for comp_cls in sorted(components):
844 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
845 if not probed_values:
846 db_components = hwid.database.components
847 probed_values = db_components.GetComponentAttributes(
848 comp_cls, comp_name).get('values')
849 results['components'][comp_cls].append(
850 {comp_name: probed_values if probed_values else None})
851 # Convert defaultdict to dict.
852 results['components'] = dict(results['components'])
853 return results
854
855
henryhsu44d793a2013-07-20 00:07:38 +0800856@Command('get_firmware_hash',
857 CmdArg('--file', metavar='FILE', help='Firmware File.'))
858def GetFirmwareHash(options):
henryhsuf6f835c2013-07-20 20:49:25 +0800859 """Get firmware hash from a file"""
henryhsu44d793a2013-07-20 00:07:38 +0800860 if os.path.exists(options.file):
861 hashes = CalculateFirmwareHashes(options.file)
862 for section, value_dict in hashes.iteritems():
863 print "%s:" % section
864 for key, value in value_dict.iteritems():
865 print " %s: %s" % (key, value)
866 else:
867 raise Error('File does not exist: %s' % options.file)
868
henryhsuf6f835c2013-07-20 20:49:25 +0800869
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800870def Main():
871 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800872
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800873 options = ParseCmdline(
Ricky Liangc662be32013-12-24 11:50:23 +0800874 ('Perform Google required factory tests. All the HWID-related functions '
875 'provided here are mainly for the deprecated HWID v2. To access HWID '
876 'v3-related utilities, please use `hwid` command.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800877 CmdArg('-l', '--log', metavar='PATH',
878 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800879 CmdArg('--suppress-event-logs', action='store_true',
880 help='Suppress event logging.'),
Jon Salzfb61b1d2013-05-15 16:04:13 +0800881 CmdArg('-i', '--hwid-version', default=3, choices=[2, 3], type=int,
Ricky Lianga70a1202013-03-15 15:03:17 +0800882 help='Version of HWID to operate on.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800883 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800884 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800885 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
886 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800887 logging.debug('gooftool options: %s', repr(options))
888 try:
889 logging.debug('GOOFTOOL command %r', options.command_name)
890 options.command(options)
891 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
892 except Error, e:
893 logging.exception(e)
894 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
895 except Exception, e:
896 logging.exception(e)
897 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
898
899
900if __name__ == '__main__':
901 Main()