Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: gft_hwcomp.py

Issue 6835028: factory_test_tools: use flimflam to get connection info directly. (Closed) Base URL: ssh://gitrw.chromium.org:9222/factory_test_tools.git@master
Patch Set: update 3g_firmware generation rule to work for models without FirmwareRevision Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # 2 #
3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 import glob 7 import glob
8 import imp
8 import os 9 import os
9 import pprint 10 import pprint
10 import re 11 import re
11 import sys 12 import sys
12 import threading 13 import threading
13 14
14 import flashrom_util 15 import flashrom_util
15 import gft_common 16 import gft_common
16 import gft_fwhash 17 import gft_fwhash
17 import vblock 18 import vblock
18 19
19 from gft_common import DebugMsg, VerboseMsg, WarningMsg, ErrorMsg, ErrorDie 20 from gft_common import DebugMsg, VerboseMsg, WarningMsg, ErrorMsg, ErrorDie
20 21
21 22
22 def Memorize(f):
23 return gft_common.ThreadSafe(gft_common.Memorize(f))
24
25
26 class HardwareComponents(object): 23 class HardwareComponents(object):
27 """ Hardware Components Scanner """ 24 """ Hardware Components Scanner """
28 25
29 # Function names in this class are used for reflection, so please don't change 26 # Function names in this class are used for reflection, so please don't change
30 # the function names even if they are not comliant to coding style guide. 27 # the function names even if they are not comliant to coding style guide.
31 28
32 version = 6 29 version = 6
33 30
34 # We divide all component IDs (cids) into 5 categories: 31 # We divide all component IDs (cids) into 5 categories:
35 # - enumerable: able to get the results by running specific commands; 32 # - enumerable: able to get the results by running specific commands;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 ] 83 ]
87 84
88 # _not_test_cids and _to_be_tested_cids will be re-created for each match. 85 # _not_test_cids and _to_be_tested_cids will be re-created for each match.
89 _not_test_cids = [] 86 _not_test_cids = []
90 _to_be_tested_cids = [] 87 _to_be_tested_cids = []
91 88
92 # TODO(hungte) unify the 'not available' style messages 89 # TODO(hungte) unify the 'not available' style messages
93 _not_present = '' 90 _not_present = ''
94 _no_match = 'No match' 91 _no_match = 'No match'
95 92
93 # Type id for connection management (compatible to flimflam)
94 _type_3g = 'cellular'
95 _type_ethernet = 'ethernet'
96 _type_wireless = 'wifi'
97
98 _flimflam_dir = '/usr/local/lib/flimflam/test'
99
96 def __init__(self, verbose=False): 100 def __init__(self, verbose=False):
97 self._initialized = False 101 self._initialized = False
98 self._verbose = verbose 102 self._verbose = verbose
99 self._pp = pprint.PrettyPrinter() 103 self._pp = pprint.PrettyPrinter()
100 104
101 # cache for firmware images 105 # cache for firmware images
102 self._flashrom = flashrom_util.flashrom_util( 106 self._flashrom = flashrom_util.flashrom_util(
103 verbose_msg=VerboseMsg, 107 verbose_msg=VerboseMsg,
104 exception_type=gft_common.GFTError, 108 exception_type=gft_common.GFTError,
105 system_output=gft_common.SystemOutput) 109 system_output=gft_common.SystemOutput)
106 self._temp_files = [] 110 self._temp_files = []
107 111
108 # variables for matching 112 # variables for matching
109 self._enumerable_system = None 113 self._enumerable_system = None
110 self._file_base = None 114 self._file_base = None
111 self._system = None 115 self._system = None
112 self._failures = None 116 self._failures = None
113 117
114 def __del__(self): 118 def __del__(self):
115 for temp_file in self._temp_files: 119 for temp_file in self._temp_files:
116 try: 120 try:
117 # DebugMsg('gft_hwcomp: delete temp file %s' % temp_file) 121 # DebugMsg('gft_hwcomp: delete temp file %s' % temp_file)
118 os.remove(temp_file) 122 os.remove(temp_file)
119 except: 123 except:
120 pass 124 pass
121 125
122 # -------------------------------------------------------------------- 126 # --------------------------------------------------------------------
123 # System Probing Utilities 127 # System Probing Utilities
124 128
129 def Memorize(f):
130 """ Decorator for thread-safe memorization """
131 return gft_common.ThreadSafe(gft_common.Memorize(f))
132
125 @Memorize 133 @Memorize
126 def load_module(self, name): 134 def load_module(self, name):
127 grep_cmd = ('lsmod 2>/dev/null | grep -q %s' % name) 135 grep_cmd = ('lsmod 2>/dev/null | grep -q %s' % name)
128 loaded = (os.system(grep_cmd) == 0) 136 loaded = (os.system(grep_cmd) == 0)
129 if not loaded: 137 if not loaded:
130 if os.system('modprobe %s >/dev/null 2>&1' % name) != 0: 138 if os.system('modprobe %s >/dev/null 2>&1' % name) != 0:
131 ErrorMsg("Cannot load module: %s" % name) 139 ErrorMsg("Cannot load module: %s" % name)
132 return loaded 140 return loaded
133 141
134 @Memorize 142 @Memorize
(...skipping 24 matching lines...) Expand all
159 usb_devs = glob.glob('/sys/bus/usb/devices/*:*') 167 usb_devs = glob.glob('/sys/bus/usb/devices/*:*')
160 for dev in usb_devs: 168 for dev in usb_devs:
161 path = os.path.join(os.path.realpath(dev), '..') 169 path = os.path.join(os.path.realpath(dev), '..')
162 device_list += ['%s:%s' % 170 device_list += ['%s:%s' %
163 (gft_common.ReadOneLine(os.path.join(path, 'idVendor')), 171 (gft_common.ReadOneLine(os.path.join(path, 'idVendor')),
164 gft_common.ReadOneLine(os.path.join(path, 'idProduct')))] 172 gft_common.ReadOneLine(os.path.join(path, 'idProduct')))]
165 DebugMsg('Legacy device list: ' + ', '.join(device_list)) 173 DebugMsg('Legacy device list: ' + ', '.join(device_list))
166 return device_list 174 return device_list
167 175
168 @Memorize 176 @Memorize
177 def import_flimflam_module(self):
178 """ Tries to load flimflam module from current system """
179 if not os.path.exists(self._flimflam_dir):
180 DebugMsg('no flimflam installed in %s' % self._flimflam_dir)
181 return None
182 try:
183 return imp.load_module('flimflam',
184 *imp.find_module('flimflam', [self._flimflam_dir]))
185 except ImportError:
186 ErrorMsg('Failed to import flimflam.')
187 except:
188 ErrorMsg('Failed to load flimflam.')
189 return None
190
191 @Memorize
192 def load_flimflam(self):
193 """Gets information provided by flimflam (connection manager)
194
195 Returns
196 (None, None) if failed to load module, otherwise
197 (connection_path, connection_info) where
198 connection_path is a dict in {type: device_path},
199 connection_info is a dict of {type: {attribute: value}}.
200 """
201 flimflam = self.import_flimflam_module()
202 if not flimflam:
203 return (None, None)
204 path = {}
205 info = {}
206 info_attribute_names = {
207 self._type_3g: ['Carrier', 'FirmwareRevision', 'HardwareRevision',
208 'ModelID', 'Manufacturer'],
209 }
210 devices = flimflam.FlimFlam().GetObjectList('Device')
211 unpack = flimflam.convert_dbus_value
212 # TODO(hungte) support multiple devices existence in future
213 for device in devices:
214 # populate the 'path' collection
215 prop = device.GetProperties()
216 prop_type = unpack(prop['Type'])
217 path[prop_type] = '/sys/class/net/%s/device' % unpack(prop['Interface'])
218 if prop_type not in info_attribute_names:
219 continue
220 # populate the 'info' collection
221 info[prop_type] = dict((
222 (key, unpack(prop['Cellular.%s' % key]))
223 for key in info_attribute_names[prop_type]
224 if ('Cellular.%s' % key) in prop))
225 return (path, info)
226
227 @Memorize
169 def _get_all_connection_info(self): 228 def _get_all_connection_info(self):
170 """ Probes available connectivity and device information """ 229 """ Probes available connectivity and device information """
171 connection_info = { 230 connection_info = {
172 'wireless': '/sys/class/net/wlan0/device', 231 self._type_wireless: '/sys/class/net/wlan0/device',
173 'ethernet': '/sys/class/net/eth0/device', 232 self._type_ethernet: '/sys/class/net/eth0/device',
174 '3g': '/sys/class/tty/ttyUSB0/device', 233 # 3g(cellular) may also be /sys/class/net/usb0
234 self._type_3g: '/sys/class/tty/ttyUSB0/device',
175 } 235 }
176 flimflam_scripts_base = '/usr/local/lib/flimflam/test' 236 (path, _) = self.load_flimflam()
177 if os.path.exists(flimflam_scripts_base): 237 if path is not None:
178 # TODO(hungte) use flimflam to update the device list. 238 # trust flimflam instead.
179 # Currently flimflam seem to be not very stable, so let's ignore it. 239 for k in connection_info:
180 list_modems = os.path.join(flimflam_scripts_base, 'mm-list-modems') 240 connection_info[k] = (path[k] if k in path else '')
181 part_id = gft_common.SystemOutput(list_modems, ignore_status=True).strip()
182 if part_id:
183 DebugMsg('mm-list-modems reported: %s' % part_id)
184 return connection_info 241 return connection_info
185 242
186 def _get_sysfs_device_info(self, path, primary, optional=[]): 243 def _get_sysfs_device_info(self, path, primary, optional=[]):
187 """Gets the device information of a sysfs node. 244 """Gets the device information of a sysfs node.
188 245
189 Args 246 Args
190 path: the sysfs device path. 247 path: the sysfs device path.
191 primary: mandatory list of elements to read. 248 primary: mandatory list of elements to read.
192 optional: optional list of elements to read. 249 optional: optional list of elements to read.
193 250
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 return info_string 295 return info_string
239 296
240 def get_sysfs_device_id(self, path): 297 def get_sysfs_device_id(self, path):
241 """Gets a sysfs device identifier. (Currently supporting USB/PCI) 298 """Gets a sysfs device identifier. (Currently supporting USB/PCI)
242 Args 299 Args
243 path: a path to sysfs device (ex, /sys/class/net/wlan0/device) 300 path: a path to sysfs device (ex, /sys/class/net/wlan0/device)
244 301
245 Returns 302 Returns
246 An identifier string, or self._not_present if not available. 303 An identifier string, or self._not_present if not available.
247 """ 304 """
305 if not path:
306 return self._not_present
248 path = os.path.realpath(path) 307 path = os.path.realpath(path)
249 if not os.path.isdir(path): 308 if not os.path.isdir(path):
250 return self._not_present 309 return self._not_present
251 310
252 info = (self._get_pci_device_info(path) or 311 info = (self._get_pci_device_info(path) or
253 self._get_usb_device_info(path)) 312 self._get_usb_device_info(path))
254 return info or self._not_present 313 return info or self._not_present
255 314
256 # -------------------------------------------------------------------- 315 # --------------------------------------------------------------------
257 # Firmware Processing Utilities 316 # Firmware Processing Utilities
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 Returns a hash of Read Only (BIOS) firmware parts, 408 Returns a hash of Read Only (BIOS) firmware parts,
350 to confirm we have proper keys / boot code / recovery image installed. 409 to confirm we have proper keys / boot code / recovery image installed.
351 """ 410 """
352 411
353 image_file = self.load_main_firmware() 412 image_file = self.load_main_firmware()
354 if not image_file: 413 if not image_file:
355 ErrorDie('get_hash_ro_firmware: cannot read firmware') 414 ErrorDie('get_hash_ro_firmware: cannot read firmware')
356 return gft_fwhash.GetBIOSReadOnlyHash(file_source=image_file) 415 return gft_fwhash.GetBIOSReadOnlyHash(file_source=image_file)
357 416
358 def get_part_id_3g(self): 417 def get_part_id_3g(self):
359 device_path = self._get_all_connection_info()['3g'] 418 device_path = self._get_all_connection_info()[self._type_3g]
360 return self.get_sysfs_device_id(device_path) or self._not_present 419 return self.get_sysfs_device_id(device_path) or self._not_present
361 420
362 def get_part_id_audio_codec(self): 421 def get_part_id_audio_codec(self):
363 cmd = 'grep -R Codec: /proc/asound/* | head -n 1 | sed s/.\*Codec://' 422 cmd = 'grep -R Codec: /proc/asound/* | head -n 1 | sed s/.\*Codec://'
364 part_id = gft_common.SystemOutput( 423 part_id = gft_common.SystemOutput(
365 cmd, progress_messsage='Searching Audio Codecs: ', 424 cmd, progress_messsage='Searching Audio Codecs: ',
366 show_progress=self._verbose).strip() 425 show_progress=self._verbose).strip()
367 return part_id 426 return part_id
368 427
369 def get_part_id_bluetooth(self): 428 def get_part_id_bluetooth(self):
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 show_progress=self._verbose, 488 show_progress=self._verbose,
430 ignore_status=True).splitlines() 489 ignore_status=True).splitlines()
431 for line in res: 490 for line in res:
432 match = re.search(r'Found (.*) at', line) 491 match = re.search(r'Found (.*) at', line)
433 if match: 492 if match:
434 parts.append(match.group(1)) 493 parts.append(match.group(1))
435 part_id = ', '.join(parts) 494 part_id = ', '.join(parts)
436 return part_id 495 return part_id
437 496
438 def get_part_id_ethernet(self): 497 def get_part_id_ethernet(self):
439 device_path = self._get_all_connection_info()['ethernet'] 498 device_path = self._get_all_connection_info()[self._type_ethernet]
440 return self.get_sysfs_device_id(device_path) or self._not_present 499 return self.get_sysfs_device_id(device_path) or self._not_present
441 500
442 def get_part_id_flash_chip(self): 501 def get_part_id_flash_chip(self):
443 (chip_id, _) = self._load_firmware('main') 502 (chip_id, _) = self._load_firmware('main')
444 return chip_id 503 return chip_id
445 504
446 def get_part_id_hwqual(self): 505 def get_part_id_hwqual(self):
447 part_id = gft_common.SystemOutput('crossystem hwid').strip() 506 part_id = gft_common.SystemOutput('crossystem hwid').strip()
448 return (part_id if part_id else self._not_present) 507 return (part_id if part_id else self._not_present)
449 508
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 usb_host_info.sort(reverse=True) 544 usb_host_info.sort(reverse=True)
486 return ' '.join(usb_host_info) 545 return ' '.join(usb_host_info)
487 546
488 def get_part_id_vga(self): 547 def get_part_id_vga(self):
489 return self.get_sysfs_device_id('/sys/class/graphics/fb0/device') 548 return self.get_sysfs_device_id('/sys/class/graphics/fb0/device')
490 549
491 def get_part_id_webcam(self): 550 def get_part_id_webcam(self):
492 return self.get_sysfs_device_id('/sys/class/video4linux/video0/device') 551 return self.get_sysfs_device_id('/sys/class/video4linux/video0/device')
493 552
494 def get_part_id_wireless(self): 553 def get_part_id_wireless(self):
495 device_path = self._get_all_connection_info()['wireless'] 554 device_path = self._get_all_connection_info()[self._type_wireless]
496 return self.get_sysfs_device_id(device_path) or self._not_present 555 return self.get_sysfs_device_id(device_path) or self._not_present
497 556
498 def get_vendor_id_touchpad_synaptics(self): 557 def get_vendor_id_touchpad_synaptics(self):
499 part_id = '' 558 part_id = ''
500 detect_program = '/opt/Synaptics/bin/syndetect' 559 detect_program = '/opt/Synaptics/bin/syndetect'
501 model_string_str = 'Model String' 560 model_string_str = 'Model String'
502 firmware_id_str = 'Firmware ID' 561 firmware_id_str = 'Firmware ID'
503 if os.path.exists(detect_program): 562 if os.path.exists(detect_program):
504 data = gft_common.SystemOutput( 563 data = gft_common.SystemOutput(
505 detect_program, 564 detect_program,
(...skipping 26 matching lines...) Expand all
532 part_id = '' 591 part_id = ''
533 for method in method_list: 592 for method in method_list:
534 part_id = getattr(self, 'get_vendor_id_touchpad_%s' % method)() 593 part_id = getattr(self, 'get_vendor_id_touchpad_%s' % method)()
535 DebugMsg('get_vendor_id_touchpad: %s: %s' % 594 DebugMsg('get_vendor_id_touchpad: %s: %s' %
536 (method, part_id or '<failed>')) 595 (method, part_id or '<failed>'))
537 if part_id: 596 if part_id:
538 break 597 break
539 return part_id 598 return part_id
540 599
541 def get_version_3g_firmware(self): 600 def get_version_3g_firmware(self):
542 version = 'Unknown' 601 (_, attributes) = self.load_flimflam()
Jason Glasgow 2011/04/15 22:39:44 Looks okay to me. I would have used mm.py and gon
543 # TODO(hungte) use mm.py directly to prevent the need of shell scripting 602 if attributes and (self._type_3g in attributes):
544 modem_status = gft_common.SystemOutput('modem status', 603 # A list of possible version info combination, since the supported fields
545 ignore_status=True).splitlines() 604 # may differ for partners.
546 if not modem_status: 605 version_formats = [
547 return self._not_present 606 ['Carrier', 'FirmwareRevision'],
548 607 ['FirmwareRevision'],
549 # status format: 608 ['HardwareRevision']]
550 # Manufacturer: $VENDOR 609 info = attributes[self._type_3g]
551 # Modem: $MODEM 610 for version_format in version_formats:
552 # Version: $VERSION_MAY_BE_MULTILINE 611 if not set(version_format).issubset(set(info)):
553 def ParseInfo(name): 612 continue
554 data = [line for line in modem_status if line.find('%s: ' % name) >= 0] 613 # compact all fields into single line with limited space
555 assert len(data) < 2 614 version_string = ' '.join([info[key] for key in version_format])
556 return data[0].split(': ', 1)[1].strip() 615 return re.sub('\s+', ' ', version_string)
557 616 return self._not_present
558 version = ParseInfo('Version')
559 vendor = ParseInfo('Manufacturer')
560 modem = ParseInfo('Modem')
561
562 if vendor == 'Samsung' and modem == 'GT-Y3300X':
563 # The real version is in "Version:" +2 lines
564 version = ''
565 for i, line in enumerate(modem_status):
566 if 'Version: ' in line:
567 version = modem_status[i + 2].strip()
568 break
569 return version or 'Unknown'
570 617
571 def get_version_rw_firmware(self): 618 def get_version_rw_firmware(self):
572 """ 619 """
573 Returns the version of Read-Write (writable) firmware from VBLOCK sections. 620 Returns the version of Read-Write (writable) firmware from VBLOCK sections.
574 621
575 If A/B has different version, that means this system needs a reboot + 622 If A/B has different version, that means this system needs a reboot +
576 firmwar update so return value is a "error report" in the form "A=x, B=y". 623 firmwar update so return value is a "error report" in the form "A=x, B=y".
577 """ 624 """
578 625
579 versions = [None, None] 626 versions = [None, None]
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
817 print 'Starting to match system...' 864 print 'Starting to match system...'
818 for arg in compdb_list: 865 for arg in compdb_list:
819 (matched, failures) = components.match_current_system(arg) 866 (matched, failures) = components.match_current_system(arg)
820 print 'Probed (%s):' % arg 867 print 'Probed (%s):' % arg
821 print components.pformat(matched) 868 print components.pformat(matched)
822 print 'Failures (%s):' % arg 869 print 'Failures (%s):' % arg
823 print components.pformat(failures) 870 print components.pformat(failures)
824 871
825 if __name__ == '__main__': 872 if __name__ == '__main__':
826 _main(sys.argv[0], sys.argv[1:]) 873 _main(sys.argv[0], sys.argv[1:])
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698