xref: /aosp_15_r20/art/tools/analyze-init-failures.py (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker#!/usr/bin/env python
2*795d594fSAndroid Build Coastguard Worker#
3*795d594fSAndroid Build Coastguard Worker# Copyright (C) 2014 The Android Open Source Project
4*795d594fSAndroid Build Coastguard Worker#
5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*795d594fSAndroid Build Coastguard Worker#
9*795d594fSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*795d594fSAndroid Build Coastguard Worker#
11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*795d594fSAndroid Build Coastguard Worker# limitations under the License.
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker"""Analyzes the dump of initialization failures and creates a Graphviz dot file
18*795d594fSAndroid Build Coastguard Worker   representing dependencies."""
19*795d594fSAndroid Build Coastguard Worker
20*795d594fSAndroid Build Coastguard Workerimport codecs
21*795d594fSAndroid Build Coastguard Workerimport os
22*795d594fSAndroid Build Coastguard Workerimport re
23*795d594fSAndroid Build Coastguard Workerimport string
24*795d594fSAndroid Build Coastguard Workerimport sys
25*795d594fSAndroid Build Coastguard Worker
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker_CLASS_RE = re.compile(r'^L(.*);$')
28*795d594fSAndroid Build Coastguard Worker_ERROR_LINE_RE = re.compile(r'^dalvik.system.TransactionAbortError: (.*)')
29*795d594fSAndroid Build Coastguard Worker_STACK_LINE_RE = re.compile(r'^\s*at\s[^\s]*\s([^\s]*)')
30*795d594fSAndroid Build Coastguard Worker
31*795d594fSAndroid Build Coastguard Workerdef Confused(filename, line_number, line):
32*795d594fSAndroid Build Coastguard Worker  sys.stderr.write('%s:%d: confused by:\n%s\n' % (filename, line_number, line))
33*795d594fSAndroid Build Coastguard Worker  raise Exception("giving up!")
34*795d594fSAndroid Build Coastguard Worker  sys.exit(1)
35*795d594fSAndroid Build Coastguard Worker
36*795d594fSAndroid Build Coastguard Worker
37*795d594fSAndroid Build Coastguard Workerdef ProcessFile(filename):
38*795d594fSAndroid Build Coastguard Worker  lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
39*795d594fSAndroid Build Coastguard Worker  it = iter(lines)
40*795d594fSAndroid Build Coastguard Worker
41*795d594fSAndroid Build Coastguard Worker  class_fail_class = {}
42*795d594fSAndroid Build Coastguard Worker  class_fail_method = {}
43*795d594fSAndroid Build Coastguard Worker  class_fail_load_library = {}
44*795d594fSAndroid Build Coastguard Worker  class_fail_get_property = {}
45*795d594fSAndroid Build Coastguard Worker  root_failures = set()
46*795d594fSAndroid Build Coastguard Worker  root_errors = {}
47*795d594fSAndroid Build Coastguard Worker
48*795d594fSAndroid Build Coastguard Worker  while True:
49*795d594fSAndroid Build Coastguard Worker    try:
50*795d594fSAndroid Build Coastguard Worker      # We start with a class descriptor.
51*795d594fSAndroid Build Coastguard Worker      raw_line = it.next()
52*795d594fSAndroid Build Coastguard Worker      m = _CLASS_RE.search(raw_line)
53*795d594fSAndroid Build Coastguard Worker      # print(raw_line)
54*795d594fSAndroid Build Coastguard Worker      if m is None:
55*795d594fSAndroid Build Coastguard Worker        continue
56*795d594fSAndroid Build Coastguard Worker      # Found a class.
57*795d594fSAndroid Build Coastguard Worker      failed_clazz = m.group(1).replace('/','.')
58*795d594fSAndroid Build Coastguard Worker      # print('Is a class %s' % failed_clazz)
59*795d594fSAndroid Build Coastguard Worker      # The error line should be next.
60*795d594fSAndroid Build Coastguard Worker      raw_line = it.next()
61*795d594fSAndroid Build Coastguard Worker      m = _ERROR_LINE_RE.search(raw_line)
62*795d594fSAndroid Build Coastguard Worker      # print(raw_line)
63*795d594fSAndroid Build Coastguard Worker      if m is None:
64*795d594fSAndroid Build Coastguard Worker        Confused(filename, -1, raw_line)
65*795d594fSAndroid Build Coastguard Worker        continue
66*795d594fSAndroid Build Coastguard Worker      # Found an error line.
67*795d594fSAndroid Build Coastguard Worker      error = m.group(1)
68*795d594fSAndroid Build Coastguard Worker      # print('Is an error %s' % error)
69*795d594fSAndroid Build Coastguard Worker      # Get the top of the stack
70*795d594fSAndroid Build Coastguard Worker      raw_line = it.next()
71*795d594fSAndroid Build Coastguard Worker      m = _STACK_LINE_RE.search(raw_line)
72*795d594fSAndroid Build Coastguard Worker      if m is None:
73*795d594fSAndroid Build Coastguard Worker        continue
74*795d594fSAndroid Build Coastguard Worker      # Found a stack line. Get the method.
75*795d594fSAndroid Build Coastguard Worker      method = m.group(1)
76*795d594fSAndroid Build Coastguard Worker      # print('Is a stack element %s' % method)
77*795d594fSAndroid Build Coastguard Worker      (left_of_paren,paren,right_of_paren) = method.partition('(')
78*795d594fSAndroid Build Coastguard Worker      (root_err_class,dot,root_method_name) = left_of_paren.rpartition('.')
79*795d594fSAndroid Build Coastguard Worker      # print('Error class %s' % err_class)
80*795d594fSAndroid Build Coastguard Worker      # print('Error method %s' % method_name)
81*795d594fSAndroid Build Coastguard Worker      # Record the root error.
82*795d594fSAndroid Build Coastguard Worker      root_failures.add(root_err_class)
83*795d594fSAndroid Build Coastguard Worker      # Parse all the trace elements to find the "immediate" cause.
84*795d594fSAndroid Build Coastguard Worker      immediate_class = root_err_class
85*795d594fSAndroid Build Coastguard Worker      immediate_method = root_method_name
86*795d594fSAndroid Build Coastguard Worker      root_errors[root_err_class] = error
87*795d594fSAndroid Build Coastguard Worker      was_load_library = False
88*795d594fSAndroid Build Coastguard Worker      was_get_property = False
89*795d594fSAndroid Build Coastguard Worker      # Now go "up" the stack.
90*795d594fSAndroid Build Coastguard Worker      while True:
91*795d594fSAndroid Build Coastguard Worker        raw_line = it.next()
92*795d594fSAndroid Build Coastguard Worker        m = _STACK_LINE_RE.search(raw_line)
93*795d594fSAndroid Build Coastguard Worker        if m is None:
94*795d594fSAndroid Build Coastguard Worker          break  # Nothing more to see here.
95*795d594fSAndroid Build Coastguard Worker        method = m.group(1)
96*795d594fSAndroid Build Coastguard Worker        (left_of_paren,paren,right_of_paren) = method.partition('(')
97*795d594fSAndroid Build Coastguard Worker        (err_class,dot,err_method_name) = left_of_paren.rpartition('.')
98*795d594fSAndroid Build Coastguard Worker        if err_method_name == "<clinit>":
99*795d594fSAndroid Build Coastguard Worker          # A class initializer is on the stack...
100*795d594fSAndroid Build Coastguard Worker          class_fail_class[err_class] = immediate_class
101*795d594fSAndroid Build Coastguard Worker          class_fail_method[err_class] = immediate_method
102*795d594fSAndroid Build Coastguard Worker          class_fail_load_library[err_class] = was_load_library
103*795d594fSAndroid Build Coastguard Worker          immediate_class = err_class
104*795d594fSAndroid Build Coastguard Worker          immediate_method = err_method_name
105*795d594fSAndroid Build Coastguard Worker          class_fail_get_property[err_class] = was_get_property
106*795d594fSAndroid Build Coastguard Worker          was_get_property = False
107*795d594fSAndroid Build Coastguard Worker        was_load_library = err_method_name == "loadLibrary"
108*795d594fSAndroid Build Coastguard Worker        was_get_property = was_get_property or err_method_name == "getProperty"
109*795d594fSAndroid Build Coastguard Worker      failed_clazz_norm = re.sub(r"^L", "", failed_clazz)
110*795d594fSAndroid Build Coastguard Worker      failed_clazz_norm = re.sub(r";$", "", failed_clazz_norm)
111*795d594fSAndroid Build Coastguard Worker      failed_clazz_norm = re.sub(r"/", "", failed_clazz_norm)
112*795d594fSAndroid Build Coastguard Worker      if immediate_class != failed_clazz_norm:
113*795d594fSAndroid Build Coastguard Worker        class_fail_class[failed_clazz_norm] = immediate_class
114*795d594fSAndroid Build Coastguard Worker        class_fail_method[failed_clazz_norm] = immediate_method
115*795d594fSAndroid Build Coastguard Worker    except StopIteration:
116*795d594fSAndroid Build Coastguard Worker      # print('Done')
117*795d594fSAndroid Build Coastguard Worker      break  # Done
118*795d594fSAndroid Build Coastguard Worker
119*795d594fSAndroid Build Coastguard Worker  # Assign IDs.
120*795d594fSAndroid Build Coastguard Worker  fail_sources = set(class_fail_class.values());
121*795d594fSAndroid Build Coastguard Worker  all_classes = fail_sources | set(class_fail_class.keys())
122*795d594fSAndroid Build Coastguard Worker  i = 0
123*795d594fSAndroid Build Coastguard Worker  class_index = {}
124*795d594fSAndroid Build Coastguard Worker  for clazz in all_classes:
125*795d594fSAndroid Build Coastguard Worker    class_index[clazz] = i
126*795d594fSAndroid Build Coastguard Worker    i = i + 1
127*795d594fSAndroid Build Coastguard Worker
128*795d594fSAndroid Build Coastguard Worker  # Now create the nodes.
129*795d594fSAndroid Build Coastguard Worker  for (r_class, r_id) in class_index.items():
130*795d594fSAndroid Build Coastguard Worker    error_string = ''
131*795d594fSAndroid Build Coastguard Worker    if r_class in root_failures:
132*795d594fSAndroid Build Coastguard Worker      error_string = ',style=filled,fillcolor=Red,tooltip="' + root_errors[r_class] + '",URL="' + root_errors[r_class] + '"'
133*795d594fSAndroid Build Coastguard Worker    elif r_class in class_fail_load_library and class_fail_load_library[r_class] == True:
134*795d594fSAndroid Build Coastguard Worker      error_string = error_string + ',style=filled,fillcolor=Bisque'
135*795d594fSAndroid Build Coastguard Worker    elif r_class in class_fail_get_property and class_fail_get_property[r_class] == True:
136*795d594fSAndroid Build Coastguard Worker      error_string = error_string + ',style=filled,fillcolor=Darkseagreen'
137*795d594fSAndroid Build Coastguard Worker    print('  n%d [shape=box,label="%s"%s];' % (r_id, r_class, error_string))
138*795d594fSAndroid Build Coastguard Worker
139*795d594fSAndroid Build Coastguard Worker  # Some space.
140*795d594fSAndroid Build Coastguard Worker  print('')
141*795d594fSAndroid Build Coastguard Worker
142*795d594fSAndroid Build Coastguard Worker  # Connections.
143*795d594fSAndroid Build Coastguard Worker  for (failed_class,error_class) in class_fail_class.items():
144*795d594fSAndroid Build Coastguard Worker    print('  n%d -> n%d;' % (class_index[failed_class], class_index[error_class]))
145*795d594fSAndroid Build Coastguard Worker
146*795d594fSAndroid Build Coastguard Worker
147*795d594fSAndroid Build Coastguard Workerdef main():
148*795d594fSAndroid Build Coastguard Worker  print('digraph {')
149*795d594fSAndroid Build Coastguard Worker  print('  overlap=false;')
150*795d594fSAndroid Build Coastguard Worker  print('  splines=true;')
151*795d594fSAndroid Build Coastguard Worker  ProcessFile(sys.argv[1])
152*795d594fSAndroid Build Coastguard Worker  print('}')
153*795d594fSAndroid Build Coastguard Worker  sys.exit(0)
154*795d594fSAndroid Build Coastguard Worker
155*795d594fSAndroid Build Coastguard Worker
156*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__':
157*795d594fSAndroid Build Coastguard Worker  main()
158