android DDMS 调试的几个关键

第一是能够在DDMS中看到进程和线程

 

首先要将default.prop的debuggable修改为1

使用

https://github.com/liudongmiao/bootimg

实现解压bootimg的修改和打包。

 

使用原来的 先 --unpack-bootimg再--unpack-ramdisk

修改完毕以后

先--repack-ramdisk再--repack-bootimg

使用twrp等刷回去调试

 

调试的时候选中 进程。然后使用Method profile截取信息。记得选择下面的那个全部方法截取,选择上面的采样截取有些函数不能够完全截取到。

截取出来的trace文件可以使用

dmtracedump.exe -ho 11.trace >aa.txt dump成txt或者html格式

 

但是这里面的没区分开来。我们用python根据线程区分出来

def func():
	file=open("aa.txt",'r')
	if not file:
		print("openfile error")
		return
	line=file.readline()
	threaddict={}
	indexdict={}
	revdict={}
	func_container=[]
	index=0
	number=0
	while line:
		while True:
			if not line[0].isdigit():
				break
			
			if " unr " in line:
				break
			if not (" ent " in line or " xit " in line):
				isfunc=False
				pos=line.find(' ')
				threadid=line[0:pos]
				threadname=line[pos+1:len(line)-1]
				threadname=threadname.replace(":","_")
				
				
				threaddict[threadid]=threadid+"_"+threadname
				
				
				indexdict[threadid]=index
				revdict[index]=threadid
				'''
				if threadid=="2599":
					print "number = + ",number
					print threadid
					print threadname
					print threaddict[threadid]
				'''
				index=index+1
				func_container.append([])
				break
			
			idpos=line.find(' ')
			tid=line[0:idpos]
			pointpos=line.find('.')
			funcname=line[pointpos:len(line)-1]
			prefix="ENTER"
			if " ent " not in line:
				prefix="LEAVE"
			func_container[indexdict[tid]].append(prefix+funcname)
			
			break;
		number=number+1
		line=file.readline()
	index=0
	for lst in func_container:
		filename_org=threaddict[revdict[index]]
		filename_filter=filename_org+"_filter"
		filename_org=filename_org+".log"
		filename_filter=filename_filter+".log"
		
		index=index+1
		fileorg=open(filename_org,"w")
		filefilter=open(filename_filter,"w")
		for item in lst:
			if "immomo" in item:
				filefilter.write(item+"\n")
			fileorg.write(item+"\n")
		filefilter.close()
		fileorg.close()
	
	
func()

 

 

 

这个会根据线程将所有的调用CALL区分开来。而且是按顺序的。比如我要找一个按钮事件。

开始method profile 点击按钮 停止method profile 得到这个trace然后搜索OnClick基本就能看懂整个流程了

哈哈哈哈 随便分析

 

 

DDMS的MethodProfiling流程

由DDMS发送调用

startMethodTracer 发送请求给 android的服务进程

/**
     * Send a MPRS (Method PRofiling Start) request to the client.
     *
     * The arguments to this method will eventually be passed to
     * android.os.Debug.startMethodTracing() on the device.
     *
     * @param fileName is the name of the file to which profiling data
     *          will be written (on the device); it will have {@link DdmConstants#DOT_TRACE}
     *          appended if necessary
     * @param bufferSize is the desired buffer size in bytes (8MB is good)
     * @param flags see startMethodTracing() docs; use 0 for default behavior
     */
android.os.Debug.startMethodTracing()

结果startMethodTracing又调用了VMDebug

public static void startMethodTracing(String traceName, FileDescriptor fd,
        int bufferSize, int flags) {
        VMDebug.startMethodTracing(traceName, fd, bufferSize, flags, false, 0);
    }

import dalvik.system.VMDebug;

 

VMDebug 根据参数调用了

 private static native void startMethodTracingDdmsImpl(int bufferSize, int flags, boolean samplingEnabled, int intervalUs);
    private static native void startMethodTracingFd(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs);
    private static native void startMethodTracingFilename(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs);

这几个都是native函数

art\runtime\native\dalvik_system_VMDebug.cc

startMethodTracingFilename{

调用Trace的

 Trace::Start(traceFilename.c_str(), -1, bufferSize, flags, Trace::TraceOutputMode::kFile,
               samplingEnabled ? Trace::TraceMode::kSampling : Trace::TraceMode::kMethodTracing,
               intervalUs);

}

Start函数位于art/runtime/trace.cc

主要是

 runtime->GetInstrumentation()->AddListener(the_trace_,
                                                   instrumentation::Instrumentation::kMethodEntered |
                                                   instrumentation::Instrumentation::kMethodExited |
                                                   instrumentation::Instrumentation::kMethodUnwind);
        // TODO: In full-PIC mode, we don't need to fully deopt.
        runtime->GetInstrumentation()->EnableMethodTracing(kTracerInstrumentationKey);

 

在当前runtime的instrumentation增加了一个Listener

这个listener被添加到了

art\runtime\instrumentation.cc的 method_entry_listeners_链表中

主要有这几个

std::list<InstrumentationListener*> method_entry_listeners_ GUARDED_BY(Locks::mutator_lock_);
  std::list<InstrumentationListener*> method_exit_listeners_ GUARDED_BY(Locks::mutator_lock_);
  std::list<InstrumentationListener*> method_unwind_listeners_ GUARDED_BY(Locks::mutator_lock_);
  std::list<InstrumentationListener*> branch_listeners_ GUARDED_BY(Locks::mutator_lock_);
  std::list<InstrumentationListener*> invoke_virtual_or_interface_listeners_
      GUARDED_BY(Locks::mutator_lock_);
  std::list<InstrumentationListener*> dex_pc_listeners_ GUARDED_BY(Locks::mutator_lock_);
  std::list<InstrumentationListener*> field_read_listeners_ GUARDED_BY(Locks::mutator_lock_);
  std::list<InstrumentationListener*> field_write_listeners_ GUARDED_BY(Locks::mutator_lock_);
  std::list<InstrumentationListener*> exception_caught_listeners_ GUARDED_BY(Locks::mutator_lock_);

 

在Instrumentation中每次有方法进入的时候会执行 MethodEnterEventImpl函数

void Instrumentation::MethodEnterEventImpl(Thread* thread, mirror::Object* this_object,
                                           ArtMethod* method,
                                           uint32_t dex_pc) const {
  if (HasMethodEntryListeners()) {
    for (InstrumentationListener* listener : method_entry_listeners_) {
      if (listener != nullptr) {
        listener->MethodEntered(thread, this_object, method, dex_pc);
      }
    }
  }
}

会对每个加载的Listener执行MethodEntered函数

也就是Trace.cc的Trace类

后续再看采集了什么数据。先看看是如何进入函数的。MethodEnterEvent.h调用MethodEnterEvent进入MethodEnterEventImpl

 

主要是在art\runtime\interpreter\interpreter.cc中Execute 调用了

static inline JValue Execute(
    Thread* self,
    const DexFile::CodeItem* code_item,
    ShadowFrame& shadow_frame,
    JValue result_register,
    bool stay_in_interpreter = false) SHARED_REQUIRES(Locks::mutator_lock_) {

    if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
      instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
                                        method, 0);
    }

调用Execute的地方

有几个 

EnterInterpreterFromInvoke   

ArtMethod::Invoke中 满足条件if (UNLIKELY(!runtime->IsStarted() || Dbg::IsForcedInterpreterNeededForCalling(self, this)))

EnterInterpreterFromDeoptimize

EnterInterpreterFromEntryPoint

ArtInterpreterToInterpreterBridge

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值