一概述

本文档主要是供Android开发人员使用,特别是Framework开发。因为Framework95%以上的问题都是靠分析log解决的,所以开发人员必须对android整个log系统十分清楚。什么问题抓什么log,使用什么工具抓Log,如何分析log,如何在代码中添加log.

DDMSlog

关于ddms是如何工作的和ddms的详细功能,见下面androidsdk中文档详细介绍:

F:\02Android\01_SDK\Gingerbread2.3\docs-2.3_r01-linux\guide\developing\tools\ddms.html

Ddms工具中打印log的几个菜单如下:

Device->Showprocessstatus

Device->Dumpdevicestate

Device->Dumpappstate

Device->Dumpradiostate

Device->Runlogcat

1、Showprocessstatus…菜单

等效于在adbshell下执行adbshellpsx命令,该命令打印出进程的详细信息,如下:

USERPIDPPIDVSIZERSSWCHANPCNAME

root10268180c009b74c 0000875c  S/init(u:2,s:371)

root2000c004e72c 00000000 Skthreadd(u:0,s:1)

root3200c003fdc8 00000000 Sksoftirqd/0(u:0,s:0)

root4200c004b2c4 00000000 Sevents/0(u:0,s:39)

root5200c004b2c4 00000000 Skhelper(u:0,s:0)

root6200c004b2c4 00000000 Ssuspend(u:0,s:0)

  USER用户名,即用户所在组

PID进程IDProcessID

PPID父进程的进程IDParentProcessid

VSZ进程所使用的虚拟内存的大小(VirtualSize

RSS进程使用的驻留集大小或者是实际内存的大小,Kbytes字节。

WCHAN进程正在睡眠的内核函数名称;该函数的名称是从/root/system.map文件中获得的

ExploringProcesses

Youcanseetheoutputofps-xforaspecificVMbyselectingDevice>Showprocessstatus...inthemenubar.

2、Dumpdevicestate…菜单

等效于执行/system/bin/dumpstate /proc/self/fd/0

等效于执行adbshelldumpstate命令

TorundumpstatefromDalvik,selectDevice>Dumpdevicestate...inthemenubar.

3、Dumpappstate…菜单

等效于执行adbshelldumpsys命令

输出android服务状态信息,即输出服务中dump函数的log.

4、Dumpradiostate…菜单

等效于执行adbshellcat/data/logs/radio命令

ExamineRadioState

Bydefault,radiostateisnotoutputduringastandardlogcat(itisalotofinformation).Toseeradioinformation,eitherclickDevice>Dumpradiostate...orrunlogcatasdescribedinLoggingRadioInformation.

5、Runlogcat…菜单

等效于执行adblogcat

Torundumpsys(logcat)fromDalvik,selectDevice>Runlogcat...inthemenubar.

总结:除了Runlogcat菜单是实时输出设备中的log外,其他菜单都是输出设备中缓存的log

AdbLog

Androidsdk文档中对adb的介绍见下:

F:\02Android\01_SDK\Gingerbread2.3\docs-2.3_r01-linux\guide\developing\tools\adb.html

adb1.0.26版本共有2条命令打印log,如下:

adblogcat[<filter-spec>]-Viewdevicelog

adbbugreport-returnallinformationfromthedevice

thatshouldbeincludedinabugreport.

Adblogcat常用命令

logcat-c清除已有log信息

logcat-bmain显示主缓冲区的log

logcat-bradio显示无线缓冲区的log

logcat-bevents显示事件缓冲区的log

logcat-f[filename]log保存到指定的文件中,例如logcat-bradio-f/data/radio.log

比较常用的是显示时间:logcat-vtime&

logcat-g查看缓冲区的大小

logcat-gmain

logcat-gradio

logcat-gevents

logcat打印/dev/log设备下的三个文件radio,events,main数据

logcat默认是输出main缓冲区的log

控制日志输出格式

日志信息包括了许多元数据域包括标签和优先级。可以修改日志的输出格式,所以可以显示出特定的元数据域。可以通过-v选项得到格式化输出日志的相关信息.

brief—Displaypriority/tagandPIDoforiginatingprocess(thedefaultformat).

process—DisplayPIDonly.

tag—Displaythepriority/tagonly.

thread—Displayprocess:threadandpriority/tagonly.

raw—Displaytherawlogmessage,withnoothermetadatafields.

time—Displaythedate,invocationtime,priority/tag,andPIDoftheoriginatingprocess.

long—Displayallmetadatafieldsandseparatemessageswithablanklines.

当启动了logcat,你可以通过-v选项来指定输出格式:

[adb]logcat[-v<format>]

此外,adbshellcmd,cmd/system/bin目录下抓log的可执行程序,如dumpsys,dumpstate

Adb下的log命令:

Adblogcat

Adbbugreport

Adbshelldumpsys

Adbshelldumpstate

Adbshelldmesg//导出当前缓存的kernellog

Adbshellkmsgcat//实时查看kernellog

其他查看系统当前信息命令

Adbshellps//查看系统进程信息,可以加很多有用信息

Adbshellpm//查看package相关信息

Adbshellam//启动apk应用

Adbshellsetprop//设置系统属性

Adbshellgetprop//查看所有系统属性

Adbshellreboot

Adbshellkill//通过进程ID杀死指定的进程

Adbshelltop//查看当前运行进程信息

Adbshellvmstat//查看虚拟机信息

Adbshellbootanimation//播放开机动画

Adbshelldf//查看分区信息

Adbshellmonkey//跑自动化测试用例

四保存在手机的Log

1、手机dropbox默认路径:

/data/system/dropbox/

实现机制:

log文件什么场景产生?

Log文件分析:

2、手机anr日志默认路径:

/data/anr/

实现机制:

log文件什么场景产生?

Log文件分析:

4tombstones路径:

/data/tombstones

log文件什么场景产生?

Log文件分析:

五如何实现后台抓Log

如:

adblogcat-vtime-r1024-n16-f/sdcard/bugreports/applogcat-log

log执行程序实现机制

1Logcat

LogCat是在文件system/core/logcat/logcat.cpp中实现的。

Logger设备驱动的实现知道,Log的读取是阻塞的操作,亦即,有数据可用,读出数据;否则,读操作会被BLOCK,相应的读进程也会被挂起等待。下面看应用程序LogCat中如何实现读的,这可能需要不断回头与写操作和驱动实现结合来看。

看具体实现之前,先看一个logcat中定义的重要的结构体log_device_t。其中的重要的成员在后面用到的时候再具体解释。

AndroidLogcat命令详解的命令参数-b<buffer>知道,logcat是可以通过参数来指定对哪个buffer(main/radio/event)进行操作的。Logcatb参数解析的地方,是通过传递进来的参数(main/radio/event)来创建了一个上面的结构变量,而这些结构通过log_device_t.next链接起来

因为logcat可能会同时操作多个Buffer,而read()会阻塞读取进程,对其他Buffer的读取就不能进行,所以这里用select()来判断可读取的Buffer

2Bugreport

I:\00_AndriodSource\android-gingerbread-src\frameworks\base\cmds\bugreport

#include<cutils/properties.h>

#include<cutils/sockets.h>

intmain(intargc,char*argv[]){

charbuffer[65536];

inti,s;

/*startthedumpstateservice*/

property_set("ctl.start","dumpstate");//启动dumpstate服务

/*socketwillnotbeavailableuntilservicestarts*/

for(i=0;i<10;i++){

s=socket_local_client("dumpstate",

ANDROID_SOCKET_NAMESPACE_RESERVED,

SOCK_STREAM);

if(s>=0)

break;

/*tryagainin1second*/

sleep(1);

}

if(s<0){

fprintf(stderr,"Failedtoconnecttodumpstateservice\n");

exit(1);

}

while(1){

intlength=read(s,buffer,sizeof(buffer));

if(length<=0)

break;

fwrite(buffer,1,length,stdout);

}

close(s);

return0;

}

原理:启动dumpstate服务,通过socket连接dumpstate服务,然后从socket中不断读取dumpstate侧的log打印出来

通过代码分析和实际对比分析,发现bugreport输出的logdumpstate输出的log完全一致。

3Dumpstate

I:\00_AndriodSource\android-gingerbread-src\frameworks\base\cmds\dumpstate

输出的信息包括:

1、版本信息

2、系统状态信息:CPU内存进程系统属性等

3、Logcat信息

4、Dumpsys输出的所以services信息

5、ANRlog信息

6、Dmesgkernellog信息

会运行下面命令输出log

run_command("CPUINFO",10,"top","-n","1","-d","1","-m","30","-t",NULL);

run_command("PROCRANK",20,"procrank",NULL);

run_command("SYSTEMLOG",20,"logcat","-v","time","-d","*:v",NULL);

run_command("EVENTLOG",20,"logcat","-b","events","-v","time","-d","*:v",NULL);

run_command("RADIOLOG",20,"logcat","-b","radio","-v","time","-d","*:v",NULL);

run_command("NETWORKINTERFACES",10,"netcfg",NULL);

run_command("KERNELLOG",20,"dmesg",NULL);

run_command("VOLDDUMP",10,"vdc","dump",NULL);

run_command("SECURECONTAINERS",10,"vdc","asec","list",NULL);

run_command("PROCESSES",10,"ps","-P",NULL);

run_command("PROCESSESANDTHREADS",10,"ps","-t","-p","-P",NULL);

run_command("LIBRANK",10,"librank",NULL);

run_command("FILESYSTEMS&FREESPACE",10,"df",NULL);

run_command("LASTRADIOLOG",10,"parse_radio_log","/proc/last_radio_log",NULL);

run_command("DUMPSYS",60,"dumpsys",NULL);

4Dumpsys

I:\00_AndriodSource\android-gingerbread-src\frameworks\base\cmds\dumpsys

constsize_tN=services.size();

if(N>1){

//firstprintalistofthecurrentservices

aout<<"Currentlyrunningservices:"<<endl;

for(size_ti=0;i<N;i++){

sp<IBinder>service=sm->checkService(services[i]);

if(service!=NULL){

aout<<""<<services[i]<<endl;

}

}

}

for(size_ti=0;i<N;i++){

sp<IBinder>service=sm->checkService(services[i]);

if(service!=NULL){

if(N>1){

aout<<"------------------------------------------------------------"

"-------------------"<<endl;

aout<<"DUMPOFSERVICE"<<services[i]<<":"<<endl;

}

interr=service->dump(STDOUT_FILENO,args);//调用每个service中的dump()方法输出log

if(err!=0){

aerr<<"Errordumpingserviceinfo:("<<strerror(err)

<<")"<<services[i]<<endl;

}

}else{

aerr<<"Can'tfindservice:"<<services[i]<<endl;

}

}

输出log信息代码如上,结合实际log分析,dumpsys输出系统服务dump信息

七其他方法技巧

1、通过设置系统属性打开log开关

如有如下打印log的代码:

if(Log.isLoggable(TAG,Log.DEBUG)){

Log.d(TAG,"RedirectrequestedbutnoLocation"

+"specified.");

}

我们只需要通过设置系统属性就可以打印出这个log,而不用修改代码。可以通过setprop命令或修改build.prop来达到目的。具体见Log.java中的介绍:

/**

*Checkstoseewhetherornotalogforthespecifiedtagisloggableatthespecifiedlevel.

*

*ThedefaultlevelofanytagissettoINFO.Thismeansthatanylevelaboveandincluding

*INFOwillbelogged.Beforeyoumakeanycallstoaloggingmethodyoushouldchecktosee

*ifyourtagshouldbelogged.Youcanchangethedefaultlevelbysettingasystemproperty:

*'setproplog.tag.<YOUR_LOG_TAG><LEVEL>'

*WhereleveliseitherVERBOSE,DEBUG,INFO,WARN,ERROR,ASSERT,orSUPPRESS.SUPRESSwill

*turnoffallloggingforyourtag.Youcanalsocreatealocal.propfilethatwiththe

*followinginit:

*'log.tag.<YOUR_LOG_TAG>=<LEVEL>'

*andplacethatin/data/local.prop.

*

*@paramtagThetagtocheck.

*@paramlevelTheleveltocheck.

*@returnWhetherornotthatthisisallowedtobelogged.

*@throwsIllegalArgumentExceptionisthrownifthetag.length()>23.

*/

publicstaticnativebooleanisLoggable(Stringtag,intlevel);

1.查看当前堆栈

1)功能:在程序中加入代码,使可以在logcat中看到打印出的当前函数调用关系

2)方法:

newException(“printtrace”).printStackTrace();

2.MethodTracing

1)功能:用于热点分析和性能优化,分析每个函数占用的CPU时间,调用次数,函数调用关系等

2)方法:

a)在程序代码中加入追踪开关

importandroid.os.Debug;

……

android.os.Debug.startMethodTracing(/data/tmp/test);//先建/data/tmp目录

……//被追踪的程序段

android.os.Debug.stopMethodTracing();

b)编译,运行后,设备端生成/data/tmp/test.trace文件

c)trace文件复制到PC

$adbpull/data/tmp/test.trace./

d)使用android自带工具分析trace文件

$$ANDROID_SRC/out/host/linux-x86/bin/traceviewtest.trace

此时可看到各个函数被调用的次数CPU占用率等信息

e)使用android自带工具分析生成调用关系类图

$apt-getinstallgraphviz#安装图片相关软件

$ANDROID_SRC/out/host/linux-x86/bin/dmtracedump-gtest.pngtest.trace

此时目录下生成类图test.png

3)注意

trace文件生成与libdvm模块DEBUG版本相冲突,所以此方法只适用于对非DEBUG版本模拟器的调试,否则在分析trace文件时会报错

3.HProf(HeapProfile)

1)功能:

用于java层面的内存分析,显示详细的内存占用信息,指出可疑的内存泄漏对象

2)方法:

a)在代码中加入dump动作

importandroid.os.Debug;

importjava.io.IOException;

……

try{

android.os.Debug.dumpHprofData(/data/tmp/input.hprof);//先建/data/tmp目录

}catch(IOExceptionioe){

}

b)hprof文件复制到PC

$adbpull/data/tmp/input.hprof./

c)使用命令hprof-convhprof转成MAT识别的标准的hprof

$$ANDROID_SRC/out/host/linux-x86/bin/hprof-convinput.hprofoutput.hprof

d)使用MAT工具看hprof信息

下载MAT工具:http://www.eclipse.org/mat/downloads.php

用工具打开output.hprof

3)注意:此工具只能显示java层面的,而不能显示C层的内存占用信息

4.SamplingProfile(android2.0上版本使用)

1)功能

每隔N毫秒对当前正在运行的函数取样,并输出到log

2)在代码中加入取样设定

importdalvik.system.SamplingProfiler

……

SamplingProfilesp=SamplingProfiler.getInstance();

sp.start(n);//n为设定每秒采样次数

sp.logSnapshot(sp.snapshot());

……

sp.shutDown();

它会启一个线程监测,在logcat中打印信息

5.用发系统信号的方式取当前堆栈情况和内存信息

1)原理

dalvik虚拟机对SIGQUITSIGUSR1信号进行处理(dalvik/vm/SignalCatcher.c),分别完成取当前堆栈和取当前内存情况的功能

2)用法

a)$chmod777/data/anr-R#anr目录权限设为可写

$rm/data/anr/traces.txt#删除之前的trace信息

$ps#找到进程号

$kill-3进程号#发送SIGQUIT信号给该进程,此时生成trace信息

$cat/data/anr/traces.txt

功能实现:遍历threadlist(dalvik/vm/Thread.c:dvmDumpAllThreadEx()),并打印当前函数调用关系(dalvik/vm/interp/Stack.c:dumpFrames())

b)$chmod777/data/misc-R

$ps#找到进程号

$kill-10进程号#发送SIGQUIT信事信号给该进程,此时生成hprof信息

$ls/data/misc/*.hprof

此时生成hprf文件,如何使用此文件,见第二部分(HProf)

注意:hprof文件都很大,注意用完马上删除,以免占满存储器

6.logcat及原理

1)android.util.Log利用println的标准java输出词句,并加前缀I/V/D.

2)dalvik利用管道加线程的方式,先利用dup2stdoutstderr重定向到管理中(vm/StdioConverter.c:dvmstdioConverterStartup),然后再启动一个线程从管道另一端读出内容(dalvik/vm/StdioConverter.c:stdioconverterThreadStart()),使用LOG公共工具(system/core/liblog/logd_write.c:__android_log_print())输出到/dev/log/*中去

LogCat是在文件system/core/logcat/logcat.cpp中实现的

7.monkey

1)monkey是一个android自带的命令行工具。它向系统发送伪随机的用户事件流,实现对正在开发的应用程序进行压力测试。

2)方法

在设备端打开setting界面

$adbshell

#monkey-pcom.android.settings-v500

此时可以看到界面不断被切换

8.其它小工具

具体见android.os.Debug中提供的工具

1)取毫微秒级的时间,用于计算时间

threadCpuTimeNanos()

2)统计两点间的内存分配情况

startAllocCounting()

stopAllocCounting()

getGlobalAllocCount()

get…..

3)打印当前已loadclass

getLoadedClassCount()

printLoadedClasses()它需要打开NDEBUG功能才能打开system/core/Log功能

更多相关文章

  1. NPM 和webpack 的基础使用
  2. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  3. Android(安卓)NDK编程入门笔记
  4. android init进程说明
  5. Android(java)学习笔记135:Android中assets文件夹资源的访问
  6. Android程序结构
  7. android Manifest.xml全局配置文件中根标签中package属性及标签
  8. Java多种方式动态生成doc文档
  9. Android高手进阶教程(四)之----Android(安卓)中自定义属性(attr.

随机推荐

  1. hbase 学习
  2. 邮件加密的第三道坎是密钥管理
  3. 前端js是什么意思?
  4. Photoshop Elements:做出完美大合照,让笑容
  5. 我用注解实现了优雅的跨库查询,架构师竖起
  6. NA(Nirvana)公链“为应用而生” NAC公链
  7. Vsftpd虚拟用户登录
  8. 设计模式3之抽象工厂模式
  9. 这款手绘风格的在线制图软件超棒
  10. 什么是Exadata Smart Scan?