Debuggable Android program debugging tool
Highlights of the Code debugging tool provided by Google:TraceviewAndDmtracedump. With these two tools, we can easily Debug programs to analyze bugs. Traceview helps us analyze program performance. dmtracedump generates a function call diagram. Unfortunately, the dmtracedump provided by Google is a failed tool and cannot be drawn. This article will introduce the solution in detail to implement plotting.
Generate a. trace file by using the dig command.
Android. OS. debug class. Two important methods are Debug. startmethodtracing () and Debug. stopmethodtracing (). These two methods are used to create. trace file, which will be from debug. startmethodtracing (), to debug. stopmethodtracing () ends, during which all calling processes are stored in. the trace file contains the called function name and execution time.
Add the following code to the start and end positions of the debugging code respectively.
Debug.startMethodTracing(“test”); Debug.stopMethodTracing();
The parameter test is the name of the trace file to be created, test. Trace. The default path is/sdcard/test. Trace. You can also Customize/data/log/test to indicate that the file is in/data/log/test. Trace.
✿ Traceview
Run the following command in the SDK:
./Traceview test. Trace
We can get
1. Start and Stop times for each thread in the program to call a method
2. Information and Efficiency Analysis of function execution
✿ Dmtracedump the original intention of dmtracedump is to combine the entire call process and time analysis and display it in the form of a function call diagram. However, the Google Project has been in the broken state and cannot be improved. The current dmtracdump can only be used by the-O option. The function call information is listed on the terminal, which is similar to the traceview function. If you execute./dmtracedump-G test.png test. Trace, it will be stuck. At first, I thought it was a problem with the test. trace file. I made a slight modification to the file Terminator and drew a ray of pictures:
Later, I found that some cool people on the Internet provided alternative dmtracedump (this is the original link). It is a Python script that uses dot to draw vector images. In a Python script, you must pay attention to the alignment format. Alignment indentation is its logical structure.
#!/usr/bin/env python"""turn the traceview data into a jpg pic, showing methods call relationship"""import sysimport osimport structimport re######################################################################################################## Global Variable #####################################################################################################################target_thread=1 #the thread that we want to track, filt out other threads#all_actions = ["enter","exit","exception","reserved"]all_threads = {}all_methods = {}all_records = []parent_methods = {}child_methods = {}method_calls = {}############################################################################################################## Methods #####################################################################################################################def add_one_thread(line): fields = line.split("/t") all_threads[int(fields[0],10)]=fieldsdef add_one_method(line): fields = line.split("/t") all_methods[int(fields[0],16)]=fieldsdef add_one_record(one): thread_id,=struct.unpack("B",one[:1]) if (thread_id == target_thread): tmp,=struct.unpack("L",one[1:5]) method_id= (tmp / 4) * 4; method_action= tmp % 4; time_offset,=struct.unpack("L",one[5:]) all_records.append([thread_id, method_id, method_action, time_offset])def handle_one_call(parent_method_id,method_id): if not (parent_methods.has_key(parent_method_id)): parent_methods[parent_method_id]=1 if not (child_methods.has_key(method_id)): child_methods[method_id]=1 if method_calls.has_key(parent_method_id): if method_calls[parent_method_id].has_key(method_id): method_calls[parent_method_id][method_id]+=1 else: method_calls[parent_method_id][method_id]=1 else: method_calls[parent_method_id]={} method_calls[parent_method_id][method_id]=1def gen_funcname(method_id): r1=re.compile(r'[/{1}lt;>]') str1=r1.sub("_",all_methods[method_id][1]) str2=r1.sub("_",all_methods[method_id][2]) return str1+"_"+str2def gen_dot_script_file(): myoutfile = open("graph.dot", "w") myoutfile.write("digraph vanzo {/n/n"); for one in all_methods.keys(): if parent_methods.has_key(one): myoutfile.write(gen_funcname(one)+" [shape=rectangle];/n") else: if child_methods.has_key(one): myoutfile.write(gen_funcname(one)+" [shape=ellipse];/n") for one in method_calls.keys(): for two in method_calls[one]: myoutfile.write(gen_funcname(one) + ' -> ' + gen_funcname(two) + ' [label="' + str(method_calls[one][two]) + '" fontsize="10"];/n') myoutfile.write("/n}/n"); myoutfile.close ########################################################################################################## Script starts from here #############################################################################################################if len(sys.argv) < 2: print 'No input file specified.' sys.exit()if not (os.path.exists(sys.argv[1])): print "input file not exists" sys.exit()#Now handle the text partcurrent_section=0for line in open(sys.argv[1]): line2 = line.strip() if (line2.startswith("*")): if (line2.startswith("*version")): current_section=1 else: if (line2.startswith("*threads")): current_section=2 else: if (line2.startswith("*methods")): current_section=3 else: if (line2.startswith("*end")): current_section=4 break continue if current_section==2: add_one_thread(line2) if current_section==3: add_one_method(line2) #Now handle the binary partmybinfile = open(sys.argv[1], "rb") alldata = mybinfile.read()mybinfile.close()pos=alldata.find("SLOW")offset,=struct.unpack("H",alldata[pos+6:pos+8])pos2=pos+offset #pos2 is where the record beginnumofrecords = len(alldata) - pos2numofrecords = numofrecords / 9for i in xrange(numofrecords): add_one_record(alldata[pos2 + i * 9:pos2 + i * 9 + 9])my_stack=[0]for onerecord in all_records: thread_id=onerecord[0]; method_id=onerecord[1]; action=onerecord[2]; time=onerecord[3]; if(action==0): if(len(my_stack) > 1): parent_method_id=my_stack[-1] handle_one_call(parent_method_id,method_id) my_stack.append(method_id) else: if(action==1): if(len(my_stack) > 1): my_stack.pop()gen_dot_script_file()os.system("dot -Tjpg graph.dot -o output.jpg;rm -f graph.dot");
Modify,/t to \ t,/N to \ n.
Add the following in the source code oncreate of the calculator:
Debug.startMethodTracing(“calc”);Log.v(LOG_TAGS”+++++++++++++++++++++++++test++++++++++++++++”);Debug.stopMethodTracing();
Run the script to obtain Calc. Trace and draw out.jpg
The drawing crashes when the trace file is complex. Modify the parameters when the script finally executes the dot command. The JPG format is too large to crash. Change-tjpg to-tpng: Gd, and draw a large PNG.
I did an experiment with camera and got a huge PNG, which is one of the following:
OK
I'm exhausted, and it's almost again! >_< Good night!