blob: f87129524e530b1d9da5fac8bebe82d00ae34e4d [file] [log] [blame]
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08001#!/usr/bin/python
Jon Salze60307f2014-08-05 16:20:00 +08002# -*- coding: utf-8 -*-
3# Copyright 2014 The Chromium OS Authors. All rights reserved.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08004# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
Jon Salze60307f2014-08-05 16:20:00 +08007# pylint: disable=E1101
8
Tammo Spalink9a96b8a2012-04-03 11:10:41 +08009"""Google Factory Tool.
10
11This tool is indended to be used on factory assembly lines. It
12provides all of the Google required test functionality and must be run
13on each device as part of the assembly process.
14"""
15
Ricky Liang5b4568d2013-04-23 17:15:23 +080016import collections
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080017import logging
18import os
Jon Salz65266432012-07-30 19:02:49 +080019import pipes
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080020import re
21import sys
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080022import threading
Hung-Te Lin6bd16472012-06-20 16:26:47 +080023import time
Jon Salza88b83b2013-05-27 20:00:35 +080024import xmlrpclib
Ricky Liang7905f272013-03-16 01:57:10 +080025import yaml
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080026
Andy Cheng2582d292012-12-04 17:38:28 +080027from tempfile import gettempdir
Tammo Spalink86a61c62012-05-25 15:10:35 +080028
Tammo Spalinka40293e2012-07-04 14:58:56 +080029import factory_common # pylint: disable=W0611
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080030
Andy Cheng0465d132013-03-20 12:12:06 +080031from cros.factory import event_log
Joel Kitchingd3bc2662014-12-16 16:03:32 -080032from cros.factory.common import SetupLogging, Shell
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
Hung-Te Linca61e732014-08-27 10:27:25 +080043from cros.factory.hwdb.yaml_datastore import YamlWrite
Ricky Liangeede7922013-06-19 10:18:41 +080044from cros.factory.hwid import common
Ricky Liangc662be32013-12-24 11:50:23 +080045from cros.factory.hwid import hwid_utils
Jon Salz40b9f822014-07-25 16:39:55 +080046from cros.factory.test import factory
Jon Salzfe9036f2014-01-16 14:11:23 +080047from cros.factory.test.factory import FACTORY_LOG_PATH, DEVICE_STATEFUL_PATH
Jon Salz40b9f822014-07-25 16:39:55 +080048from cros.factory.utils import file_utils
Jon Salzff88c022012-11-03 12:19:58 +080049from cros.factory.utils.process_utils import Spawn
Joel Kitchingd3bc2662014-12-16 16:03:32 -080050from cros.factory.utils.type_utils import Error
Jon Salz8baad8b2013-03-11 20:01:45 +080051from cros.factory.privacy import FilterDict
Tammo Spalink86a61c62012-05-25 15:10:35 +080052
Tammo Spalink5c699832012-07-03 17:50:39 +080053
Tammo Spalink5c699832012-07-03 17:50:39 +080054# TODO(tammo): Replace calls to sys.exit with raise Exit, and maybe
55# treat that specially (as a smoot exit, as opposed to the more
56# verbose output for generic Error).
57
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080058_global_gooftool = None
59_gooftool_lock = threading.Lock()
Tammo Spalink5c699832012-07-03 17:50:39 +080060
Ricky Lianga70a1202013-03-15 15:03:17 +080061def GetGooftool(options):
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080062 global _global_gooftool # pylint: disable=W0603
Ricky Lianga70a1202013-03-15 15:03:17 +080063
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080064 if _global_gooftool is None:
65 with _gooftool_lock:
Ricky Liang43b879b2014-02-24 11:36:55 +080066 hwid_version = getattr(options, 'hwid_version', 3)
67 if hwid_version == 2:
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080068 hwdb_path = getattr(options, 'hwdb_path', None)
69 component_db = (
70 hwid_tool.HardwareDb(options.hwdb_path).comp_db if hwdb_path
71 else None)
72 _global_gooftool = Gooftool(hwid_version=2, component_db=component_db)
Ricky Liang43b879b2014-02-24 11:36:55 +080073 elif hwid_version == 3:
Cheng-Yi Chiang9fc121c2014-01-27 11:23:22 +080074 board = getattr(options, 'board', None)
75 hwdb_path = getattr(options, 'hwdb_path', None)
76 _global_gooftool = Gooftool(hwid_version=3, board=board,
77 hwdb_path=hwdb_path)
78 else:
79 raise Error, 'Invalid HWID version: %r' % options.hwid_version
80
81 return _global_gooftool
Ricky Lianga70a1202013-03-15 15:03:17 +080082
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080083@Command('write_hwid',
84 CmdArg('hwid', metavar='HWID', help='HWID string'))
Andy Chengc92e6f92012-11-20 16:55:53 +080085def WriteHWID(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080086 """Write specified HWID value into the system BB."""
Andy Cheng7a76cb82012-11-19 18:08:19 +080087
Tammo Spalink95c43732012-07-25 15:57:14 -070088 logging.info('writing hwid string %r', options.hwid)
Ricky Lianga70a1202013-03-15 15:03:17 +080089 GetGooftool(options).WriteHWID(options.hwid)
Andy Cheng0465d132013-03-20 12:12:06 +080090 event_log.Log('write_hwid', hwid=options.hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -070091 print 'Wrote HWID: %r' % options.hwid
Tammo Spalink9a96b8a2012-04-03 11:10:41 +080092
93
Ricky Liang53390232013-03-08 15:37:57 +080094_board_cmd_arg = CmdArg(
95 '--board', metavar='BOARD',
96 default=None, help='Board name to test.')
97
Tammo Spalink8fab5312012-05-28 18:33:30 +080098_hwdb_path_cmd_arg = CmdArg(
99 '--hwdb_path', metavar='PATH',
Ricky Liangeede7922013-06-19 10:18:41 +0800100 default=common.DEFAULT_HWID_DATA_PATH,
Tammo Spalink8fab5312012-05-28 18:33:30 +0800101 help='Path to the HWID database.')
102
Tammo Spalink95c43732012-07-25 15:57:14 -0700103_hwid_status_list_cmd_arg = CmdArg(
104 '--status', nargs='*', default=['supported'],
105 help='allow only HWIDs with these status values')
106
Jon Salzce124fb2012-10-02 17:42:03 +0800107_probe_results_cmd_arg = CmdArg(
108 '--probe_results', metavar='RESULTS.yaml',
Ricky Liangc662be32013-12-24 11:50:23 +0800109 help=('Output from "gooftool probe --include_vpd" (used instead of '
Jon Salzce124fb2012-10-02 17:42:03 +0800110 'probing this system).'))
111
Ricky Liang53390232013-03-08 15:37:57 +0800112_device_info_cmd_arg = CmdArg(
Ricky Liangf89f73a2013-03-19 05:00:24 +0800113 '--device_info', metavar='DEVICE_INFO.yaml', default=None,
Ricky Liang53390232013-03-08 15:37:57 +0800114 help='A dict of device info to use instead of fetching from shopfllor '
115 'server.')
116
Jon Salzce124fb2012-10-02 17:42:03 +0800117_hwid_cmd_arg = CmdArg(
118 '--hwid', metavar='HWID',
Ricky Lianga70a1202013-03-15 15:03:17 +0800119 help='HWID to verify (instead of the currently set HWID of this system).')
Jon Salzce124fb2012-10-02 17:42:03 +0800120
Bernie Thompson3c11c872013-07-22 18:22:45 -0700121_rma_mode_cmd_arg = CmdArg(
122 '--rma_mode', action='store_true',
123 help='Enable RMA mode, do not check for deprecated components.')
Tammo Spalink95c43732012-07-25 15:57:14 -0700124
Ricky Liang43b879b2014-02-24 11:36:55 +0800125_hwid_version_cmd_arg = CmdArg(
126 '-i', '--hwid-version', default=3, choices=(2, 3), type=int,
127 help='Version of HWID to operate on. (default: %(default)s)')
128
129
Tammo Spalink95c43732012-07-25 15:57:14 -0700130@Command('best_match_hwids',
Tammo Spalink8fab5312012-05-28 18:33:30 +0800131 _hwdb_path_cmd_arg,
132 CmdArg('-b', '--board', metavar='BOARD',
Tammo Spalink95c43732012-07-25 15:57:14 -0700133 help='optional BOARD name, needed only if data is present '
134 'for more than one'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800135 CmdArg('--bom', metavar='BOM', help='BOM name'),
136 CmdArg('--variant', metavar='VARIANT', help='VARIANT code'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800137 CmdArg('--optimistic', action='store_true',
138 help='do not probe; assume singletons match'),
Tammo Spalink95c43732012-07-25 15:57:14 -0700139 CmdArg('--comps', nargs='*', default=[],
140 help='list of canonical component names'),
141 CmdArg('--missing', nargs='*', default=[],
142 help='list component classes to be assumed missing'),
Tammo Spalink5c699832012-07-03 17:50:39 +0800143 CmdArg('--status', nargs='*', default=['supported'],
Tammo Spalink95c43732012-07-25 15:57:14 -0700144 help='consider only HWIDs within this list of status values'))
145def BestMatchHwids(options):
Ricky Liangc662be32013-12-24 11:50:23 +0800146 """Determine a list of possible HWIDs using provided args and probing.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800147
148 VOLATILE can always be determined by probing. To get a unique
149 result, VARIANT must be specified for all cases where the matching
150 BOM has more than one associated variant code, otherwise all HWID
151 variants will be returned. Both VARIANT and BOM information can
Tammo Spalink95c43732012-07-25 15:57:14 -0700152 alternatively be specified using the --stdin_comps argument, which
153 allows specifying a list of canonical names (one per line) on stdin,
154 one per line. Based on what is known from BOM and stdin_comps,
155 determine a list of components to probe for, and use those probe
156 results to resolve a list of matching HWIDs. If no boms,
157 components, or variant codes are specified, then a list of all HWIDs
Andy Cheng8ece7382012-08-22 16:25:42 +0800158 that match probeable components will be returned.
Tammo Spalink8fab5312012-05-28 18:33:30 +0800159
160 Returns (on stdout): A list of HWIDs that match the available probe
161 results and argument contraints, one per line.
Tammo Spalink70b48a52012-08-08 16:54:51 -0700162
163 Example:
164
165 // Three ways to specify a keyboard (assuming it is a variant component)
166 gooftool best_match_hwids --missing keyboard
167 gooftool best_match_hwids --variant A or
168 gooftool best_match_hwids --comps us_kbd
Tammo Spalink8fab5312012-05-28 18:33:30 +0800169 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800170
Tammo Spalink5c699832012-07-03 17:50:39 +0800171 map(hwid_tool.Validate.Status, options.status)
Tammo Spalink95c43732012-07-25 15:57:14 -0700172 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Tammo Spalink5c699832012-07-03 17:50:39 +0800173 comp_db = hw_db.comp_db
Tammo Spalink3a7e9022012-06-27 14:08:40 +0800174 device = hw_db.GetDevice(options.board)
Tammo Spalink5c699832012-07-03 17:50:39 +0800175 component_spec = hwid_tool.ComponentSpec.New()
Tammo Spalink8fab5312012-05-28 18:33:30 +0800176 if options.bom:
Tammo Spalink5c699832012-07-03 17:50:39 +0800177 device.BomExists(options.bom)
Tammo Spalink01e11722012-07-24 10:17:54 -0700178 component_spec = hwid_tool.CombineComponentSpecs(
Tammo Spalink5c699832012-07-03 17:50:39 +0800179 component_spec, device.boms[options.bom].primary)
Tammo Spalink8fab5312012-05-28 18:33:30 +0800180 if options.variant:
Tammo Spalink5c699832012-07-03 17:50:39 +0800181 device.VariantExists(options.variant)
182 variant_spec = device.variants[options.variant]
Tammo Spalink01e11722012-07-24 10:17:54 -0700183 if hwid_tool.ComponentSpecsConflict(component_spec, variant_spec):
Tammo Spalink95c43732012-07-25 15:57:14 -0700184 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700185 % YamlWrite(sorted(
186 hwid_tool.ComponentSpecClasses(component_spec) &
187 hwid_tool.ComponentSpecClasses(variant_spec))))
Tammo Spalink01e11722012-07-24 10:17:54 -0700188 component_spec = hwid_tool.CombineComponentSpecs(
189 component_spec, variant_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700190 if options.comps or options.missing:
191 map(comp_db.CompExists, options.comps)
192 map(comp_db.CompClassExists, options.missing)
193 extra_comp_spec = comp_db.CreateComponentSpec(
194 components=options.comps,
195 missing=options.missing)
196 print 'cmdline asserted components:\n%s' % extra_comp_spec.Encode()
197 if hwid_tool.ComponentSpecsConflict(component_spec, extra_comp_spec):
198 sys.exit('ERROR: multiple specifications for these components:\n%s'
Tammo Spalink394e4492012-08-01 10:20:30 -0700199 % YamlWrite(sorted(
200 hwid_tool.ComponentSpecClasses(component_spec) &
201 hwid_tool.ComponentSpecClasses(extra_comp_spec))))
Tammo Spalink95c43732012-07-25 15:57:14 -0700202 component_spec = hwid_tool.CombineComponentSpecs(
203 component_spec, extra_comp_spec)
Tammo Spalink01e11722012-07-24 10:17:54 -0700204 spec_classes = hwid_tool.ComponentSpecClasses(component_spec)
Tammo Spalink95c43732012-07-25 15:57:14 -0700205 missing_classes = set(comp_db.all_comp_classes) - spec_classes
Tammo Spalink5c699832012-07-03 17:50:39 +0800206 if missing_classes and not options.optimistic:
Andy Cheng8ece7382012-08-22 16:25:42 +0800207 non_probeable_missing = missing_classes - PROBEABLE_COMPONENT_CLASSES
208 if non_probeable_missing:
Tammo Spalink95c43732012-07-25 15:57:14 -0700209 sys.exit('FAILURE: these classes are necessary, were not specified '
Tammo Spalink70b48a52012-08-08 16:54:51 -0700210 'as inputs, and cannot be probed for:\n%s'
211 'This problem can often be addressed by specifying all of '
212 'the missing components on the command line (see the command '
Andy Cheng8ece7382012-08-22 16:25:42 +0800213 'help).' % YamlWrite(list(non_probeable_missing)))
Tammo Spalink95c43732012-07-25 15:57:14 -0700214 print 'probing for missing classes:'
215 print YamlWrite(list(missing_classes))
216 probe_results = Probe(target_comp_classes=list(missing_classes),
217 probe_volatile=False, probe_initial_config=False)
218 cooked_components = comp_db.MatchComponentProbeValues(
219 probe_results.found_probe_value_map)
220 if cooked_components.unmatched:
221 sys.exit('ERROR: some probed components are unrecognized:\n%s'
222 % YamlWrite(cooked_components.unmatched))
223 probed_comp_spec = comp_db.CreateComponentSpec(
224 components=cooked_components.matched,
225 missing=probe_results.missing_component_classes)
226 component_spec = hwid_tool.CombineComponentSpecs(
227 component_spec, probed_comp_spec)
228 print YamlWrite({'component data used for matching': {
229 'missing component classes': component_spec.classes_missing,
230 'found components': component_spec.components}})
231 component_data = hwid_tool.ComponentData(
232 extant_components=hwid_tool.ComponentSpecCompClassMap(
233 component_spec).keys(),
234 classes_missing=component_spec.classes_missing)
235 match_tree = device.BuildMatchTree(component_data)
236 if not match_tree:
237 sys.exit('FAILURE: NO matching BOMs found')
238 print 'potential BOMs/VARIANTs:'
239 potential_variants = set()
240 potential_volatiles = set()
241 for bom_name, variant_tree in match_tree.items():
242 print ' BOM: %-8s VARIANTS: %s' % (
243 bom_name, ', '.join(sorted(variant_tree)))
244 for variant_code in variant_tree:
245 potential_variants.add(variant_code)
246 for volatile_code in device.volatiles:
247 status = device.GetHwidStatus(bom_name, variant_code, volatile_code)
248 if status in options.status:
249 potential_volatiles.add(volatile_code)
250 print ''
251 if len(potential_variants) == 0:
252 sys.exit('FAILURE: no matching VARIANTs found')
253 if len(potential_volatiles) == 0:
254 sys.exit('FAILURE: no VOLATILEs found for potential matching BOMs/VARIANTS '
255 '(with specified status)')
Tammo Spalink394e4492012-08-01 10:20:30 -0700256 if (options.optimistic and
257 len(match_tree) == 1 and
258 len(potential_variants) == 1 and
259 len(potential_volatiles) == 1):
260 print ('MATCHING HWID: %s' % device.FmtHwid(match_tree.keys().pop(),
261 potential_variants.pop(),
262 potential_volatiles.pop()))
Tammo Spalink5c699832012-07-03 17:50:39 +0800263 return
Tammo Spalink95c43732012-07-25 15:57:14 -0700264 print ('probing VOLATILEs to resolve potential matches: %s\n' %
265 ', '.join(sorted(potential_volatiles)))
266 vol_probe_results = Probe(
267 target_comp_classes=[],
268 probe_volatile=True,
269 probe_initial_config=False)
270 cooked_volatiles = device.MatchVolatileValues(
271 vol_probe_results.found_volatile_values)
272 match_tree = device.BuildMatchTree(
273 component_data, cooked_volatiles.matched_tags)
274 matched_hwids = device.GetMatchTreeHwids(match_tree)
275 if matched_hwids:
276 for hwid in matched_hwids:
Ricky Liang02f3bd72012-09-21 14:33:01 +0800277 if matched_hwids[hwid] in options.status:
278 print 'MATCHING HWID: %s' % hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700279 return
280 print 'exact HWID matching failed, but the following BOMs match: %s' % (
281 ', '.join(sorted(match_tree)))
282 if options.optimistic and len(match_tree) == 1:
283 bom_name = set(match_tree).pop()
Tammo Spalink5c699832012-07-03 17:50:39 +0800284 bom = device.boms[bom_name]
Tammo Spalink95c43732012-07-25 15:57:14 -0700285 variant_matches = match_tree[bom_name]
Tammo Spalink5c699832012-07-03 17:50:39 +0800286 if len(variant_matches) == 1:
287 var_code = set(variant_matches).pop()
288 elif len(bom.variants) == 1:
289 var_code = set(bom.variants).pop()
290 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700291 sys.exit('FAILURE: NO matching HWIDs found; optimistic matching failed '
292 'because there were too many variants to choose from for BOM %r'
293 % bom_name)
294 hwids = [device.FmtHwid(bom_name, var_code, vol_code)
295 for vol_code in device.volatiles
296 if device.GetHwidStatus(bom_name, var_code, vol_code)
297 in options.status]
298 for hwid in hwids:
299 print 'MATCHING HWID: %s' % hwid
Tammo Spalink5c699832012-07-03 17:50:39 +0800300 return
301 else:
Tammo Spalink95c43732012-07-25 15:57:14 -0700302 print ('optimistic matching not attempted because either it was '
303 'not requested, or because the number of BOMs was <> 1\n')
304 sys.exit('FAILURE: NO matching HWIDs found')
Tammo Spalink8fab5312012-05-28 18:33:30 +0800305
306
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800307@Command('probe',
308 CmdArg('--comps', nargs='*',
309 help='List of keys from the component_db registry.'),
Ricky Liangb30da672013-06-14 12:36:34 +0800310 CmdArg('--fast_fw_probe', action='store_true',
311 help='Do a fast probe for EC and main firmware versions only. '
312 'This implies --no_vol and --no_ic.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800313 CmdArg('--no_vol', action='store_true',
314 help='Do not probe volatile data.'),
315 CmdArg('--no_ic', action='store_true',
Jon Salz0f8a6842012-09-25 11:28:22 +0800316 help='Do not probe initial_config data.'),
317 CmdArg('--include_vpd', action='store_true',
318 help='Include VPD data in volatiles.'))
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800319def RunProbe(options):
320 """Print yaml-formatted breakdown of probed device properties."""
Ricky Lianga70a1202013-03-15 15:03:17 +0800321 print GetGooftool(options).Probe(
322 target_comp_classes=options.comps,
Ricky Liangb30da672013-06-14 12:36:34 +0800323 fast_fw_probe=options.fast_fw_probe,
Ricky Lianga70a1202013-03-15 15:03:17 +0800324 probe_volatile=not options.no_vol,
325 probe_initial_config=not options.no_ic,
326 probe_vpd=options.include_vpd).Encode()
Ricky Liang53390232013-03-08 15:37:57 +0800327
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800328
Tammo Spalink214caf42012-05-28 10:45:00 +0800329@Command('verify_components',
330 _hwdb_path_cmd_arg,
Tammo Spalink5c699832012-07-03 17:50:39 +0800331 CmdArg('target_comps', nargs='*'))
Tammo Spalink214caf42012-05-28 10:45:00 +0800332def VerifyComponents(options):
Andy Cheng8ece7382012-08-22 16:25:42 +0800333 """Verify that probeable components all match entries in the component_db.
Tammo Spalink214caf42012-05-28 10:45:00 +0800334
Tammo Spalink5c699832012-07-03 17:50:39 +0800335 Probe for each component class in the target_comps and verify
Tammo Spalink214caf42012-05-28 10:45:00 +0800336 that a corresponding match exists in the component_db -- make sure
337 that these components are present, that they have been approved, but
338 do not check against any specific BOM/HWID configurations.
339 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800340
Andy Chengc531e2f2012-10-15 19:09:17 +0800341 try:
Ricky Lianga70a1202013-03-15 15:03:17 +0800342 result = GetGooftool(options).VerifyComponents(
Andy Chengc531e2f2012-10-15 19:09:17 +0800343 options.target_comps)
344 except ValueError, e:
345 sys.exit(e)
346
Ricky Liang53390232013-03-08 15:37:57 +0800347 PrintVerifyComponentsResults(result)
348
349
350def PrintVerifyComponentsResults(result):
351 """Prints out the results of VerifyComponents method call.
352
353 Groups the results into two groups: 'matches' and 'errors', and prints out
354 their values.
355 """
Andy Chengc531e2f2012-10-15 19:09:17 +0800356 # group by matches and errors
Tammo Spalink214caf42012-05-28 10:45:00 +0800357 matches = []
Andy Chengc531e2f2012-10-15 19:09:17 +0800358 errors = []
359 for result_list in result.values():
360 for component_name, _, error in result_list:
361 if component_name:
362 matches.append(component_name)
Tammo Spalink214caf42012-05-28 10:45:00 +0800363 else:
Andy Chengc531e2f2012-10-15 19:09:17 +0800364 errors.append(error)
365
Andy Cheng228a8c92012-08-27 10:53:57 +0800366 if matches:
367 print 'found probeable components:\n %s' % '\n '.join(matches)
Tammo Spalink214caf42012-05-28 10:45:00 +0800368 if errors:
Andy Cheng228a8c92012-08-27 10:53:57 +0800369 print '\nerrors:\n %s' % '\n '.join(errors)
370 sys.exit('\ncomponent verification FAILURE')
Tammo Spalink214caf42012-05-28 10:45:00 +0800371 else:
Andy Cheng228a8c92012-08-27 10:53:57 +0800372 print "\ncomponent verification SUCCESS"
Tammo Spalink214caf42012-05-28 10:45:00 +0800373
374
Ricky Liang43b879b2014-02-24 11:36:55 +0800375@Command('verify_hwid_v2',
Tammo Spalink95c43732012-07-25 15:57:14 -0700376 _hwid_status_list_cmd_arg,
Jon Salz0f8a6842012-09-25 11:28:22 +0800377 _hwdb_path_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800378 _probe_results_cmd_arg,
379 _hwid_cmd_arg)
Ricky Liang43b879b2014-02-24 11:36:55 +0800380def VerifyHWIDv2(options):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800381 """Verify system HWID properties match probed device properties.
382
383 First probe components, volatile and initial_config parameters for
384 the DUT. Then use the available device data to produce a list of
385 candidate HWIDs. Then verify the HWID from the DUT is present in
386 that list. Then verify that the DUT initial config values match
387 those specified for its HWID. Finally, verify that VPD contains all
388 the necessary fields as specified by the board data, and when
389 possible verify that values are legitimate.
390 """
Ricky Liangf7857c12012-09-17 13:34:41 +0800391 def VerifyVpd(ro_vpd_keys, rw_vpd_keys):
Tammo Spalink5c699832012-07-03 17:50:39 +0800392 for key in ro_vpd_keys:
393 if key not in ro_vpd:
Ricky Liangf7857c12012-09-17 13:34:41 +0800394 sys.exit('Missing required RO VPD field: %s' % key)
Tammo Spalink01e11722012-07-24 10:17:54 -0700395 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800396 value = ro_vpd[key]
Ricky Liangf7857c12012-09-17 13:34:41 +0800397 if (known_valid_values is not None) and (value not in known_valid_values):
398 sys.exit('Invalid RO VPD entry : key %r, value %r' % (key, value))
Ricky Liangf7857c12012-09-17 13:34:41 +0800399 for key in rw_vpd_keys:
400 if key not in rw_vpd:
401 sys.exit('Missing required RW VPD field: %s' % key)
402 known_valid_values = KNOWN_VPD_FIELD_DATA.get(key, None)
403 value = rw_vpd[key]
404 if (known_valid_values is not None) and (value not in known_valid_values):
405 sys.exit('Invalid RW VPD entry : key %r, value %r' % (key, value))
Andy Cheng0465d132013-03-20 12:12:06 +0800406 event_log.Log('vpd', ro_vpd=FilterDict(ro_vpd), rw_vpd=FilterDict(rw_vpd))
Tammo Spalink5c699832012-07-03 17:50:39 +0800407 map(hwid_tool.Validate.Status, options.status)
Jon Salz0f8a6842012-09-25 11:28:22 +0800408
Jon Salz81350812012-10-11 16:13:22 +0800409 if not options.hwid or not options.probe_results:
410 main_fw_file = crosfw.LoadMainFirmware().GetFileName()
Jon Salz0f8a6842012-09-25 11:28:22 +0800411
412 if options.hwid:
413 hwid_str = options.hwid
414 else:
415 gbb_result = Shell('gbb_utility -g --hwid %s' % main_fw_file).stdout
416 hwid_str = re.findall(r'hardware_id:(.*)', gbb_result)[0].strip()
Tammo Spalink95c43732012-07-25 15:57:14 -0700417 hwid = hwid_tool.ParseHwid(hwid_str)
Tammo Spalink5c699832012-07-03 17:50:39 +0800418 hw_db = hwid_tool.HardwareDb(options.hwdb_path)
Jon Salz0f8a6842012-09-25 11:28:22 +0800419 print 'Verifying HWID: %r\n' % hwid.hwid
Tammo Spalink95c43732012-07-25 15:57:14 -0700420 device = hw_db.GetDevice(hwid.board)
421 hwid_status = device.GetHwidStatus(hwid.bom, hwid.variant, hwid.volatile)
422 if hwid_status not in options.status:
Tammo Spalink5c699832012-07-03 17:50:39 +0800423 sys.exit('HWID status must be one of [%s], found %r' %
Hung-Te Lin4f5beb12012-08-20 14:48:06 +0800424 (', '.join(options.status), hwid_status))
Jon Salz0f8a6842012-09-25 11:28:22 +0800425 if options.probe_results:
426 # Pull in probe results (including VPD data) from the given file
427 # rather than probing the current system.
428 probe_results = hwid_tool.ProbeResults.Decode(
429 open(options.probe_results).read())
430 ro_vpd = {}
431 rw_vpd = {}
432 for k, v in probe_results.found_volatile_values.items():
433 match = re.match('^vpd\.(ro|rw)\.(\w+)$', k)
434 if match:
435 del probe_results.found_volatile_values[k]
436 (ro_vpd if match.group(1) == 'ro' else rw_vpd)[match.group(2)] = v
437 else:
438 probe_results = Probe()
439 ro_vpd = ReadRoVpd(main_fw_file)
440 rw_vpd = ReadRwVpd(main_fw_file)
Tammo Spalink95c43732012-07-25 15:57:14 -0700441 cooked_components = hw_db.comp_db.MatchComponentProbeValues(
442 probe_results.found_probe_value_map)
443 cooked_volatiles = device.MatchVolatileValues(
444 probe_results.found_volatile_values)
445 cooked_initial_configs = device.MatchInitialConfigValues(
446 probe_results.initial_configs)
447 component_data = hwid_tool.ComponentData(
448 extant_components=cooked_components.matched,
449 classes_missing=probe_results.missing_component_classes)
450 match_tree = device.BuildMatchTree(
451 component_data, cooked_volatiles.matched_tags)
452 matched_hwids = device.GetMatchTreeHwids(match_tree)
453 print 'HWID status: %s\n' % hwid_status
454 print 'probed system components:'
455 print YamlWrite(cooked_components.__dict__)
456 print 'missing component classes:'
457 print YamlWrite(probe_results.missing_component_classes)
458 print 'probed volatiles:'
459 print YamlWrite(cooked_volatiles.__dict__)
460 print 'probed initial_configs:'
461 print YamlWrite(cooked_initial_configs)
462 print 'hwid match tree:'
463 print YamlWrite(match_tree)
Andy Cheng0465d132013-03-20 12:12:06 +0800464 event_log.Log(
Tammo Spalink5c699832012-07-03 17:50:39 +0800465 'probe',
Tammo Spalink95c43732012-07-25 15:57:14 -0700466 found_components=cooked_components.__dict__,
467 missing_component_classes=probe_results.missing_component_classes,
468 volatiles=cooked_volatiles.__dict__,
469 initial_configs=cooked_initial_configs)
470 if hwid.hwid not in matched_hwids:
Tammo Spalink5c699832012-07-03 17:50:39 +0800471 err_msg = 'HWID verification FAILED.\n'
Tammo Spalink95c43732012-07-25 15:57:14 -0700472 if cooked_components.unmatched:
Tammo Spalink5c699832012-07-03 17:50:39 +0800473 sys.exit(err_msg + 'some components could not be indentified:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700474 YamlWrite(cooked_components.unmatched))
475 if not match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800476 sys.exit(err_msg + 'no matching boms were found for components:\n%s' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700477 component_data.Encode())
478 if hwid.bom not in match_tree:
Tammo Spalink5c699832012-07-03 17:50:39 +0800479 sys.exit(err_msg + 'matching boms [%s] do not include target bom %r' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700480 (', '.join(sorted(match_tree)), hwid.bom))
481 err_msg += 'target bom %r matches components' % hwid.bom
482 if hwid.bom not in device.IntersectBomsAndInitialConfigs(
483 cooked_initial_configs):
Tammo Spalink5c699832012-07-03 17:50:39 +0800484 sys.exit(err_msg + ', but failed initial config verification')
Tammo Spalink95c43732012-07-25 15:57:14 -0700485 matched_variants = match_tree.get(hwid.bom, {})
486 if hwid.variant not in matched_variants:
Tammo Spalink5c699832012-07-03 17:50:39 +0800487 sys.exit(err_msg + ', but target variant_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700488 hwid.variant)
489 matched_volatiles = matched_variants.get(hwid.variant, {})
490 if hwid.volatile not in matched_volatiles:
Tammo Spalink5c699832012-07-03 17:50:39 +0800491 sys.exit(err_msg + ', but target volatile_code %r did not match' %
Tammo Spalink95c43732012-07-25 15:57:14 -0700492 hwid.volatile)
493 found_status = matched_volatiles.get(hwid.volatile, None)
Tammo Spalink5c699832012-07-03 17:50:39 +0800494 sys.exit(err_msg + ', but hwid status %r was unacceptable' % found_status)
Ricky Liangf7857c12012-09-17 13:34:41 +0800495 VerifyVpd(device.vpd_ro_fields, device.vpd_rw_fields)
Andy Cheng0465d132013-03-20 12:12:06 +0800496 event_log.Log('verified_hwid', hwid=hwid)
Tammo Spalink95c43732012-07-25 15:57:14 -0700497 print 'Verification SUCCESS!'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800498
499
500@Command('verify_keys')
Tammo Spalink01e11722012-07-24 10:17:54 -0700501def VerifyKeys(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800502 """Verify keys in firmware and SSD match."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800503
Ricky Lianga70a1202013-03-15 15:03:17 +0800504 return GetGooftool(options).VerifyKeys()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800505
506
507@Command('set_fw_bitmap_locale')
Tammo Spalink01e11722012-07-24 10:17:54 -0700508def SetFirmwareBitmapLocale(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800509 """Use VPD locale value to set firmware bitmap default language."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800510
Ricky Lianga70a1202013-03-15 15:03:17 +0800511 (index, locale) = GetGooftool(options).SetFirmwareBitmapLocale()
Andy Cheng2582d292012-12-04 17:38:28 +0800512 logging.info('Firmware bitmap initial locale set to %d (%s).',
513 index, locale)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800514
515
516@Command('verify_system_time')
Tammo Spalink01e11722012-07-24 10:17:54 -0700517def VerifySystemTime(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800518 """Verify system time is later than release filesystem creation time."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800519
Ricky Lianga70a1202013-03-15 15:03:17 +0800520 return GetGooftool(options).VerifySystemTime()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800521
522
523@Command('verify_rootfs')
Tammo Spalink01e11722012-07-24 10:17:54 -0700524def VerifyRootFs(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800525 """Verify rootfs on SSD is valid by checking hash."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800526
Ricky Lianga70a1202013-03-15 15:03:17 +0800527 return GetGooftool(options).VerifyRootFs()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800528
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800529@Command('verify_tpm')
530def VerifyTPM(options): # pylint: disable=W0613
531 """Verify TPM is cleared."""
532
533 return GetGooftool(options).VerifyTPM()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800534
Hung-Te Lindd708d42014-07-11 17:05:01 +0800535@Command('verify_me_locked')
536def VerifyManagementEngineLocked(options): # pylint: disable=W0613
537 """Verify Managment Engine is locked."""
538
539 return GetGooftool(options).VerifyManagementEngineLocked()
540
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800541@Command('verify_switch_wp')
Andy Chengc92e6f92012-11-20 16:55:53 +0800542def VerifyWPSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800543 """Verify hardware write protection switch is enabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800544
Ricky Lianga70a1202013-03-15 15:03:17 +0800545 GetGooftool(options).VerifyWPSwitch()
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800546
547
548@Command('verify_switch_dev')
Tammo Spalink01e11722012-07-24 10:17:54 -0700549def VerifyDevSwitch(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800550 """Verify developer switch is disabled."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800551
Ricky Lianga70a1202013-03-15 15:03:17 +0800552 if GetGooftool(options).CheckDevSwitchForDisabling():
Hung-Te Lind7d34722012-07-26 16:48:35 +0800553 logging.warn('VerifyDevSwitch: No physical switch.')
Andy Cheng0465d132013-03-20 12:12:06 +0800554 event_log.Log('switch_dev', type='virtual switch')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800555
556
Jon Salzadd90d32014-04-29 16:16:27 +0800557@Command('verify_branding')
558def VerifyBranding(options): # pylint: disable=W0613
559 """Verify that branding fields are properly set.
560
561 customization_id, if set in the RO VPD, must be of the correct format.
562
563 rlz_brand_code must be set either in the RO VPD or OEM partition, and must
564 be of the correct format.
565 """
566 return GetGooftool(options).VerifyBranding()
567
568
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800569@Command('write_protect')
Tammo Spalink01e11722012-07-24 10:17:54 -0700570def EnableFwWp(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800571 """Enable then verify firmware write protection."""
572
Hung-Te Linb21c6682012-08-01 13:53:57 +0800573 def CalculateLegacyRange(fw_type, length, section_data,
574 section_name):
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800575 ro_size = length / 2
576 ro_a = int(section_data[0] / ro_size)
577 ro_b = int((section_data[0] + section_data[1] - 1) / ro_size)
578 if ro_a != ro_b:
579 raise Error("%s firmware section %s has illegal size" %
Hung-Te Linb21c6682012-08-01 13:53:57 +0800580 (fw_type, section_name))
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800581 ro_offset = ro_a * ro_size
582 return (ro_offset, ro_size)
583
584 def WriteProtect(fw_file_path, fw_type, legacy_section):
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800585 """Calculate protection size, then invoke flashrom.
586
587 Our supported chips only allow write protecting half their total
588 size, so we parition the flash chipset space accordingly.
589 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800590
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800591 raw_image = open(fw_file_path, 'rb').read()
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800592 wp_section = 'WP_RO'
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800593 image = crosfw.FirmwareImage(raw_image)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800594 if image.has_section(wp_section):
595 section_data = image.get_section_area(wp_section)
596 ro_offset = section_data[0]
597 ro_size = section_data[1]
598 elif image.has_section(legacy_section):
599 section_data = image.get_section_area(legacy_section)
600 (ro_offset, ro_size) = CalculateLegacyRange(
Hung-Te Linb21c6682012-08-01 13:53:57 +0800601 fw_type, len(raw_image), section_data, legacy_section)
Hung-Te Lin7ea39e82012-07-31 18:39:33 +0800602 else:
603 raise Error('could not find %s firmware section %s or %s' %
604 (fw_type, wp_section, legacy_section))
605
606 logging.debug('write protecting %s [off=%x size=%x]', fw_type,
607 ro_offset, ro_size)
608 crosfw.Flashrom(fw_type).EnableWriteProtection(ro_offset, ro_size)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800609
610 WriteProtect(crosfw.LoadMainFirmware().GetFileName(), 'main', 'RO_SECTION')
Andy Cheng0465d132013-03-20 12:12:06 +0800611 event_log.Log('wp', fw='main')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800612 ec_fw_file = crosfw.LoadEcFirmware().GetFileName()
613 if ec_fw_file is not None:
614 WriteProtect(ec_fw_file, 'ec', 'EC_RO')
Andy Cheng0465d132013-03-20 12:12:06 +0800615 event_log.Log('wp', fw='ec')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800616 else:
617 logging.warning('EC not write protected (seems there is no EC flash).')
618
619
620@Command('clear_gbb_flags')
Andy Chengc92e6f92012-11-20 16:55:53 +0800621def ClearGBBFlags(options): # pylint: disable=W0613
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800622 """Zero out the GBB flags, in preparation for transition to release state.
623
624 No GBB flags are set in release/shipping state, but they are useful
625 for factory/development. See "gbb_utility --flags" for details.
626 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800627
Ricky Lianga70a1202013-03-15 15:03:17 +0800628 GetGooftool(options).ClearGBBFlags()
Andy Cheng0465d132013-03-20 12:12:06 +0800629 event_log.Log('clear_gbb_flags')
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800630
631
Jon Salzaa3a30e2013-05-15 15:56:28 +0800632@Command('clear_factory_vpd_entries')
633def ClearFactoryVPDEntries(options): # pylint: disable=W0613
634 """Clears factory.* items in the RW VPD."""
635 entries = GetGooftool(options).ClearFactoryVPDEntries()
636 event_log.Log('clear_factory_vpd_entries', entries=FilterDict(entries))
637
638
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800639@Command('prepare_wipe',
640 CmdArg('--fast', action='store_true',
641 help='use non-secure but faster wipe method.'))
642def PrepareWipe(options):
643 """Prepare system for transition to release state in next reboot."""
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800644
Ricky Lianga70a1202013-03-15 15:03:17 +0800645 GetGooftool(options).PrepareWipe(options.fast)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800646
647@Command('verify',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800648 CmdArg('--no_write_protect', action='store_true',
649 help='Do not check write protection switch state.'),
Ricky Liang43b879b2014-02-24 11:36:55 +0800650 _hwid_version_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700651 _hwid_status_list_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800652 _hwdb_path_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800653 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800654 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800655 _hwid_cmd_arg,
656 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800657def Verify(options):
658 """Verifies if whole factory process is ready for finalization.
659
660 This routine performs all the necessary checks to make sure the
661 device is ready to be finalized, but does not modify state. These
662 checks include dev switch, firmware write protection switch, hwid,
663 system time, keys, and root file system.
664 """
Andy Cheng7a76cb82012-11-19 18:08:19 +0800665
Hung-Te Lin6d827542012-07-19 11:50:41 +0800666 if not options.no_write_protect:
Ricky Lianga70a1202013-03-15 15:03:17 +0800667 VerifyWPSwitch(options)
Hung-Te Lindd708d42014-07-11 17:05:01 +0800668 VerifyManagementEngineLocked(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800669 VerifyDevSwitch(options)
670 if options.hwid_version == 2:
Ricky Liang43b879b2014-02-24 11:36:55 +0800671 VerifyHWIDv2(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800672 elif options.hwid_version == 3:
Ricky Liangc662be32013-12-24 11:50:23 +0800673 VerifyHWIDv3(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800674 else:
675 raise Error, 'Invalid HWID version: %r' % options.hwid_version
676 VerifySystemTime(options)
677 VerifyKeys(options)
678 VerifyRootFs(options)
Cheng-Yi Chiang676b5292013-06-18 12:05:33 +0800679 VerifyTPM(options)
Jon Salzadd90d32014-04-29 16:16:27 +0800680 VerifyBranding(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800681
Jon Salzfe9036f2014-01-16 14:11:23 +0800682@Command('untar_stateful_files')
Hung-Te Lin388bce22014-06-03 19:56:40 +0800683def UntarStatefulFiles(unused_options):
Jon Salzfe9036f2014-01-16 14:11:23 +0800684 """Untars stateful files from stateful_files.tar.xz on stateful partition.
685
686 If that file does not exist (which should only be R30 and earlier),
687 this is a no-op.
688 """
689 tar_file = os.path.join(DEVICE_STATEFUL_PATH, 'stateful_files.tar.xz')
690 if os.path.exists(tar_file):
691 Spawn(['tar', 'xf', tar_file], cwd=DEVICE_STATEFUL_PATH,
692 log=True, check_call=True)
693 else:
694 logging.warning('No stateful files at %s', tar_file)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800695
Jon Salz40b9f822014-07-25 16:39:55 +0800696
697@Command('log_source_hashes')
698def LogSourceHashes(options): # pylint: disable=W0613
699 """Logs hashes of source files in the factory toolkit."""
Jon Salze60307f2014-08-05 16:20:00 +0800700 # WARNING: The following line is necessary to validate the integrity
701 # of the factory software. Do not remove or modify it.
702 #
703 # 警告:此行会验证工厂软件的完整性,禁止删除或修改。
Jon Salz40b9f822014-07-25 16:39:55 +0800704 event_log.Log(
705 'source_hashes',
Jon Salz9596ae02014-07-29 14:25:49 +0800706 **file_utils.HashSourceTree(os.path.join(factory.FACTORY_PATH, 'py')))
Jon Salz40b9f822014-07-25 16:39:55 +0800707
708
Tammo Spalink86a61c62012-05-25 15:10:35 +0800709@Command('log_system_details')
Tammo Spalink01e11722012-07-24 10:17:54 -0700710def LogSystemDetails(options): # pylint: disable=W0613
Tammo Spalink86a61c62012-05-25 15:10:35 +0800711 """Write miscellaneous system details to the event log."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800712
Ricky Liang43b879b2014-02-24 11:36:55 +0800713 event_log.Log('system_details', **GetGooftool(options).GetSystemDetails())
Tammo Spalink86a61c62012-05-25 15:10:35 +0800714
715
Jon Salza88b83b2013-05-27 20:00:35 +0800716def CreateReportArchiveBlob(*args, **kwargs):
717 """Creates a report archive and returns it as a blob.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800718
Jon Salza88b83b2013-05-27 20:00:35 +0800719 Args:
720 See CreateReportArchive.
Andy Cheng7a76cb82012-11-19 18:08:19 +0800721
Jon Salza88b83b2013-05-27 20:00:35 +0800722 Returns:
723 An xmlrpclib.Binary object containing a .tar.xz file.
724 """
725 with open(CreateReportArchive(*args, **kwargs)) as f:
726 return xmlrpclib.Binary(f.read())
727
728
729def CreateReportArchive(device_sn=None, add_file=None):
730 """Creates a report archive in a temporary directory.
731
732 Args:
733 device_sn: The device serial number (optional).
734 add_file: A list of files to add (optional).
735
736 Returns:
737 Path to the archive.
738 """
Hung-Te Lin6bd16472012-06-20 16:26:47 +0800739 def NormalizeAsFileName(token):
740 return re.sub(r'\W+', '', token).strip()
Jon Salza88b83b2013-05-27 20:00:35 +0800741
742 target_name = '%s%s.tar.xz' % (
743 time.strftime('%Y%m%dT%H%M%SZ',
744 time.gmtime()),
745 ("" if device_sn is None else
746 "_" + NormalizeAsFileName(device_sn)))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800747 target_path = os.path.join(gettempdir(), target_name)
Jon Salza88b83b2013-05-27 20:00:35 +0800748
Tammo Spalink86a61c62012-05-25 15:10:35 +0800749 # Intentionally ignoring dotfiles in EVENT_LOG_DIR.
Andy Cheng0465d132013-03-20 12:12:06 +0800750 tar_cmd = 'cd %s ; tar cJf %s *' % (event_log.EVENT_LOG_DIR, target_path)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800751 tar_cmd += ' --add-file %s' % FACTORY_LOG_PATH
Jon Salza88b83b2013-05-27 20:00:35 +0800752 if add_file:
753 for f in add_file:
Jon Salz65266432012-07-30 19:02:49 +0800754 # Require absolute paths since the tar command may change the
755 # directory.
756 if not f.startswith('/'):
757 raise Error('Not an absolute path: %s' % f)
758 if not os.path.exists(f):
759 raise Error('File does not exist: %s' % f)
760 tar_cmd += ' --add-file %s' % pipes.quote(f)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800761 cmd_result = Shell(tar_cmd)
Jon Salzff88c022012-11-03 12:19:58 +0800762
763 if ((cmd_result.status == 1) and
764 all((x == '' or
765 'file changed as we read it' in x or
766 "Removing leading `/' from member names" in x)
767 for x in cmd_result.stderr.split('\n'))):
768 # That's OK. Make sure it's valid though.
Vic Yang85199e72013-01-28 14:33:11 +0800769 Spawn(['tar', 'tfJ', target_path], check_call=True, log=True,
Jon Salzff88c022012-11-03 12:19:58 +0800770 ignore_stdout=True)
771 elif not cmd_result.success:
Tammo Spalink86a61c62012-05-25 15:10:35 +0800772 raise Error('unable to tar event logs, cmd %r failed, stderr: %r' %
773 (tar_cmd, cmd_result.stderr))
Jon Salzff88c022012-11-03 12:19:58 +0800774
Jon Salza88b83b2013-05-27 20:00:35 +0800775 return target_path
776
777_upload_method_cmd_arg = CmdArg(
778 '--upload_method', metavar='METHOD:PARAM',
779 help=('How to perform the upload. METHOD should be one of '
780 '{ftp, shopfloor, ftps, cpfe}.'))
781_add_file_cmd_arg = CmdArg(
782 '--add_file', metavar='FILE', action='append',
783 help='Extra file to include in report (must be an absolute path)')
784
785@Command('upload_report',
786 _upload_method_cmd_arg,
787 _add_file_cmd_arg)
788def UploadReport(options):
789 """Create a report containing key device details."""
790 ro_vpd = ReadRoVpd(crosfw.LoadMainFirmware().GetFileName())
791 device_sn = ro_vpd.get('serial_number', None)
792 if device_sn is None:
793 logging.warning('RO_VPD missing device serial number')
794 device_sn = 'MISSING_SN_' + event_log.TimedUuid()
795 target_path = CreateReportArchive(device_sn)
796
Tammo Spalink86a61c62012-05-25 15:10:35 +0800797 if options.upload_method is None or options.upload_method == 'none':
798 logging.warning('REPORT UPLOAD SKIPPED (report left at %s)', target_path)
799 return
800 method, param = options.upload_method.split(':', 1)
801 if method == 'shopfloor':
802 report_upload.ShopFloorUpload(target_path, param)
803 elif method == 'ftp':
Jay Kim360c1dd2012-06-25 10:58:11 -0700804 report_upload.FtpUpload(target_path, 'ftp:' + param)
Tammo Spalink86a61c62012-05-25 15:10:35 +0800805 elif method == 'ftps':
806 report_upload.CurlUrlUpload(target_path, '--ftp-ssl-reqd ftp:%s' % param)
807 elif method == 'cpfe':
Shawn Nematbakhsh3404a092013-01-28 16:49:09 -0800808 report_upload.CpfeUpload(target_path, pipes.quote(param))
Tammo Spalink86a61c62012-05-25 15:10:35 +0800809 else:
810 raise Error('unknown report upload method %r', method)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800811
812
813@Command('finalize',
Hung-Te Lin6d827542012-07-19 11:50:41 +0800814 CmdArg('--no_write_protect', action='store_true',
815 help='Do not enable firmware write protection.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800816 CmdArg('--fast', action='store_true',
817 help='use non-secure but faster wipe method.'),
Ricky Liang43b879b2014-02-24 11:36:55 +0800818 _hwid_version_cmd_arg,
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800819 _hwdb_path_cmd_arg,
Tammo Spalink95c43732012-07-25 15:57:14 -0700820 _hwid_status_list_cmd_arg,
Jon Salz65266432012-07-30 19:02:49 +0800821 _upload_method_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800822 _add_file_cmd_arg,
Ricky Lianga70a1202013-03-15 15:03:17 +0800823 _board_cmd_arg,
Jon Salzce124fb2012-10-02 17:42:03 +0800824 _probe_results_cmd_arg,
Cheng-Yi Chiang406ad912013-11-14 16:51:33 +0800825 _hwid_cmd_arg,
826 _rma_mode_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800827def Finalize(options):
828 """Verify system readiness and trigger transition into release state.
829
Jon Salzaa3a30e2013-05-15 15:56:28 +0800830 This routine does the following:
831 - Verifies system state (see verify command)
Jon Salzfe9036f2014-01-16 14:11:23 +0800832 - Untars stateful_files.tar.xz, if it exists, in the stateful partition, to
833 initialize files such as the CRX cache
Jon Salzaa3a30e2013-05-15 15:56:28 +0800834 - Modifies firmware bitmaps to match locale
835 - Clears all factory-friendly flags from the GBB
836 - Removes factory-specific entries from RW_VPD (factory.*)
837 - Enables firmware write protection (cannot rollback after this)
838 - Uploads system logs & reports
839 - Sets the necessary boot flags to cause wipe of the factory image on the
840 next boot.
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800841 """
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800842 Verify(options)
Jon Salz40b9f822014-07-25 16:39:55 +0800843 LogSourceHashes(options)
Jon Salzfe9036f2014-01-16 14:11:23 +0800844 UntarStatefulFiles(options)
Ricky Lianga70a1202013-03-15 15:03:17 +0800845 SetFirmwareBitmapLocale(options)
846 ClearGBBFlags(options)
Jon Salzaa3a30e2013-05-15 15:56:28 +0800847 ClearFactoryVPDEntries(options)
Hung-Te Lin6d827542012-07-19 11:50:41 +0800848 if options.no_write_protect:
849 logging.warn('WARNING: Firmware Write Protection is SKIPPED.')
Andy Cheng0465d132013-03-20 12:12:06 +0800850 event_log.Log('wp', fw='both', status='skipped')
Hung-Te Lin6d827542012-07-19 11:50:41 +0800851 else:
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800852 EnableFwWp({})
Jon Salza0f58e02012-05-29 19:33:39 +0800853 LogSystemDetails(options)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800854 UploadReport(options)
855 PrepareWipe(options)
856
857
Ricky Liangc662be32013-12-24 11:50:23 +0800858def VerifyHWIDv3(options):
859 """A simple wrapper that calls out to HWID utils to verify version 3 HWID.
Ricky Liang53390232013-03-08 15:37:57 +0800860
Ricky Liangc662be32013-12-24 11:50:23 +0800861 This is mainly for Gooftool to verify v3 HWID during finalize. For testing
862 and development purposes, please use `hwid` command.
Ricky Liang53390232013-03-08 15:37:57 +0800863 """
Ricky Liangc662be32013-12-24 11:50:23 +0800864 db = GetGooftool(options).db
865 encoded_string = options.hwid or hwid_utils.GetHWIDString()
Ricky Liang7905f272013-03-16 01:57:10 +0800866 if options.probe_results:
Ricky Liangc662be32013-12-24 11:50:23 +0800867 probed_results = yaml.load(open(options.probe_results).read())
Ricky Liang7905f272013-03-16 01:57:10 +0800868 else:
Ricky Liangc662be32013-12-24 11:50:23 +0800869 probed_results = yaml.load(Probe(probe_vpd=True).Encode())
870 vpd = hwid_utils.GetVPD(probed_results)
Ricky Liang53390232013-03-08 15:37:57 +0800871
Ricky Liangc662be32013-12-24 11:50:23 +0800872 event_log.Log('probed_results', probed_results=probed_results)
873 event_log.Log('vpd', vpd=vpd)
Ricky Liang53390232013-03-08 15:37:57 +0800874
Ricky Liangc662be32013-12-24 11:50:23 +0800875 hwid_utils.VerifyHWID(db, encoded_string, probed_results, vpd,
876 rma_mode=options.rma_mode)
Ricky Liang53390232013-03-08 15:37:57 +0800877
Ricky Liangc662be32013-12-24 11:50:23 +0800878 event_log.Log('verified_hwid', hwid=encoded_string)
Ricky Liang53390232013-03-08 15:37:57 +0800879
880
Ricky Liang59611a62013-06-11 13:47:33 +0800881def ParseDecodedHWID(hwid):
882 """Parse the HWID object into a more compact dict.
883
884 Args:
885 hwid: A decoded HWID object.
886
887 Returns:
888 A dict containing the board name, the binary string, and the list of
889 components.
890 """
891 results = {}
892 results['board'] = hwid.database.board
893 results['binary_string'] = hwid.binary_string
894 results['components'] = collections.defaultdict(list)
895 components = hwid.bom.components
896 for comp_cls in sorted(components):
897 for (comp_name, probed_values, _) in sorted(components[comp_cls]):
898 if not probed_values:
899 db_components = hwid.database.components
900 probed_values = db_components.GetComponentAttributes(
901 comp_cls, comp_name).get('values')
902 results['components'][comp_cls].append(
903 {comp_name: probed_values if probed_values else None})
904 # Convert defaultdict to dict.
905 results['components'] = dict(results['components'])
906 return results
907
908
henryhsu44d793a2013-07-20 00:07:38 +0800909@Command('get_firmware_hash',
910 CmdArg('--file', metavar='FILE', help='Firmware File.'))
911def GetFirmwareHash(options):
henryhsuf6f835c2013-07-20 20:49:25 +0800912 """Get firmware hash from a file"""
henryhsu44d793a2013-07-20 00:07:38 +0800913 if os.path.exists(options.file):
914 hashes = CalculateFirmwareHashes(options.file)
915 for section, value_dict in hashes.iteritems():
916 print "%s:" % section
917 for key, value in value_dict.iteritems():
918 print " %s: %s" % (key, value)
919 else:
920 raise Error('File does not exist: %s' % options.file)
921
henryhsuf6f835c2013-07-20 20:49:25 +0800922
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800923def Main():
924 """Run sub-command specified by the command line args."""
Andy Cheng7a76cb82012-11-19 18:08:19 +0800925
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800926 options = ParseCmdline(
Ricky Liangc662be32013-12-24 11:50:23 +0800927 ('Perform Google required factory tests. All the HWID-related functions '
928 'provided here are mainly for the deprecated HWID v2. To access HWID '
929 'v3-related utilities, please use `hwid` command.'),
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800930 CmdArg('-l', '--log', metavar='PATH',
931 help='Write logs to this file.'),
Jon Salza4bea382012-10-29 13:00:34 +0800932 CmdArg('--suppress-event-logs', action='store_true',
933 help='Suppress event logging.'),
Tammo Spalink8fab5312012-05-28 18:33:30 +0800934 verbosity_cmd_arg)
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800935 SetupLogging(options.verbosity, options.log)
Andy Cheng0465d132013-03-20 12:12:06 +0800936 event_log.SetGlobalLoggerDefaultPrefix('gooftool')
937 event_log.GetGlobalLogger().suppress = options.suppress_event_logs
Tammo Spalink9a96b8a2012-04-03 11:10:41 +0800938 logging.debug('gooftool options: %s', repr(options))
939 try:
940 logging.debug('GOOFTOOL command %r', options.command_name)
941 options.command(options)
942 logging.info('GOOFTOOL command %r SUCCESS', options.command_name)
943 except Error, e:
944 logging.exception(e)
945 sys.exit('GOOFTOOL command %r ERROR: %s' % (options.command_name, e))
946 except Exception, e:
947 logging.exception(e)
948 sys.exit('UNCAUGHT RUNTIME EXCEPTION %s' % e)
949
950
951if __name__ == '__main__':
952 Main()