dumpstate的结构
dumpState log在Android开发中是解决问题的重要途径之一,dumpstate文件一般有几十万行的log,要从这么多log中找出想要的关键信息,如果不掌握一定的技巧,俨然大海捞针。先从总体上了解dumpstate的结构,以至于不会迷失在log海当中.
dumpstate解析
对于三星型号,电话盘输入*#9900#进入以下界面
这个界面的代码在android\vendor\samsung\packages\apps\MSP\FactoryTest\ServiceModeApp\src\com\sec\android\app\servicemodeapp\app\SysDump.java
这里只分析点击第三项RUN DUMPSTATE/LOGCAT为例,实际运行的主要代码是
Runtime.getRuntime().exec("bugreport >/data/log/dumpstate_sysdump_time.log");
这里运行了bugreport程序,并将结果重定位到log文件中,这个log文件就是我们所说的dumpstate log了
bugreport的代码位于android\frameworks\native\cmds\bugreport\Bugreport.c
dumpstate的代码位于android\frameworks\native\cmds\dumpstate\Dumpstate.c
在bugreport中,先启动dumpstate的service
dumpstate类似于dumpsys都是android提供给开发者的帮助了解系统运行状态的利器。
从main函数看起:
1. 设置执行dumpstate这个命令的进程的一些属性
使它不会占用过多系统资源,即利用setpriority来告知内核它可以随时被调度
因为在手机系统信息,通过proc/self/oom_adj接口来告知内核(-17这是一个特殊的参数,详见man proc),在寻找可以被kill掉的进程时,忽略该进程。
/* set as high priority, and protect from OOM killer */
setpriority(PRIO_PROCESS, 0, -20);
FILE *oom_adj = fopen("/proc/self/oom_adj", "w");
if (oom_adj) {
fputs("-17", oom_adj);
fclose(oom_adj);
}
2. 如果有root权限,就可以从dalvik处获得各种dalvik提供的trace信息
利用了utils/中的dump_vm_traces函数,
其中通过proc/[pid]/exe的link的程序如果是app_process,再找到对应pid下的cmdline过滤掉根 zygote,即得到所有由Android系统通过zygote所fork出来的所有的dalvik process(即各个APK)。
从这里可以看出,所有的APK都是由app_process这个应用从跟zygote所fork出来。
例如,
#ps
...
app_67 9986 172 99464 21012 ffffffff afd0c75c S com.keramidas.TitaniumBackup
app_80 9995 172 116304 32656 ffffffff afd0c75c S com.hiapk.marketpho
...
# ls -l /proc/9986/exe
lrwxrwxrwx 1 app_67 app_67 0 Oct 19 15:12 /proc/9986/exe -> /system/bin/app_process
# cat /proc/9986/cmdline
com.keramidas.TitaniumBackup#
3. 解析参数
中间一个有一个关于使用socket的参数值得看一下
它使用到了由init.rc中定义的专门给dumpstate使用的socket
service dumpstate /system/bin/dumpstate -s
socket dumpstate stream 0660 shell log
disabled
oneshot
相关启动各种系统service的init.rc的命令参见/init/readme.txt
4. 如果有root权限,拿到控制vibrator的权限和获得kernel启动的cmd参数
vibrator用来在dumpstate结束之后震动以提示用户。这是一个在嵌入式设备中常用的提示技巧,有时候也会用简单一个声音提示。
kernel的启动参数会在dump出来的信息中显示。
5. 根据dumpstate的参数做一些简单的准备,然后调用dumpstate()
关键的dumpstate函数
5.1 通过property_get获得一些从kernel cmdline及vendor提供的property信息(参见default.prop, build.prop中的预设值)
5.2 通过proc系统获得各种内存管理系统提供的信息(如, /proc/meminfo, top等等),其中利用了android提供的一个procrank命令获得制定进程的信息(参见我的另一篇文章,《Android性能分析工具之procrank》)
5.3 dump logcat中的信息和一些网络信息(netcfg, /proc/net/XXX下的内容)
5.4 dump 一些dalvik收集的trace信息
5.5 dump properties信息
5.6 各种通过sysfs接口暴露出来的kernel信息
5.7 vold, native packages, led灯等信息
5.8 调用dumpsys,显示dumpsys的信息
6. dumpstate()结束之后的一些后续处理(文件copy,压缩等等)
Log工具
要打印一句log,通过这样的方法,Log.i("csf", "log test");
Log源码在android\frameworks\base\core\java\android\util\Log.java,看Log.i的实现
public static int i(String tag, String msg) {
return println_native(LOG_ID_MAIN, INFO, tag, msg);
}
打印堆栈Log的方式
android.util.Log.d(TAG,"nnn"+android.util.Log.getStackTraceString(new Throwable()));
在native层实现,android\frameworks\base\core\jni\android_util_Log.cpp
static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
const char* tag = NULL;
const char* msg = NULL;
if (msgObj == NULL) {
jniThrowNullPointerException(env, "println needs a message");
return -1;
}
if (bufID < 0 || bufID >= LOG_ID_MAX) {
jniThrowNullPointerException(env, "bad bufID");
return -1;
}
if (tagObj != NULL)
tag = env->GetStringUTFChars(tagObj, NULL);
msg = env->GetStringUTFChars(msgObj, NULL);
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
if (tag != NULL)
env->ReleaseStringUTFChars(tagObj, tag);
env->ReleaseStringUTFChars(msgObj, msg);
return res;
}
真面目还藏在__android_log_buf_write()函数中,这个函数在android\system\core\liblog\logd_write.c中
通过分析,总结出下面,具体请查看源码
通过Log.d、Log.i、Log.v等输出的log保存在/dev/log/main这个缓冲区中,一般app用这种方式打log
通过Rlog.d、Rlog.v、Rlog.i等输出的log保存在/dev/log/radio这个缓冲区中,一般射频、SIM、telephony模块用这个比较多
通过Slog.d、Slog.v、Slog.i等输出的log保存在/dev/log/system这个缓冲区中,很多framework的log都用Slog
通过EventLog.writeEvent输出的log保存在/dev/log/events这个缓冲区中,一般用在framework模块中
查看FrameWork所有service的信息,实际上运行的是dumpsys serviceName
比如:
dumpsys account列出所有账户
dumpsys activity activity的相关信息
dumpsys的代码在android\frameworks\native\cmds\dumpsys\dumpsys.cpp
从源码实现中看,是遍历所有的service,然后调用service->dump()方法,比如查看EmailService的栈
EmailContent$Account.dumpAccountInfo(Context) line: 7597
EmailSyncServiceLogger.dumpAllAccountInfo(Context, PrintWriter) line: 768
EmailService.dump(FileDescriptor, PrintWriter, String[]) line: 395
ActivityThread.handleDumpService(ActivityThread$DumpComponentInfo) line: 3655
dumpsys activity all -> 所有task和task上activity,activity的view Hierachy
dumpsys activity service all ->所有app service的信息
具体参考源码dumpstate.cpp的dumpsys_other()函数
一些关键字
1、广播相关信息
ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)
Registered Receivers 列出系统中所有动态注册的广播接收者ReceiverList,该结构包含一些Intent filter,比如下面的log
ReceiverList{27d9778 18700 system/1000/u0 local:com.android.server.AlarmManagerService$UninstallReceiver@86fd5ea,7c790db}
app=18700:system/1000 pid=18700 uid=1000 user=0
Filter #0: BroadcastFilter{2703e51}
Action: "android.intent.action.PACKAGE_REMOVED"
Action: "android.intent.action.PACKAGE_RESTARTED"
Action: "android.intent.action.PACKAGE_DATA_CLEARED"
Action: "android.intent.action.QUERY_PACKAGE_RESTART"
Scheme: "package"
AutoVerify=false
Filter #1: BroadcastFilter{6d66b6}
Action: "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE"
Action: "android.intent.action.USER_STOPPED"
Action: "android.intent.action.UID_REMOVED"
AutoVerify=false
存在Filter #0 和 Filter #1,说明UninstallReceiver这个receiver动态注册了两次,两次注册的filter分别有所不同,过滤的action有所不同,查看AlaramManagerService.java的源码后也确实如此
public UninstallReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme("package");
getContext().registerReceiver(this, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
sdFilter.addAction(Intent.ACTION_UID_REMOVED);
getContext().registerReceiver(this, sdFilter);
}
Historical Broadcast foreground 列出位于前台的历史广播
Historical Broadcast background 列出位于后台的历史广播
经常可以查看广播从哪里发出。
2、虚拟机信息
Dalvik Thread
3、查看系统登录了哪些账号
DUMP OF SERVICE account:
属于dumpstate的第四个阶段的DumpsysAll中的dumpsys account
4、等待的intent的状态
ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)
5、所有所有注册的broadcastReceiver及其filter、action的信息
ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)
6、显示所有content providers信息
ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)
7、当前active状态的service信息
ACTIVITY MANAGER SERVICES (dumpsys activity services)
上述4、5、6、7都是发生在dumpsys activity的过程中
8、查看CPU最近的使用情况
DUMP OF SERVICE cpuinfo:
9、查看系统上db的相关情况,app的数据库最近的操作情况
DUMP OF SERVICE dbinfo
10、查看当前的notification,每个NotificationRecord记录一个通知
DUMP OF SERVICE notification
11、查看某个包的信息,包名是AndroidManifest.xml中的包名
Package [com.samsung.android.email.provider]
这里也可以查看app的版本
12、查看是否发生了ANR
WINDOW MANAGER LAST ANR (dumpsys window lastanr)
13、查看data是否连接的信息
DUMP OF SERVICE connectivity
14、查看email service的相关信息
SERVICE com.samsung.android.email.provider/com.samsung.android.email.sync.service.EmailService
SERVICE com.samsung.android.email.provider/com.samsung.android.email.sync.exchange.ExchangeService
15、查看Email是否收到新邮件,更新badge
11-16 14:50:54.314: D/BadgeCache(12920): 1. updateBadgeCounts: com.samsung.android.email.provider = 2,2表示badge的数量
16、查看手机芯片
Chip Name
17、手机使用的网络
Network: China Telecom
18、Debug Level : 1
19、语言Current Lang Name : English (US)
20、查看是哪里启动当前activity,可查看event log
如查到当前activity的event log:am_create_activity
可查看前面am_on_stop_called,am_destroy_activity,am_finish_activity,am_pause_activity,便可以推断出是哪里启动当前activity
21、查看每个进程的流量消耗
------ QTAGUID STATS INFO (/proc/net/xt_qtaguid/stats) ------
idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets