blob: e42a7816b8e724978b670f4ba686f747ce9aca6b [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 Salz40b9f822014-07-25 16:39:55 +080045from cros.factory.test import factory
Jon Salzfe9036f2014-01-16 14:11:23 +080046from cros.factory.test.factory import FACTORY_LOG_PATH, DEVICE_STATEFUL_PATH
Jon Salz40b9f822014-07-25 16:39:55 +080047from cros.factory.utils import file_utils
Jon Salzff88c022012-11-03 12:19:58 +080048from cros.factory.utils.process_utils import Spawn
Jon Salz8baad8b2013-03-11 20:01:45 +080049from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080050
Tammo Spalink5c699832012-07-03 17:50:39 +080051
Tammo Spalink5c699832012-07-03 17:50:39 +080052# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
53# treat that specially (as a smoot exit, as opposed to the more
54# verbose output for generic Error).
55
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080056_global_gooftool = None
57_gooftool_lock = threading.Lock()
Tammo Spalink5c699832012-07-03 17:50:39 +080058
Ricky Lianga70a1202013-03-15 15:03:17 +080059def GetGooftool(options):
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080060 global _global_gooftool # pylint: disable=W0603
Ricky Lianga70a1202013-03-15 15:03:17 +080061
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080062 if _global_gooftool is None:
63 with _gooftool_lock:
Ricky Liang43b879b2014-02-24 11:36:55 +080064 hwid_version = getattr(options, 'hwid_version', 3)
65 if hwid_version == 2:
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080066 hwdb_path = getattr(options, 'hwdb_path', None)
67 component_db = (
68 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path
69 else None)
70 _global_gooftool = Gooftool(hwid_version=2, component_db=component_db)
Ricky Liang43b879b2014-02-24 11:36:55 +080071 elif hwid_version == 3:
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080072 board = getattr(options, 'board', None)
73 hwdb_path = getattr(options, 'hwdb_path', None)
74 _global_gooftool = Gooftool(hwid_version=3, board=board,
75 hwdb_path=hwdb_path)
76 else:
77 raise Error, 'Invalid HWID version: %r' % options.hwid_version
78
79 return _global_gooftool
Ricky Lianga70a1202013-03-15 15:03:17 +080080
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080081@Command('write_hwid',
82 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080083def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080084 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080085
Tammo Spalink95c43732012-07-25 15:57:14 -070086 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080087 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080088 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070089 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080090
91
Ricky Liang53390232013-03-08 15:37:57 +080092_board_cmd_arg = CmdArg(
93 '--board', metavar='BOARD',
94 default=None, help='Board name to test.')
95
Tammo Spalink8fab5312012-05-28 18:33:30 +080096_hwdb_path_cmd_arg = CmdArg(
97 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +080098 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +080099 help='Path to the HWID database.')
100
Tammo Spalink95c43732012-07-25 15:57:14 -0700101_hwid_status_list_cmd_arg = CmdArg(
102 '--status', nargs='*', default=['supported'],
103 help='allow only HWIDs with these status values')
104
Jon Salzce124fb2012-10-02 17:42:03 +0800105_probe_results_cmd_arg = CmdArg(
106 '--probe_results', metavar='RESULTS.yaml',
Ricky Liangc662be32013-12-24 11:50:23 +0800107 help=('Output from "gooftool probe --include_vpd" (used instead of '
Jon Salzce124fb2012-10-02 17:42:03 +0800108 'probing this system).'))
109
Ricky Liang53390232013-03-08 15:37:57 +0800110_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +0800111 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +0800112 help='A dict of device info to use instead of fetching from shopfllor '
113 'server.')
114
Jon Salzce124fb2012-10-02 17:42:03 +0800115_hwid_cmd_arg = CmdArg(
116 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800117 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800118
Bernie Thompson3c11c872013-07-22 18:22:45 -0700119_rma_mode_cmd_arg = CmdArg(
120 '--rma_mode', action='store_true',
121 help='Enable RMA mode, do not check for deprecated components.')
Tammo Spalink95c43732012-07-25 15:57:14 -0700122
Ricky Liang43b879b2014-02-24 11:36:55 +0800123_hwid_version_cmd_arg = CmdArg(
124 '-i', '--hwid-version', default=3, choices=(2, 3), type=int,
125 help='Version of HWID to operate on. (default: %(default)s)')
126
127
Tammo Spalink95c43732012-07-25 15:57:14 -0700128@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800129 _hwdb_path_cmd_arg,
130 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700131 help='optional BOARD name, needed only if data is present '
132 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800133 CmdArg('--bom', metavar='BOM', help='BOM name'),
134 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800135 CmdArg('--optimistic', action='store_true',
136 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700137 CmdArg('--comps', nargs='*', default=[],
138 help='list of canonical component names'),
139 CmdArg('--missing', nargs='*', default=[],
140 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800141 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700142 help='consider only HWIDs within this list of status values'))
143def BestMatchHwids(options):
Ricky Liangc662be32013-12-24 11:50:23 +0800144 """Determine a list of possible HWIDs using provided args and probing.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800145
146 VOLATILE can always be determined by probing. To get a unique
147 result, VARIANT must be specified for all cases where the matching
148 BOM has more than one associated variant code, otherwise all HWID
149 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700150 alternatively be specified using the --stdin_comps argument, which
151 allows specifying a list of canonical names (one per line) on stdin,
152 one per line. Based on what is known from BOM and stdin_comps,
153 determine a list of components to probe for, and use those probe
154 results to resolve a list of matching HWIDs. If no boms,
155 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800156 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800157
158 Returns (on stdout): A list of HWIDs that match the available probe
159 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700160
161 Example:
162
163 // Three ways to specify a keyboard (assuming it is a variant component)
164 gooftool best_match_hwids --missing keyboard
165 gooftool best_match_hwids --variant A or
166 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800167 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800168
Tammo Spalink5c699832012-07-03 17:50:39 +0800169 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700170 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800171 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800172 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800173 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800174 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800175 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700176 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800177 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800178 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800179 device.VariantExists(options.variant)
180 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700181 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700182 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700183 % YamlWrite(sorted(
184 hwid_tool.ComponentSpecClasses(component_spec) &
185 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700186 component_spec = hwid_tool.CombineComponentSpecs(
187 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700188 if options.comps or options.missing:
189 map(comp_db.CompExists, options.comps)
190 map(comp_db.CompClassExists, options.missing)
191 extra_comp_spec = comp_db.CreateComponentSpec(
192 components=options.comps,
193 missing=options.missing)
194 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
195 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
196 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700197 % YamlWrite(sorted(
198 hwid_tool.ComponentSpecClasses(component_spec) &
199 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700200 component_spec = hwid_tool.CombineComponentSpecs(
201 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700202 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700203 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800204 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800205 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
206 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700207 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700208 'as inputs, and cannot be probed for:\n%s'
209 'This problem can often be addressed by specifying all of '
210 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800211 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700212 print 'probing for missing classes:'
213 print YamlWrite(list(missing_classes))
214 probe_results = Probe(target_comp_classes=list(missing_classes),
215 probe_volatile=False, probe_initial_config=False)
216 cooked_components = comp_db.MatchComponentProbeValues(
217 probe_results.found_probe_value_map)
218 if cooked_components.unmatched:
219 sys.exit('ERROR: some probed components are unrecognized:\n%s'
220 % YamlWrite(cooked_components.unmatched))
221 probed_comp_spec = comp_db.CreateComponentSpec(
222 components=cooked_components.matched,
223 missing=probe_results.missing_component_classes)
224 component_spec = hwid_tool.CombineComponentSpecs(
225 component_spec, probed_comp_spec)
226 print YamlWrite({'component data used for matching': {
227 'missing component classes': component_spec.classes_missing,
228 'found components': component_spec.components}})
229 component_data = hwid_tool.ComponentData(
230 extant_components=hwid_tool.ComponentSpecCompClassMap(
231 component_spec).keys(),
232 classes_missing=component_spec.classes_missing)
233 match_tree = device.BuildMatchTree(component_data)
234 if not match_tree:
235 sys.exit('FAILURE: NO matching BOMs found')
236 print 'potential BOMs/VARIANTs:'
237 potential_variants = set()
238 potential_volatiles = set()
239 for bom_name, variant_tree in match_tree.items():
240 print ' BOM: %-8s VARIANTS: %s' % (
241 bom_name, ', '.join(sorted(variant_tree)))
242 for variant_code in variant_tree:
243 potential_variants.add(variant_code)
244 for volatile_code in device.volatiles:
245 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
246 if status in options.status:
247 potential_volatiles.add(volatile_code)
248 print ''
249 if len(potential_variants) == 0:
250 sys.exit('FAILURE: no matching VARIANTs found')
251 if len(potential_volatiles) == 0:
252 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
253 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700254 if (options.optimistic and
255 len(match_tree) == 1 and
256 len(potential_variants) == 1 and
257 len(potential_volatiles) == 1):
258 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
259 potential_variants.pop(),
260 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800261 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700262 print ('probing VOLATILEs to resolve potential matches: %s\n' %
263 ', '.join(sorted(potential_volatiles)))
264 vol_probe_results = Probe(
265 target_comp_classes=[],
266 probe_volatile=True,
267 probe_initial_config=False)
268 cooked_volatiles = device.MatchVolatileValues(
269 vol_probe_results.found_volatile_values)
270 match_tree = device.BuildMatchTree(
271 component_data, cooked_volatiles.matched_tags)
272 matched_hwids = device.GetMatchTreeHwids(match_tree)
273 if matched_hwids:
274 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800275 if matched_hwids[hwid] in options.status:
276 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700277 return
278 print 'exact HWID matching failed, but the following BOMs match: %s' % (
279 ', '.join(sorted(match_tree)))
280 if options.optimistic and len(match_tree) == 1:
281 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800282 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700283 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800284 if len(variant_matches) == 1:
285 var_code = set(variant_matches).pop()
286 elif len(bom.variants) == 1:
287 var_code = set(bom.variants).pop()
288 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700289 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
290 'because there were too many variants to choose from for BOM %r'
291 % bom_name)
292 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
293 for vol_code in device.volatiles
294 if device.GetHwidStatus(bom_name, var_code, vol_code)
295 in options.status]
296 for hwid in hwids:
297 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800298 return
299 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700300 print ('optimistic matching not attempted because either it was '
301 'not requested, or because the number of BOMs was <> 1\n')
302 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800303
304
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800305@Command('probe',
306 CmdArg('--comps', nargs='*',
307 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800308 CmdArg('--fast_fw_probe', action='store_true',
309 help='Do a fast probe for EC and main firmware versions only. '
310 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800311 CmdArg('--no_vol', action='store_true',
312 help='Do not probe volatile data.'),
313 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800314 help='Do not probe initial_config data.'),
315 CmdArg('--include_vpd', action='store_true',
316 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800317def RunProbe(options):
318 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800319 print GetGooftool(options).Probe(
320 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800321 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800322 probe_volatile=not options.no_vol,
323 probe_initial_config=not options.no_ic,
324 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800325
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800326
Tammo Spalink214caf42012-05-28 10:45:00 +0800327@Command('verify_components',
328 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800329 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800330def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800331 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800332
Tammo Spalink5c699832012-07-03 17:50:39 +0800333 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800334 that a corresponding match exists in the component_db -- make sure
335 that these components are present, that they have been approved, but
336 do not check against any specific BOM/HWID configurations.
337 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800338
Andy Chengc531e2f2012-10-15 19:09:17 +0800339 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800340 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800341 options.target_comps)
342 except ValueError, e:
343 sys.exit(e)
344
Ricky Liang53390232013-03-08 15:37:57 +0800345 PrintVerifyComponentsResults(result)
346
347
348def PrintVerifyComponentsResults(result):
349 """Prints out the results of VerifyComponents method call.
350
351 Groups the results into two groups: 'matches' and 'errors', and prints out
352 their values.
353 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800354 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800355 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800356 errors = []
357 for result_list in result.values():
358 for component_name, _, error in result_list:
359 if component_name:
360 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800361 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800362 errors.append(error)
363
Andy Cheng228a8c92012-08-27 10:53:57 +0800364 if matches:
365 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800366 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800367 print '\nerrors:\n %s' % '\n '.join(errors)
368 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800369 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800370 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800371
372
Ricky Liang43b879b2014-02-24 11:36:55 +0800373@Command('verify_hwid_v2',
Tammo Spalink95c43732012-07-25 15:57:14 -0700374 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800375 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800376 _probe_results_cmd_arg,
377 _hwid_cmd_arg)
Ricky Liang43b879b2014-02-24 11:36:55 +0800378def VerifyHWIDv2(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800379 """Verify system HWID properties match probed device properties.
380
381 First probe components, volatile and initial_config parameters for
382 the DUT. Then use the available device data to produce a list of
383 candidate HWIDs. Then verify the HWID from the DUT is present in
384 that list. Then verify that the DUT initial config values match
385 those specified for its HWID. Finally, verify that VPD contains all
386 the necessary fields as specified by the board data, and when
387 possible verify that values are legitimate.
388 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800389 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800390 for key in ro_vpd_keys:
391 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800392 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700393 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800394 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800395 if (known_valid_values is not None) and (value not in known_valid_values):
396 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800397 for key in rw_vpd_keys:
398 if key not in rw_vpd:
399 sys.exit('Missing required RW VPD field: %s' % key)
400 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
401 value = rw_vpd[key]
402 if (known_valid_values is not None) and (value not in known_valid_values):
403 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800404 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800405 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800406
Jon Salz81350812012-10-11 16:13:22 +0800407 if not options.hwid or not options.probe_results:
408 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800409
410 if options.hwid:
411 hwid_str = options.hwid
412 else:
413 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
414 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700415 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800416 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800417 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700418 device = hw_db.GetDevice(hwid.board)
419 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
420 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800421 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800422 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800423 if options.probe_results:
424 # Pull in probe results (including VPD data) from the given file
425 # rather than probing the current system.
426 probe_results = hwid_tool.ProbeResults.Decode(
427 open(options.probe_results).read())
428 ro_vpd = {}
429 rw_vpd = {}
430 for k, v in probe_results.found_volatile_values.items():
431 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
432 if match:
433 del probe_results.found_volatile_values[k]
434 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
435 else:
436 probe_results = Probe()
437 ro_vpd = ReadRoVpd(main_fw_file)
438 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700439 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
440 probe_results.found_probe_value_map)
441 cooked_volatiles = device.MatchVolatileValues(
442 probe_results.found_volatile_values)
443 cooked_initial_configs = device.MatchInitialConfigValues(
444 probe_results.initial_configs)
445 component_data = hwid_tool.ComponentData(
446 extant_components=cooked_components.matched,
447 classes_missing=probe_results.missing_component_classes)
448 match_tree = device.BuildMatchTree(
449 component_data, cooked_volatiles.matched_tags)
450 matched_hwids = device.GetMatchTreeHwids(match_tree)
451 print 'HWID status: %s\n' % hwid_status
452 print 'probed system components:'
453 print YamlWrite(cooked_components.__dict__)
454 print 'missing component classes:'
455 print YamlWrite(probe_results.missing_component_classes)
456 print 'probed volatiles:'
457 print YamlWrite(cooked_volatiles.__dict__)
458 print 'probed initial_configs:'
459 print YamlWrite(cooked_initial_configs)
460 print 'hwid match tree:'
461 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800462 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800463 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700464 found_components=cooked_components.__dict__,
465 missing_component_classes=probe_results.missing_component_classes,
466 volatiles=cooked_volatiles.__dict__,
467 initial_configs=cooked_initial_configs)
468 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800469 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700470 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800471 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700472 YamlWrite(cooked_components.unmatched))
473 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800474 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700475 component_data.Encode())
476 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800477 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700478 (', '.join(sorted(match_tree)), hwid.bom))
479 err_msg += 'target bom %r matches components' % hwid.bom
480 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
481 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800482 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700483 matched_variants = match_tree.get(hwid.bom, {})
484 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800485 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700486 hwid.variant)
487 matched_volatiles = matched_variants.get(hwid.variant, {})
488 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800489 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700490 hwid.volatile)
491 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800492 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800493 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800494 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700495 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800496
497
498@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700499def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800500 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800501
Ricky Lianga70a1202013-03-15 15:03:17 +0800502 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800503
504
505@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700506def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800507 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800508
Ricky Lianga70a1202013-03-15 15:03:17 +0800509 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800510 logging.info('Firmware bitmap initial locale set to %d (%s).',
511 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800512
513
514@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700515def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800516 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800517
Ricky Lianga70a1202013-03-15 15:03:17 +0800518 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800519
520
521@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700522def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800523 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800524
Ricky Lianga70a1202013-03-15 15:03:17 +0800525 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800526
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800527@Command('verify_tpm')
528def VerifyTPM(options): # pylint: disable=W0613
529 """Verify TPM is cleared."""
530
531 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800532
Hung-Te Lindd708d42014-07-11 17:05:01 +0800533@Command('verify_me_locked')
534def VerifyManagementEngineLocked(options): # pylint: disable=W0613
535 """Verify Managment Engine is locked."""
536
537 return GetGooftool(options).VerifyManagementEngineLocked()
538
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800539@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800540def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800541 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800542
Ricky Lianga70a1202013-03-15 15:03:17 +0800543 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800544
545
546@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700547def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800548 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800549
Ricky Lianga70a1202013-03-15 15:03:17 +0800550 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800551 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800552 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800553
554
Jon Salzadd90d32014-04-29 16:16:27 +0800555@Command('verify_branding')
556def VerifyBranding(options): # pylint: disable=W0613
557 """Verify that branding fields are properly set.
558
559 customization_id, if set in the RO VPD, must be of the correct format.
560
561 rlz_brand_code must be set either in the RO VPD or OEM partition, and must
562 be of the correct format.
563 """
564 return GetGooftool(options).VerifyBranding()
565
566
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800567@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700568def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800569 """Enable then verify firmware write protection."""
570
Hung-Te Linb21c6682012-08-01 13:53:57 +0800571 def CalculateLegacyRange(fw_type, length, section_data,
572 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800573 ro_size = length / 2
574 ro_a = int(section_data[0] / ro_size)
575 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
576 if ro_a != ro_b:
577 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800578 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800579 ro_offset = ro_a * ro_size
580 return (ro_offset, ro_size)
581
582 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800583 """Calculate protection size, then invoke flashrom.
584
585 Our supported chips only allow write protecting half their total
586 size, so we parition the flash chipset space accordingly.
587 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800588
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800589 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800590 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800591 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800592 if image.has_section(wp_section):
593 section_data = image.get_section_area(wp_section)
594 ro_offset = section_data[0]
595 ro_size = section_data[1]
596 elif image.has_section(legacy_section):
597 section_data = image.get_section_area(legacy_section)
598 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800599 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800600 else:
601 raise Error('could not find %s firmware section %s or %s' %
602 (fw_type, wp_section, legacy_section))
603
604 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
605 ro_offset, ro_size)
606 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800607
608 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800609 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800610 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
611 if ec_fw_file is not None:
612 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800613 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800614 else:
615 logging.warning('EC not write protected (seems there is no EC flash).')
616
617
618@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800619def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800620 """Zero out the GBB flags, in preparation for transition to release state.
621
622 No GBB flags are set in release/shipping state, but they are useful
623 for factory/development. See "gbb_utility --flags" for details.
624 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800625
Ricky Lianga70a1202013-03-15 15:03:17 +0800626 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800627 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800628
629
Jon Salzaa3a30e2013-05-15 15:56:28 +0800630@Command('clear_factory_vpd_entries')
631def ClearFactoryVPDEntries(options): # pylint: disable=W0613
632 """Clears factory.* items in the RW VPD."""
633 entries = GetGooftool(options).ClearFactoryVPDEntries()
634 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
635
636
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800637@Command('prepare_wipe',
638 CmdArg('--fast', action='store_true',
639 help='use non-secure but faster wipe method.'))
640def PrepareWipe(options):
641 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800642
Ricky Lianga70a1202013-03-15 15:03:17 +0800643 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800644
645@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800646 CmdArg('--no_write_protect', action='store_true',
647 help='Do not check write protection switch state.'),
Ricky Liang43b879b2014-02-24 11:36:55 +0800648 _hwid_version_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700649 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800650 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800651 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800652 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800653 _hwid_cmd_arg,
654 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800655def Verify(options):
656 """Verifies if whole factory process is ready for finalization.
657
658 This routine performs all the necessary checks to make sure the
659 device is ready to be finalized, but does not modify state. These
660 checks include dev switch, firmware write protection switch, hwid,
661 system time, keys, and root file system.
662 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800663
Hung-Te Lin6d827542012-07-19 11:50:41 +0800664 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800665 VerifyWPSwitch(options)
Hung-Te Lindd708d42014-07-11 17:05:01 +0800666 VerifyManagementEngineLocked(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800667 VerifyDevSwitch(options)
668 if options.hwid_version == 2:
Ricky Liang43b879b2014-02-24 11:36:55 +0800669 VerifyHWIDv2(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800670 elif options.hwid_version == 3:
Ricky Liangc662be32013-12-24 11:50:23 +0800671 VerifyHWIDv3(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800672 else:
673 raise Error, 'Invalid HWID version: %r' % options.hwid_version
674 VerifySystemTime(options)
675 VerifyKeys(options)
676 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800677 VerifyTPM(options)
Jon Salzadd90d32014-04-29 16:16:27 +0800678 VerifyBranding(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800679
Jon Salzfe9036f2014-01-16 14:11:23 +0800680@Command('untar_stateful_files')
Hung-Te Lin388bce22014-06-03 19:56:40 +0800681def UntarStatefulFiles(unused_options):
Jon Salzfe9036f2014-01-16 14:11:23 +0800682 """Untars stateful files from stateful_files.tar.xz on stateful partition.
683
684 If that file does not exist (which should only be R30 and earlier),
685 this is a no-op.
686 """
687 tar_file = os.path.join(DEVICE_STATEFUL_PATH, 'stateful_files.tar.xz')
688 if os.path.exists(tar_file):
689 Spawn(['tar', 'xf', tar_file], cwd=DEVICE_STATEFUL_PATH,
690 log=True, check_call=True)
691 else:
692 logging.warning('No stateful files at %s', tar_file)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800693
Jon Salz40b9f822014-07-25 16:39:55 +0800694
695@Command('log_source_hashes')
696def LogSourceHashes(options): # pylint: disable=W0613
697 """Logs hashes of source files in the factory toolkit."""
698 event_log.Log(
699 'source_hashes',
Jon Salz9596ae02014-07-29 14:25:49 +0800700 **file_utils.HashSourceTree(os.path.join(factory.FACTORY_PATH, 'py')))
Jon Salz40b9f822014-07-25 16:39:55 +0800701
702
Tammo Spalink86a61c62012-05-25 15:10:35 +0800703@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700704def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800705 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800706
Ricky Liang43b879b2014-02-24 11:36:55 +0800707 event_log.Log('system_details', **GetGooftool(options).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800708
709
Jon Salza88b83b2013-05-27 20:00:35 +0800710def CreateReportArchiveBlob(*args, **kwargs):
711 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800712
Jon Salza88b83b2013-05-27 20:00:35 +0800713 Args:
714 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800715
Jon Salza88b83b2013-05-27 20:00:35 +0800716 Returns:
717 An xmlrpclib.Binary object containing a .tar.xz file.
718 """
719 with open(CreateReportArchive(*args, **kwargs)) as f:
720 return xmlrpclib.Binary(f.read())
721
722
723def CreateReportArchive(device_sn=None, add_file=None):
724 """Creates a report archive in a temporary directory.
725
726 Args:
727 device_sn: The device serial number (optional).
728 add_file: A list of files to add (optional).
729
730 Returns:
731 Path to the archive.
732 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800733 def NormalizeAsFileName(token):
734 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800735
736 target_name = '%s%s.tar.xz' % (
737 time.strftime('%Y%m%dT%H%M%SZ',
738 time.gmtime()),
739 ("" if device_sn is None else
740 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800741 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800742
Tammo Spalink86a61c62012-05-25 15:10:35 +0800743 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800744 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800745 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800746 if add_file:
747 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800748 # Require absolute paths since the tar command may change the
749 # directory.
750 if not f.startswith('/'):
751 raise Error('Not an absolute path: %s' % f)
752 if not os.path.exists(f):
753 raise Error('File does not exist: %s' % f)
754 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800755 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800756
757 if ((cmd_result.status == 1) and
758 all((x == '' or
759 'file changed as we read it' in x or
760 "Removing leading `/' from member names" in x)
761 for x in cmd_result.stderr.split('\n'))):
762 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800763 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800764 ignore_stdout=True)
765 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800766 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
767 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800768
Jon Salza88b83b2013-05-27 20:00:35 +0800769 return target_path
770
771_upload_method_cmd_arg = CmdArg(
772 '--upload_method', metavar='METHOD:PARAM',
773 help=('How to perform the upload. METHOD should be one of '
774 '{ftp, shopfloor, ftps, cpfe}.'))
775_add_file_cmd_arg = CmdArg(
776 '--add_file', metavar='FILE', action='append',
777 help='Extra file to include in report (must be an absolute path)')
778
779@Command('upload_report',
780 _upload_method_cmd_arg,
781 _add_file_cmd_arg)
782def UploadReport(options):
783 """Create a report containing key device details."""
784 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
785 device_sn = ro_vpd.get('serial_number', None)
786 if device_sn is None:
787 logging.warning('RO_VPD missing device serial number')
788 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
789 target_path = CreateReportArchive(device_sn)
790
Tammo Spalink86a61c62012-05-25 15:10:35 +0800791 if options.upload_method is None or options.upload_method == 'none':
792 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
793 return
794 method, param = options.upload_method.split(':', 1)
795 if method == 'shopfloor':
796 report_upload.ShopFloorUpload(target_path, param)
797 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700798 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800799 elif method == 'ftps':
800 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
801 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800802 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800803 else:
804 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800805
806
807@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800808 CmdArg('--no_write_protect', action='store_true',
809 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800810 CmdArg('--fast', action='store_true',
811 help='use non-secure but faster wipe method.'),
Ricky Liang43b879b2014-02-24 11:36:55 +0800812 _hwid_version_cmd_arg,
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800813 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700814 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800815 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800816 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800817 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800818 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800819 _hwid_cmd_arg,
820 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800821def Finalize(options):
822 """Verify system readiness and trigger transition into release state.
823
Jon Salzaa3a30e2013-05-15 15:56:28 +0800824 This routine does the following:
825 - Verifies system state (see verify command)
Jon Salzfe9036f2014-01-16 14:11:23 +0800826 - Untars stateful_files.tar.xz, if it exists, in the stateful partition, to
827 initialize files such as the CRX cache
Jon Salzaa3a30e2013-05-15 15:56:28 +0800828 - Modifies firmware bitmaps to match locale
829 - Clears all factory-friendly flags from the GBB
830 - Removes factory-specific entries from RW_VPD (factory.*)
831 - Enables firmware write protection (cannot rollback after this)
832 - Uploads system logs & reports
833 - Sets the necessary boot flags to cause wipe of the factory image on the
834 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800835 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800836 Verify(options)
Jon Salz40b9f822014-07-25 16:39:55 +0800837 LogSourceHashes(options)
Jon Salzfe9036f2014-01-16 14:11:23 +0800838 UntarStatefulFiles(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800839 SetFirmwareBitmapLocale(options)
840 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800841 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800842 if options.no_write_protect:
843 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800844 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800845 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800846 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800847 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800848 UploadReport(options)
849 PrepareWipe(options)
850
851
Ricky Liangc662be32013-12-24 11:50:23 +0800852def VerifyHWIDv3(options):
853 """A simple wrapper that calls out to HWID utils to verify version 3 HWID.
Ricky Liang53390232013-03-08 15:37:57 +0800854
Ricky Liangc662be32013-12-24 11:50:23 +0800855 This is mainly for Gooftool to verify v3 HWID during finalize. For testing
856 and development purposes, please use `hwid` command.
Ricky Liang53390232013-03-08 15:37:57 +0800857 """
Ricky Liangc662be32013-12-24 11:50:23 +0800858 db = GetGooftool(options).db
859 encoded_string = options.hwid or hwid_utils.GetHWIDString()
Ricky Liang7905f272013-03-16 01:57:10 +0800860 if options.probe_results:
Ricky Liangc662be32013-12-24 11:50:23 +0800861 probed_results = yaml.load(open(options.probe_results).read())
Ricky Liang7905f272013-03-16 01:57:10 +0800862 else:
Ricky Liangc662be32013-12-24 11:50:23 +0800863 probed_results = yaml.load(Probe(probe_vpd=True).Encode())
864 vpd = hwid_utils.GetVPD(probed_results)
Ricky Liang53390232013-03-08 15:37:57 +0800865
Ricky Liangc662be32013-12-24 11:50:23 +0800866 event_log.Log('probed_results', probed_results=probed_results)
867 event_log.Log('vpd', vpd=vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800868
Ricky Liangc662be32013-12-24 11:50:23 +0800869 hwid_utils.VerifyHWID(db, encoded_string, probed_results, vpd,
870 rma_mode=options.rma_mode)
Ricky Liang53390232013-03-08 15:37:57 +0800871
Ricky Liangc662be32013-12-24 11:50:23 +0800872 event_log.Log('verified_hwid', hwid=encoded_string)
Ricky Liang53390232013-03-08 15:37:57 +0800873
874
Ricky Liang59611a62013-06-11 13:47:33 +0800875def ParseDecodedHWID(hwid):
876 """Parse the HWID object into a more compact dict.
877
878 Args:
879 hwid: A decoded HWID object.
880
881 Returns:
882 A dict containing the board name, the binary string, and the list of
883 components.
884 """
885 results = {}
886 results['board'] = hwid.database.board
887 results['binary_string'] = hwid.binary_string
888 results['components'] = collections.defaultdict(list)
889 components = hwid.bom.components
890 for comp_cls in sorted(components):
891 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
892 if not probed_values:
893 db_components = hwid.database.components
894 probed_values = db_components.GetComponentAttributes(
895 comp_cls, comp_name).get('values')
896 results['components'][comp_cls].append(
897 {comp_name: probed_values if probed_values else None})
898 # Convert defaultdict to dict.
899 results['components'] = dict(results['components'])
900 return results
901
902
henryhsu44d793a2013-07-20 00:07:38 +0800903@Command('get_firmware_hash',
904 CmdArg('--file', metavar='FILE', help='Firmware File.'))
905def GetFirmwareHash(options):
henryhsuf6f835c2013-07-20 20:49:25 +0800906 """Get firmware hash from a file"""
henryhsu44d793a2013-07-20 00:07:38 +0800907 if os.path.exists(options.file):
908 hashes = CalculateFirmwareHashes(options.file)
909 for section, value_dict in hashes.iteritems():
910 print "%s:" % section
911 for key, value in value_dict.iteritems():
912 print " %s: %s" % (key, value)
913 else:
914 raise Error('File does not exist: %s' % options.file)
915
henryhsuf6f835c2013-07-20 20:49:25 +0800916
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800917def Main():
918 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800919
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800920 options = ParseCmdline(
Ricky Liangc662be32013-12-24 11:50:23 +0800921 ('Perform Google required factory tests. All the HWID-related functions '
922 'provided here are mainly for the deprecated HWID v2. To access HWID '
923 'v3-related utilities, please use `hwid` command.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800924 CmdArg('-l', '--log', metavar='PATH',
925 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800926 CmdArg('--suppress-event-logs', action='store_true',
927 help='Suppress event logging.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800928 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800929 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800930 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
931 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800932 logging.debug('gooftool options: %s', repr(options))
933 try:
934 logging.debug('GOOFTOOL command %r', options.command_name)
935 options.command(options)
936 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
937 except Error, e:
938 logging.exception(e)
939 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
940 except Exception, e:
941 logging.exception(e)
942 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
943
944
945if __name__ == '__main__':
946 Main()