OLD | NEW |
---|---|
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 os | 8 import os |
9 import pprint | 9 import pprint |
10 import re | 10 import re |
11 import sys | 11 import sys |
12 import threading | |
12 | 13 |
13 import flashrom_util | 14 import flashrom_util |
14 import gft_common | 15 import gft_common |
15 import gft_fwhash | 16 import gft_fwhash |
16 import vblock | 17 import vblock |
17 | 18 |
18 from gft_common import DebugMsg, VerboseMsg, WarningMsg, ErrorMsg, ErrorDie | 19 from gft_common import DebugMsg, VerboseMsg, WarningMsg, ErrorMsg, ErrorDie |
19 | 20 |
20 | 21 |
21 def Memorize(f): | 22 def Memorize(f): |
22 """ Decorator for functions that need memorization.""" | 23 return gft_common.ThreadSafe(gft_common.Memorize(f)) |
23 memorize_data = {} | |
24 def memorize_call(*args): | |
25 index = repr(args) | |
26 if index in memorize_data: | |
27 value = memorize_data[index] | |
28 # DebugMsg('Memorize: using cached value for: %s %s' % (repr(f), index)) | |
29 return value | |
30 value = f(*args) | |
31 memorize_data[index] = value | |
32 return value | |
33 return memorize_call | |
34 | 24 |
35 | 25 |
36 class HardwareComponents(object): | 26 class HardwareComponents(object): |
37 """ Hardware Components Scanner """ | 27 """ Hardware Components Scanner """ |
38 | 28 |
39 # Function names in this class are used for reflection, so please don't change | 29 # Function names in this class are used for reflection, so please don't change |
40 # the function names even if they are not comliant to coding style guide. | 30 # the function names even if they are not comliant to coding style guide. |
41 | 31 |
42 version = 5 | 32 version = 6 |
43 | 33 |
44 # We divide all component IDs (cids) into 5 categories: | 34 # We divide all component IDs (cids) into 5 categories: |
45 # - enumerable: able to get the results by running specific commands; | 35 # - enumerable: able to get the results by running specific commands; |
46 # - probable: returns existed or not by given some pre-defined choices; | 36 # - probable: returns existed or not by given some pre-defined choices; |
47 # - pure data: data for some special purpose, can't be tested; | 37 # - pure data: data for some special purpose, can't be tested; |
48 | 38 |
49 _enumerable_cids = [ | 39 _enumerable_cids = [ |
50 'data_display_geometry', | 40 'data_display_geometry', |
51 'hash_ec_firmware', | 41 'hash_ec_firmware', |
52 'hash_ro_firmware', | 42 'hash_ro_firmware', |
(...skipping 28 matching lines...) Expand all Loading... | |
81 _probable_cids = [ | 71 _probable_cids = [ |
82 'key_recovery', | 72 'key_recovery', |
83 'key_root', | 73 'key_root', |
84 'part_id_cardreader', | 74 'part_id_cardreader', |
85 ] | 75 ] |
86 _pure_data_cids = [ | 76 _pure_data_cids = [ |
87 'data_bitmap_fv', | 77 'data_bitmap_fv', |
88 'data_recovery_url', | 78 'data_recovery_url', |
89 ] | 79 ] |
90 | 80 |
81 # list of cids that should not be fetched asynchronously. | |
82 _non_async_cids = [ | |
83 # Reading EC will become very slow and cause inaccurate results if we try to | |
84 # probe components that also fires EC command at the same time. | |
85 'part_id_ec_flash_chip', | |
86 ] | |
87 | |
91 # _not_test_cids and _to_be_tested_cids will be re-created for each match. | 88 # _not_test_cids and _to_be_tested_cids will be re-created for each match. |
92 _not_test_cids = [] | 89 _not_test_cids = [] |
93 _to_be_tested_cids = [] | 90 _to_be_tested_cids = [] |
94 | 91 |
95 # TODO(hungte) unify the 'not available' style messages | 92 # TODO(hungte) unify the 'not available' style messages |
96 _not_present = '' | 93 _not_present = '' |
97 _no_match = 'No match' | 94 _no_match = 'No match' |
98 | 95 |
99 def __init__(self, verbose=False): | 96 def __init__(self, verbose=False): |
100 self._initialized = False | 97 self._initialized = False |
(...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
626 def read_approved_from_file(self, filename): | 623 def read_approved_from_file(self, filename): |
627 approved = gft_common.LoadComponentsDatabaseFile(filename) | 624 approved = gft_common.LoadComponentsDatabaseFile(filename) |
628 for cid in self._to_be_tested_cids + self._not_test_cids: | 625 for cid in self._to_be_tested_cids + self._not_test_cids: |
629 if cid not in approved: | 626 if cid not in approved: |
630 # If we don't have any listing for this type | 627 # If we don't have any listing for this type |
631 # of part in HWID, it's not required. | 628 # of part in HWID, it's not required. |
632 WarningMsg('gft_hwcomp: Bypassing unlisted cid %s' % cid) | 629 WarningMsg('gft_hwcomp: Bypassing unlisted cid %s' % cid) |
633 approved[cid] = '*' | 630 approved[cid] = '*' |
634 return approved | 631 return approved |
635 | 632 |
636 def get_all_enumerable_components(self): | 633 def get_all_enumerable_components(self, async): |
637 results = {} | 634 results = {} |
638 for cid in self._enumerable_cids: | 635 thread_pools = [] |
636 | |
637 def fetch_enumerable_component(cid): | |
638 """ Fetch an enumerable component and update the results """ | |
639 if self._verbose: | 639 if self._verbose: |
640 sys.stdout.flush() | 640 sys.stdout.flush() |
641 sys.stderr.write('<Fetching property %s>\n' % cid) | 641 sys.stderr.write('<Fetching property %s>\n' % cid) |
642 components = self.force_get_property('get_' + cid) | 642 components = self.force_get_property('get_' + cid) |
643 if not isinstance(components, list): | 643 if not isinstance(components, list): |
644 components = [components] | 644 components = [components] |
645 results[cid] = components | 645 results[cid] = components |
646 | |
647 class FetchThread(threading.Thread): | |
648 """ Thread object for parallel enumerating """ | |
649 def __init__(self, cid): | |
650 threading.Thread.__init__(self) | |
651 self.cid = cid | |
652 | |
653 def run(self): | |
654 fetch_enumerable_component(self.cid) | |
655 | |
656 for cid in self._enumerable_cids: | |
657 if async and cid not in self._non_async_cids: | |
658 thread_pools.append(FetchThread(cid)) | |
659 else: | |
660 fetch_enumerable_component(cid) | |
661 | |
662 # Complete the threads | |
663 for thread in thread_pools: | |
664 thread.start() | |
665 for thread in thread_pools: | |
666 thread.join() | |
646 return results | 667 return results |
647 | 668 |
648 def check_enumerable_component(self, cid, exact_values, approved_values): | 669 def check_enumerable_component(self, cid, exact_values, approved_values): |
649 if '*' in approved_values: | 670 if '*' in approved_values: |
650 return | 671 return |
651 | 672 |
652 for value in exact_values: | 673 for value in exact_values: |
653 if value not in approved_values: | 674 if value not in approved_values: |
654 if cid in self._failures: | 675 if cid in self._failures: |
655 self._failures[cid].append(value) | 676 self._failures[cid].append(value) |
(...skipping 14 matching lines...) Expand all Loading... | |
670 def check_probable_component(self, cid, approved_values): | 691 def check_probable_component(self, cid, approved_values): |
671 (probed, value) = self.verify_probable_component(cid, approved_values) | 692 (probed, value) = self.verify_probable_component(cid, approved_values) |
672 if probed: | 693 if probed: |
673 self._system[cid] = value | 694 self._system[cid] = value |
674 else: | 695 else: |
675 self._failures[cid] = value | 696 self._failures[cid] = value |
676 | 697 |
677 def pformat(self, obj): | 698 def pformat(self, obj): |
678 return '\n' + self._pp.pformat(obj) + '\n' | 699 return '\n' + self._pp.pformat(obj) + '\n' |
679 | 700 |
680 def initialize(self, force=False): | 701 def initialize(self, force=False, async=False): |
681 if self._initialized and not force: | 702 if self._initialized and not force: |
682 return | 703 return |
683 # probe current system components | 704 # probe current system components |
684 DebugMsg('Starting to detect system components...') | 705 DebugMsg('Starting to detect system components...') |
685 self._enumerable_system = self.get_all_enumerable_components() | 706 self._enumerable_system = self.get_all_enumerable_components(async) |
686 self._initialized = True | 707 self._initialized = True |
687 | 708 |
688 def match_current_system(self, filename, ignored_cids=[]): | 709 def match_current_system(self, filename, ignored_cids=[]): |
689 """ Matches a given component list to current system. | 710 """ Matches a given component list to current system. |
690 Returns: (current, failures) | 711 Returns: (current, failures) |
691 """ | 712 """ |
692 | 713 |
693 # assert self._initialized, 'Not initialized.' | 714 # assert self._initialized, 'Not initialized.' |
694 self._to_be_tested_cids = (self._enumerable_cids + | 715 self._to_be_tested_cids = (self._enumerable_cids + |
695 self._probable_cids) | 716 self._probable_cids) |
(...skipping 18 matching lines...) Expand all Loading... | |
714 else: | 735 else: |
715 self.check_probable_component(cid, approved[cid]) | 736 self.check_probable_component(cid, approved[cid]) |
716 | 737 |
717 return (self._system, self._failures) | 738 return (self._system, self._failures) |
718 | 739 |
719 | 740 |
720 ############################################################################# | 741 ############################################################################# |
721 # Console main entry | 742 # Console main entry |
722 @gft_common.GFTConsole | 743 @gft_common.GFTConsole |
723 def _main(self_path, args): | 744 def _main(self_path, args): |
724 if not args: | 745 do_async = True |
725 print 'Usage: %s components_db_files...\n' % self_path | 746 |
726 sys.exit(1) | 747 # preprocess args |
748 compdb_list = [] | |
749 for arg in args: | |
750 if arg == '--sync': | |
751 do_async = False | |
752 elif arg == '--async': | |
753 do_async = True | |
754 elif not os.path.exists(arg): | |
755 print 'ERROR: unknown parameter: ' + arg | |
756 print 'Usage: %s [--sync|--async] [components_db_files...]\n' % self_path | |
757 sys.exit(1) | |
758 else: | |
759 compdb_list.append(arg) | |
760 | |
727 components = HardwareComponents(verbose=True) | 761 components = HardwareComponents(verbose=True) |
728 print 'Starting to probe system...' | 762 print 'Starting to detect %s...' % ('Asynchronously' if do_async else '') |
Tom Wai-Hong Tam
2011/04/13 01:19:36
Asynchronously -> asynchronously
| |
729 components.initialize() | 763 components.initialize(async=do_async) |
764 | |
765 if not compdb_list: | |
766 print 'Enumerable properties:' | |
767 print components.pformat(components._enumerable_system) | |
768 sys.exit(0) | |
769 | |
730 print 'Starting to match system...' | 770 print 'Starting to match system...' |
731 | 771 for arg in compdb_list: |
732 for arg in args: | |
733 (matched, failures) = components.match_current_system(arg) | 772 (matched, failures) = components.match_current_system(arg) |
734 print 'Probed (%s):' % arg | 773 print 'Probed (%s):' % arg |
735 print components.pformat(matched) | 774 print components.pformat(matched) |
736 print 'Failures (%s):' % arg | 775 print 'Failures (%s):' % arg |
737 print components.pformat(failures) | 776 print components.pformat(failures) |
738 | 777 |
739 if __name__ == '__main__': | 778 if __name__ == '__main__': |
740 _main(sys.argv[0], sys.argv[1:]) | 779 _main(sys.argv[0], sys.argv[1:]) |
OLD | NEW |