xref: /aosp_15_r20/development/scripts/boardconfig_usage_analysis.py (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*90c8c64dSAndroid Build Coastguard Worker
3*90c8c64dSAndroid Build Coastguard Workerimport argparse
4*90c8c64dSAndroid Build Coastguard Workerimport fnmatch
5*90c8c64dSAndroid Build Coastguard Workerimport json
6*90c8c64dSAndroid Build Coastguard Workerimport os
7*90c8c64dSAndroid Build Coastguard Workerimport re
8*90c8c64dSAndroid Build Coastguard Workerimport sys
9*90c8c64dSAndroid Build Coastguard Worker
10*90c8c64dSAndroid Build Coastguard WorkerHELP_MSG = '''
11*90c8c64dSAndroid Build Coastguard WorkerThis script analyses the usage of build-time variables which are defined in BoardConfig*.mk
12*90c8c64dSAndroid Build Coastguard Workerand used by framework modules (installed in system.img). Please 'lunch' and 'make' before
13*90c8c64dSAndroid Build Coastguard Workerrunning it.
14*90c8c64dSAndroid Build Coastguard Worker'''
15*90c8c64dSAndroid Build Coastguard Worker
16*90c8c64dSAndroid Build Coastguard WorkerTOP = os.environ.get('ANDROID_BUILD_TOP')
17*90c8c64dSAndroid Build Coastguard WorkerOUT = os.environ.get('OUT')
18*90c8c64dSAndroid Build Coastguard Worker
19*90c8c64dSAndroid Build Coastguard Workerwhite_list = [
20*90c8c64dSAndroid Build Coastguard Worker    'TARGET_ARCH',
21*90c8c64dSAndroid Build Coastguard Worker    'TARGET_ARCH_VARIANT',
22*90c8c64dSAndroid Build Coastguard Worker    'TARGET_CPU_VARIANT',
23*90c8c64dSAndroid Build Coastguard Worker    'TARGET_CPU_ABI',
24*90c8c64dSAndroid Build Coastguard Worker    'TARGET_CPU_ABI2',
25*90c8c64dSAndroid Build Coastguard Worker
26*90c8c64dSAndroid Build Coastguard Worker    'TARGET_2ND_ARCH',
27*90c8c64dSAndroid Build Coastguard Worker    'TARGET_2ND_ARCH_VARIANT',
28*90c8c64dSAndroid Build Coastguard Worker    'TARGET_2ND_CPU_VARIANT',
29*90c8c64dSAndroid Build Coastguard Worker    'TARGET_2ND_CPU_ABI',
30*90c8c64dSAndroid Build Coastguard Worker    'TARGET_2ND_CPU_ABI2',
31*90c8c64dSAndroid Build Coastguard Worker
32*90c8c64dSAndroid Build Coastguard Worker    'TARGET_NO_BOOTLOADER',
33*90c8c64dSAndroid Build Coastguard Worker    'TARGET_NO_KERNEL',
34*90c8c64dSAndroid Build Coastguard Worker    'TARGET_NO_RADIOIMAGE',
35*90c8c64dSAndroid Build Coastguard Worker    'TARGET_NO_RECOVERY',
36*90c8c64dSAndroid Build Coastguard Worker
37*90c8c64dSAndroid Build Coastguard Worker    'TARGET_BOARD_PLATFORM',
38*90c8c64dSAndroid Build Coastguard Worker
39*90c8c64dSAndroid Build Coastguard Worker    'ARCH_ARM_HAVE_ARMV7A',
40*90c8c64dSAndroid Build Coastguard Worker    'ARCH_ARM_HAVE_NEON',
41*90c8c64dSAndroid Build Coastguard Worker    'ARCH_ARM_HAVE_VFP',
42*90c8c64dSAndroid Build Coastguard Worker    'ARCH_ARM_HAVE_VFP_D32',
43*90c8c64dSAndroid Build Coastguard Worker
44*90c8c64dSAndroid Build Coastguard Worker    'BUILD_NUMBER'
45*90c8c64dSAndroid Build Coastguard Worker]
46*90c8c64dSAndroid Build Coastguard Worker
47*90c8c64dSAndroid Build Coastguard Worker
48*90c8c64dSAndroid Build Coastguard Worker# used by find_board_configs_mks() and find_makefiles()
49*90c8c64dSAndroid Build Coastguard Workerdef find_files(folders, filter):
50*90c8c64dSAndroid Build Coastguard Worker  ret = []
51*90c8c64dSAndroid Build Coastguard Worker
52*90c8c64dSAndroid Build Coastguard Worker  for folder in folders:
53*90c8c64dSAndroid Build Coastguard Worker    for root, dirs, files in os.walk(os.path.join(TOP, folder), topdown=True):
54*90c8c64dSAndroid Build Coastguard Worker      dirs[:] = [d for d in dirs if not d[0] == '.']
55*90c8c64dSAndroid Build Coastguard Worker      for file in files:
56*90c8c64dSAndroid Build Coastguard Worker        if filter(file):
57*90c8c64dSAndroid Build Coastguard Worker          ret.append(os.path.join(root, file))
58*90c8c64dSAndroid Build Coastguard Worker
59*90c8c64dSAndroid Build Coastguard Worker  return ret
60*90c8c64dSAndroid Build Coastguard Worker
61*90c8c64dSAndroid Build Coastguard Worker# find board configs (BoardConfig*.mk)
62*90c8c64dSAndroid Build Coastguard Workerdef find_board_config_mks(folders = ['build', 'device', 'vendor', 'hardware']):
63*90c8c64dSAndroid Build Coastguard Worker  return find_files(folders, lambda x:
64*90c8c64dSAndroid Build Coastguard Worker                    fnmatch.fnmatch(x, 'BoardConfig*.mk'))
65*90c8c64dSAndroid Build Coastguard Worker
66*90c8c64dSAndroid Build Coastguard Worker# find makefiles (*.mk or Makefile) under specific folders
67*90c8c64dSAndroid Build Coastguard Workerdef find_makefiles(folders = ['system', 'frameworks', 'external']):
68*90c8c64dSAndroid Build Coastguard Worker  return find_files(folders, lambda x:
69*90c8c64dSAndroid Build Coastguard Worker                    fnmatch.fnmatch(x, '*.mk') or fnmatch.fnmatch(x, 'Makefile'))
70*90c8c64dSAndroid Build Coastguard Worker
71*90c8c64dSAndroid Build Coastguard Worker# read module-info.json and find makefiles of modules in system image
72*90c8c64dSAndroid Build Coastguard Workerdef find_system_module_makefiles():
73*90c8c64dSAndroid Build Coastguard Worker  makefiles = []
74*90c8c64dSAndroid Build Coastguard Worker  out_system_path = os.path.join(OUT[len(TOP) + 1:], 'system')
75*90c8c64dSAndroid Build Coastguard Worker
76*90c8c64dSAndroid Build Coastguard Worker  with open(os.path.join(OUT, 'module-info.json')) as module_info_json:
77*90c8c64dSAndroid Build Coastguard Worker    module_info = json.load(module_info_json)
78*90c8c64dSAndroid Build Coastguard Worker    for module in module_info:
79*90c8c64dSAndroid Build Coastguard Worker      installs = module_info[module]['installed']
80*90c8c64dSAndroid Build Coastguard Worker      paths = module_info[module]['path']
81*90c8c64dSAndroid Build Coastguard Worker
82*90c8c64dSAndroid Build Coastguard Worker      installed_in_system = False
83*90c8c64dSAndroid Build Coastguard Worker
84*90c8c64dSAndroid Build Coastguard Worker      for install in installs:
85*90c8c64dSAndroid Build Coastguard Worker        if install.startswith(out_system_path):
86*90c8c64dSAndroid Build Coastguard Worker          installed_in_system = True
87*90c8c64dSAndroid Build Coastguard Worker          break
88*90c8c64dSAndroid Build Coastguard Worker
89*90c8c64dSAndroid Build Coastguard Worker      if installed_in_system:
90*90c8c64dSAndroid Build Coastguard Worker        for path in paths:
91*90c8c64dSAndroid Build Coastguard Worker          makefile = os.path.join(TOP, path, 'Android.mk')
92*90c8c64dSAndroid Build Coastguard Worker          makefiles.append(makefile)
93*90c8c64dSAndroid Build Coastguard Worker
94*90c8c64dSAndroid Build Coastguard Worker  return makefiles
95*90c8c64dSAndroid Build Coastguard Worker
96*90c8c64dSAndroid Build Coastguard Worker# find variables defined in board_config_mks
97*90c8c64dSAndroid Build Coastguard Workerdef find_defined_variables(board_config_mks):
98*90c8c64dSAndroid Build Coastguard Worker  re_def = re.compile('^[\s]*([\w\d_]*)[\s]*:=')
99*90c8c64dSAndroid Build Coastguard Worker  variables = dict()
100*90c8c64dSAndroid Build Coastguard Worker
101*90c8c64dSAndroid Build Coastguard Worker  for board_config_mk in board_config_mks:
102*90c8c64dSAndroid Build Coastguard Worker    for line in open(board_config_mk, encoding='latin1'):
103*90c8c64dSAndroid Build Coastguard Worker      mo = re_def.search(line)
104*90c8c64dSAndroid Build Coastguard Worker      if mo is None:
105*90c8c64dSAndroid Build Coastguard Worker        continue
106*90c8c64dSAndroid Build Coastguard Worker
107*90c8c64dSAndroid Build Coastguard Worker      variable = mo.group(1)
108*90c8c64dSAndroid Build Coastguard Worker      if variable in white_list:
109*90c8c64dSAndroid Build Coastguard Worker        continue
110*90c8c64dSAndroid Build Coastguard Worker
111*90c8c64dSAndroid Build Coastguard Worker      if variable not in variables:
112*90c8c64dSAndroid Build Coastguard Worker        variables[variable] = set()
113*90c8c64dSAndroid Build Coastguard Worker
114*90c8c64dSAndroid Build Coastguard Worker      variables[variable].add(board_config_mk[len(TOP) + 1:])
115*90c8c64dSAndroid Build Coastguard Worker
116*90c8c64dSAndroid Build Coastguard Worker  return variables
117*90c8c64dSAndroid Build Coastguard Worker
118*90c8c64dSAndroid Build Coastguard Worker# count variable usage in makefiles
119*90c8c64dSAndroid Build Coastguard Workerdef find_usage(variable, makefiles):
120*90c8c64dSAndroid Build Coastguard Worker  re_usage = re.compile('\$\(' + variable + '\)')
121*90c8c64dSAndroid Build Coastguard Worker  usage = set()
122*90c8c64dSAndroid Build Coastguard Worker
123*90c8c64dSAndroid Build Coastguard Worker  for makefile in makefiles:
124*90c8c64dSAndroid Build Coastguard Worker    if not os.path.isfile(makefile):
125*90c8c64dSAndroid Build Coastguard Worker      # TODO: support bp
126*90c8c64dSAndroid Build Coastguard Worker      continue
127*90c8c64dSAndroid Build Coastguard Worker
128*90c8c64dSAndroid Build Coastguard Worker    with open(makefile, encoding='latin1') as mk_file:
129*90c8c64dSAndroid Build Coastguard Worker      mk_str = mk_file.read()
130*90c8c64dSAndroid Build Coastguard Worker
131*90c8c64dSAndroid Build Coastguard Worker    if re_usage.search(mk_str) is not None:
132*90c8c64dSAndroid Build Coastguard Worker      usage.add(makefile[len(TOP) + 1:])
133*90c8c64dSAndroid Build Coastguard Worker
134*90c8c64dSAndroid Build Coastguard Worker  return usage
135*90c8c64dSAndroid Build Coastguard Worker
136*90c8c64dSAndroid Build Coastguard Workerdef main():
137*90c8c64dSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(description=HELP_MSG)
138*90c8c64dSAndroid Build Coastguard Worker  parser.add_argument("-v", "--verbose",
139*90c8c64dSAndroid Build Coastguard Worker                      help="print definition and usage locations",
140*90c8c64dSAndroid Build Coastguard Worker                      action="store_true")
141*90c8c64dSAndroid Build Coastguard Worker  args = parser.parse_args()
142*90c8c64dSAndroid Build Coastguard Worker
143*90c8c64dSAndroid Build Coastguard Worker  print('TOP : ' + TOP)
144*90c8c64dSAndroid Build Coastguard Worker  print('OUT : ' + OUT)
145*90c8c64dSAndroid Build Coastguard Worker  print()
146*90c8c64dSAndroid Build Coastguard Worker
147*90c8c64dSAndroid Build Coastguard Worker  sfe_makefiles = find_makefiles()
148*90c8c64dSAndroid Build Coastguard Worker  system_module_makefiles = find_system_module_makefiles()
149*90c8c64dSAndroid Build Coastguard Worker  board_config_mks = find_board_config_mks()
150*90c8c64dSAndroid Build Coastguard Worker  variables = find_defined_variables(board_config_mks)
151*90c8c64dSAndroid Build Coastguard Worker
152*90c8c64dSAndroid Build Coastguard Worker  if args.verbose:
153*90c8c64dSAndroid Build Coastguard Worker    print('sfe_makefiles', len(sfe_makefiles))
154*90c8c64dSAndroid Build Coastguard Worker    print('system_module_makefiles', len(system_module_makefiles))
155*90c8c64dSAndroid Build Coastguard Worker    print('board_config_mks', len(board_config_mks))
156*90c8c64dSAndroid Build Coastguard Worker    print('variables', len(variables))
157*90c8c64dSAndroid Build Coastguard Worker    print()
158*90c8c64dSAndroid Build Coastguard Worker
159*90c8c64dSAndroid Build Coastguard Worker  glossary = (
160*90c8c64dSAndroid Build Coastguard Worker      '*Output in CSV format\n\n'
161*90c8c64dSAndroid Build Coastguard Worker
162*90c8c64dSAndroid Build Coastguard Worker      '*definition count      :'
163*90c8c64dSAndroid Build Coastguard Worker      ' This variable is defined in how many BoardConfig*.mk\'s\n'
164*90c8c64dSAndroid Build Coastguard Worker
165*90c8c64dSAndroid Build Coastguard Worker      '*usage in SFE          :'
166*90c8c64dSAndroid Build Coastguard Worker      ' This variable is used by how many makefiles under system/, frameworks/ and external/ folders\n'
167*90c8c64dSAndroid Build Coastguard Worker
168*90c8c64dSAndroid Build Coastguard Worker      '*usage in system image :'
169*90c8c64dSAndroid Build Coastguard Worker      ' This variable is used by how many system image modules\n')
170*90c8c64dSAndroid Build Coastguard Worker
171*90c8c64dSAndroid Build Coastguard Worker  csv_string = (
172*90c8c64dSAndroid Build Coastguard Worker      'variable name,definition count,usage in SFE,usage in system image\n')
173*90c8c64dSAndroid Build Coastguard Worker
174*90c8c64dSAndroid Build Coastguard Worker  for variable, locations in sorted(variables.items()):
175*90c8c64dSAndroid Build Coastguard Worker    usage_in_sfe = find_usage(variable, sfe_makefiles)
176*90c8c64dSAndroid Build Coastguard Worker    usage_of_system_modules = find_usage(variable, system_module_makefiles)
177*90c8c64dSAndroid Build Coastguard Worker    usage = usage_in_sfe | usage_of_system_modules
178*90c8c64dSAndroid Build Coastguard Worker
179*90c8c64dSAndroid Build Coastguard Worker    if len(usage) == 0:
180*90c8c64dSAndroid Build Coastguard Worker      continue
181*90c8c64dSAndroid Build Coastguard Worker
182*90c8c64dSAndroid Build Coastguard Worker    csv_string += ','.join([variable,
183*90c8c64dSAndroid Build Coastguard Worker                            str(len(locations)),
184*90c8c64dSAndroid Build Coastguard Worker                            str(len(usage_in_sfe)),
185*90c8c64dSAndroid Build Coastguard Worker                            str(len(usage_of_system_modules))]) + '\n'
186*90c8c64dSAndroid Build Coastguard Worker
187*90c8c64dSAndroid Build Coastguard Worker    if args.verbose:
188*90c8c64dSAndroid Build Coastguard Worker      print((variable + ' ').ljust(80, '='))
189*90c8c64dSAndroid Build Coastguard Worker
190*90c8c64dSAndroid Build Coastguard Worker      print('Defined in (' + str(len(locations)) + ') :')
191*90c8c64dSAndroid Build Coastguard Worker      for location in sorted(locations):
192*90c8c64dSAndroid Build Coastguard Worker        print('  ' + location)
193*90c8c64dSAndroid Build Coastguard Worker
194*90c8c64dSAndroid Build Coastguard Worker      print('Used in (' + str(len(usage)) + ') :')
195*90c8c64dSAndroid Build Coastguard Worker      for location in sorted(usage):
196*90c8c64dSAndroid Build Coastguard Worker        print('  ' + location)
197*90c8c64dSAndroid Build Coastguard Worker
198*90c8c64dSAndroid Build Coastguard Worker      print()
199*90c8c64dSAndroid Build Coastguard Worker
200*90c8c64dSAndroid Build Coastguard Worker  if args.verbose:
201*90c8c64dSAndroid Build Coastguard Worker    print('\n')
202*90c8c64dSAndroid Build Coastguard Worker
203*90c8c64dSAndroid Build Coastguard Worker  print(glossary)
204*90c8c64dSAndroid Build Coastguard Worker  print(csv_string)
205*90c8c64dSAndroid Build Coastguard Worker
206*90c8c64dSAndroid Build Coastguard Workerif __name__ == '__main__':
207*90c8c64dSAndroid Build Coastguard Worker  if TOP is None:
208*90c8c64dSAndroid Build Coastguard Worker    sys.exit('$ANDROID_BUILD_TOP is undefined, please lunch and make before running this script')
209*90c8c64dSAndroid Build Coastguard Worker
210*90c8c64dSAndroid Build Coastguard Worker  if OUT is None:
211*90c8c64dSAndroid Build Coastguard Worker    sys.exit('$OUT is undefined, please lunch and make before running this script')
212*90c8c64dSAndroid Build Coastguard Worker
213*90c8c64dSAndroid Build Coastguard Worker  if not os.path.isfile(os.path.join(OUT, 'module-info.json')):
214*90c8c64dSAndroid Build Coastguard Worker    sys.exit('module-info.json is missing, please lunch and make before running this script')
215*90c8c64dSAndroid Build Coastguard Worker
216*90c8c64dSAndroid Build Coastguard Worker  main()
217*90c8c64dSAndroid Build Coastguard Worker
218