Android中AM、PM、dumpsys命令使用总结
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android中AM、PM、dumpsys命令使用总结相关的知识,希望对你有一定的参考价值。
参考技术Aam指令是 activity manager的缩写,可以启动Service、Broadcast,杀进程,监控等功能,这些功能都非常便捷调试程序。
可以通过adb shell 进入android 的Linux命令界面,输入am -help查看详细命令,先介绍几个简单用法,
命令格式如下
命令列表:
原理分析:am命令实的实现方式在Am.java,最终几乎都是调用ActivityManagerService相应的方法来完成的,am monitor除外。比如前面概述中介绍的命令am start -a android.intent.action.VIEW -d https://amberweather.com , 启动Acitivty最终调用的是ActivityManagerService类的startActivityAsUser()方法来完成的。再比如am kill-all命令,最终的实现工作是由ActivityManagerService的killBackgroundProcesses()方法完成的。
下面说一下[options]和 <INTENT>参数的意义以及如何正确取值。
主要是启动Activity命令am start [options] <INTENT>使用options参数,接下来列举Activity命令的[options]参数:
启动Activity的实现原理: 存在-W参数则调用startActivityAndWait()方法来运行,否则startActivityAsUser()。
命令
例如: 向pid=12345的进程,发出level=RUNNING_LOW的收紧内存命令
level取值范围为: HIDDEN、RUNNING_MODERATE、BACKGROUND、RUNNING_LOW、MODERATE、RUNNING_CRITICAL、COMPLETE
am的子命令,startservice, stopservice, broadcast, kill, profile start, profile stop, dumpheap的可选参数都允许设置--user <USER_ID>。目前市面上的绝大多数手机还是单用户模式,因此可以忽略该参数,默认为当前用户。
例如:启动id=10001的用户的指定service。
Intent的参数和flags较多,为了方便,这里分为3种类型参数,常用参数,Extra参数,Flags参数
实例
(1). 基本类型
参数es是Extra String首字母简称,实例:
(2). 数组类型
参数eia,是Extra int array首字母简称,多个value值之间以逗号隔开,实例:
(3). ArrayList类型
参数efal,是Extra float Array List首字母简称,多个value值之间以逗号隔开,实例:
pm工具为包管理(package manager)的简称,可以使用pm工具来执行应用的安装和查询应用宝的信息、系统权限、控制应用,pm工具是Android开发与测试过程中必不可少的工具,shell命令格式如下:
原理分析:pm命令实的实现方式在Pm.java,最后大多数都是调用PackageManagerService相应的方法来完成的。disbale之后,在桌面和应用程序列表里边都看到不该app。
查看所有的package,
[options]参数:
disabled + enabled = 总应用个数; 系统 + 第三方 = 总应用个数。
查看第3方应用:
查看已经被禁用的包名
<FILTER>参数
当FILTER为不为空时,则只会输出包名带有FILTER字段的应用;当FILTER为空时,则默认显示所有满足条件的应用。
例如,查看包名带有weather字段的包名
[options]参数:
<PATH>参数: 指的是需要安装的apk所在的路径
dumpsys是Android自带的强大debug工具,从名字就可以看出,主要是用于dump 当前android system的一些信息,是一项分析手机问题,运行状态,使用情况等十分有效的手段。
实现原理
dumpsys的源码结构其实很简单,只有一个dumpsys.cpp
/frameworks/native/cmds/dumpsys/dumpsys.cpp
先通过defaultServiceManager()函数获得ServiceManager对象,然后根据dumpsys传进来的参数通过函数checkService来找到具体的service, 并执行该service的dump方法,达到dump service的目的。
不同的Android系统版本支持的命令有所不同,可通过下面命令查看当前手机所支持的dump服务,先进入adb shell,再执行如下命令:dumpsys -l。 这些服务名可能并看不出其调用的哪个服务,可以通过下面指令:service list。
服务列表有很多,这里简单介绍几种
通过下面命令可打印具体某一项服务:dumpsys <service>,其中service便是前面表格中的服务名
接下来主要说下dumpsys activity 用法
命令
options可选值
dumpsys activity等价于依次输出下面7条指令:
cmd可选值
命令
返回结果
上面的输出结果可以分为以下四个部分
也可以只输出某个pid或package的进程信息:
下面以AmberLocker作为实例进行分析
场景1:查询某个App所有的Service状态
解读:Service类名为com.amber.lockscreen.LockerHeartService,包名为mobi.infolife.ezweather.locker.locker_2,baseDir(apk路径)为/data/app/mobi.infolife.ezweather.locker.locker_2-2/base.apk,dataDir((apk数据路径)
运行在进程pid=1115,进程名为进程名为mobi.infolife.ezweather.locker.locker_2,,uid=10060,还有创建时间等信息
场景2:查询某个App所有的广播状态
场景3:查询某个App所有的Activity状态
场景4:查询某个App的进程状态
格式:ProcessRecordHashcode pid:进程名/uid,进程pid=941,进程名为mobi.infolife.ezweather.locker.locker_2:live,uid=10060.
该进程中还有Services,Connections, Providers, Receivers,
场景5:查询栈顶Activity
dumpsys 的命令还有很多,这里就不一一列举了。
Android 进阶——Framework 核心之dumpsys命令浅析
文章大纲
引言
Dumpsys是安卓系统提供用来动态查看系统内部服务运行状态的命令。了解dumpsys命令的使用方法,可以方便我们查看系统中各个进程内存使用情况,各个进程CPU占用率情况,各个应用apk运行情况,系统唤醒源情况等。同时,了解dumpsys命令使用方法的过程也是我们深入了解安卓各个服务的过程。
一、Dumpsys 命令概述
在Android系统中,各个系统服务进程之间主要是通过binder或者socket实现跨进程通信,大部分的服务程序使用binder通信的方式提供API接口,所有使用binder通信方式提供API接口的服务均由一个系统核心的服务管理进程——ServiceManager进程进行同一管理。其中Dumpsys命令就是Android系统提供用来查询ServiceManager中所有服务的状态以及服务内部详细信息的工具,其对应的Dumpsys源码文件——frameworks/native/cmds/dumpsys/dumpsys.cpp,在Android系统编译完成后,dumpsys命令会被打包在system.img中。Dumpsys命令可以理解成Android 独有的shell 程序,使用是 首先adb shell 进入到Android 系统环境,再根据以下发育执行相关命令:
dumpsys [-l][service]
命令 | 说明 |
---|---|
dumpsys | 输出设备中所有服务以及服务内部详细信息 |
dumpsys -l | 输出设备中所有的服务名称 |
dumpsys service | 输出名字为service的服务内部详细信息 |
二、 Dumpsys命令语法详解
1、Package信息查询
命令格式:
dumpsys package [-h][-f][--checkin][cmd]…
参数 | 说明 |
---|---|
-h | 输出package子命令帮助信息 |
-f | 输出intent filter信息 |
–checkin | 输出已经登记的安装包 |
cmd | 子命令(可以在-h中查看有哪些子命令) |
其中子命令:
cmd子命令 | 说明 |
---|---|
prov[iders] | 获取content providers信息 |
p[ackages] | 获取安装包信息 |
s[hared-user] | 获取共享用户ID的应用 |
m[essages] | 打印运行时收集的信息 |
v[erifiers] | 打印包校验信息 |
version | 打印数据库版本信息 |
write | 写当前位置 |
<package.name> | 输出给定包的信息 |
installs | 安装会话的详细信息 |
l[ibraries] | 列出已知的共享库 |
f[ibraries] | 列出手机的功能 |
k[eysets] | 列出各个包的Signing KeySets |
r[esolvers] | 获取intent filter |
2、Activity信息查询
命令格式:
dumpsys activity [-h][-a][-c][-p]…
参数 | 说明 |
---|---|
-h | 输出activity子命令帮助信息 |
-a | 输出所有可用服务端状态 |
-c | 输出客户端状态 |
-p | 输出指定包的activity详细信息 |
cmd | 子命令(可以在-h中查看有哪些子命令) |
子命令:
cmd子命令 | 说明 |
---|---|
a[ctivities] | activity堆栈状态 |
r[recents] | 最近activity的状态 |
b[rodacasts] [package_name] [history [-s]] | 广播状态 |
i[ntents] [package_name] | 挂起的intent状态 |
p[rocesses] [package_name] | 进程状态 |
o[om] | oom管理 |
perm[issions] | URI权限授权状态 |
prov[iders] [comp_spec…] | content provider状态 |
provider [comp_spec] | provider客户端状态 |
s[ervices] [comp_spec…] | 服务状态 |
as[sociations] | 跟踪应用程序的关联 |
service [comp_spec] | 服务客户端状态 |
package [package_name] | 指定包的所有状态 |
all | dump所有activities信息 |
3、网络信息查询
安卓系统网络连接和管理服务由四个系统服务ConnectivityService,NetworkPolicyManagerService,NetworkManagementService,NetworkStatsService共同配合完成网络连接和管理功能。因此,要查看设备网络相关信息,就需要使用dumpsys命令分别查看设备中这些服务的详细信息:
命令 | 说明 |
---|---|
dumpsys connectivity | 查看设备当前网络连接状态 |
dumpsys netpolicy | 查看设备网络策略 |
dumpsys netstats | 查看设备网络状态 |
dumpsys network_management | 查看设备网络管理服务信息 |
4、其他常用服务信息查询
命令 | 说明 |
---|---|
dumpsys meminfo | 查看系统各个进程(某一个进程)内存使用情况 |
dumpsys cpuinfo | 查看系统各个进程CPU占用情况 |
dumpsys power | 查看系统应用申请wakelock情况 |
dumpsys batterstats | 查看系统各个应用(进程)耗电情况 |
dumpsys alarm | 查看系统RTC定时器使用情况 |
dumpsys wifi | 查看wifi网络使用情况 |
dumpsys media.player | 查看系统native播放器以及recorder创建以及使用情况 |
三、Dumpsys命令实现原理
1、安卓binder服务管理
Dumpsys基于安卓的binder通信机制实现,因此了解安卓binder通信机制是基础。安卓binder通信框架如图1所示(Binder通信机制详细内容请参考[1]&[2])。它由客户端程序,服务端程序,ServiceManager进程,binder驱动四大部分组成。Binder即可作为进程间通信也可以作为进程内通信,它的优势在于客户端与服务端通信只需要一次数据拷贝。
如上图所示Binder通信是一个C/S架构,它们通过kernel的binder driver建立通信桥梁。ServiceManager在此框架中的作用相当于一个“路由器”,所有的服务通过addService接口把服务的“句柄”和名字注册到ServiceManager中,应用程序(客户端)调用服务接口时,首先使用ServiceManager的checkService/getService接口通过服务名字获取该服务的“句柄”,然后通过服务“句柄”调用相应的服务接口(BpBinder是client端创建的用于消息发送的代理,而BBinder是server端用于接收消息的通道)。其交互过程如图2所示服务“句柄”管理机制:
2、Dumpsys源码分析
Dumpsys命令在源码位于:frameworks/native/cmds/dumpsys/dumpsys.cpp。
int main(int argc, char* const argv[])
{
//捕捉信号
signal(SIGPIPE, SIG_IGN);
//获取 ServiceManager服务的binder代理对象
sp<IServiceManager> sm = defaultServiceManager();
fflush(stdout);
if (sm == NULL) {
aerr << "dumpsys: Unable to get default service manager!" << endl;
return 20;
}
Vector<String16> services;
Vector<String16> args;
Vector<String16> skippedServices;
bool showListOnly = false;
bool skipServices = false;
int timeoutArg = 10;
static struct option longOptions[] = {
{"skip", no_argument, 0, 0 },
{"help", no_argument, 0, 0 },
{ 0, 0, 0, 0 }
};
while (1) {
int c;
int optionIndex = 0;
//传入的参数转为case 的值
c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
if (c == -1) {
break;
}
switch (c) {
case 0:
if (!strcmp(longOptions[optionIndex].name, "skip")) {
skipServices = true;
} else if (!strcmp(longOptions[optionIndex].name, "help")) {
usage();
return 0;
}
break;
case 't':
{
char *endptr;
timeoutArg = strtol(optarg, &endptr, 10);
if (*endptr != '\\0' || timeoutArg <= 0) {
fprintf(stderr, "Error: invalid timeout number: '%s'\\n", optarg);
return -1;
}
}
break;
case 'l':
showListOnly = true;
break;
default:
fprintf(stderr, "\\n");
usage();
return -1;
}
}
for (int i = optind; i < argc; i++) {
if (skipServices) {
skippedServices.add(String16(argv[i]));
} else {
if (i == optind) {
services.add(String16(argv[i]));
} else {
args.add(String16(argv[i]));
}
}
}
if ((skipServices && skippedServices.empty()) ||
(showListOnly && (!services.empty() || !skippedServices.empty()))) {
usage();
return -1;
}
if (services.empty() || showListOnly) {
// gets all services 通过ServiceManager获取所有的服务
services = sm->listServices();
services.sort(sort_func);
args.add(String16("-a"));
}
const size_t N = services.size();
if (N > 1) {
// first print a list of the current services
aout << "Currently running services:" << endl;
for (size_t i=0; i<N; i++) {
sp<IBinder> service = sm->checkService(services[i]);
if (service != NULL) {
bool skipped = IsSkipped(skippedServices, services[i]);
aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
}
}
}
if (showListOnly) {
return 0;
}
for (size_t i = 0; i < N; i++) {
String16 service_name = std::move(services[i]);
if (IsSkipped(skippedServices, service_name)) continue;
sp<IBinder> service = sm->checkService(service_name);
if (service != NULL) {
int sfd[2];
if (pipe(sfd) != 0) {
aerr << "Failed to create pipe to dump service info for " << service_name
<< ": " << strerror(errno) << endl;
continue;
}
unique_fd local_end(sfd[0]);
unique_fd remote_end(sfd[1]);
sfd[0] = sfd[1] = -1;
if (N > 1) {
aout << "-------------" << endl;
aout << "DUMP OF SERVICE " << service_name << ":" << endl;
}
// dump blocks until completion, so spawn a thread..
std::thread dump_thread([=, remote_end { std::move(remote_end) }]() mutable {
//调用各自服务里的dump函数
int err = service->dump(remote_end.get(), args);
// It'd be nice to be able to close the remote end of the socketpair before the dump
// call returns, to terminate our reads if the other end closes their copy of the
// file descriptor, but then hangs for some reason. There doesn't seem to be a good
// way to do this, though.
remote_end.clear();
if (err != 0) {
aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
<< endl;
}
});
auto timeout = std::chrono::seconds(timeoutArg);
auto start = std::chrono::steady_clock::now();
auto end = start + timeout;
struct pollfd pfd = {
.fd = local_end.get(),
.events = POLLIN
};
bool timed_out = false;
bool error = false;
while (true) {
// Wrap this in a lambda so that TEMP_FAILURE_RETRY recalculates the timeout.
auto time_left_ms = [end]() {
auto now = std::chrono::steady_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
return std::max(diff.count(), 0ll);
};
int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
if (rc < 0) {
aerr << "Error in poll while dumping service " << service_name << " : "
<< strerror(errno) << endl;
error = true;
break;
} else if (rc == 0) {
timed_out = true;
break;
}
char buf[4096];
rc = TEMP_FAILURE_RETRY(read(local_end.get(), buf, sizeof(buf)));
if (rc < 0) {
aerr << "Failed to read while dumping service " << service_name << ": "
<< strerror(errno) << endl;
error = true;
break;
} else if (rc == 0) {
// EOF.
break;
}
if (!WriteFully(STDOUT_FILENO, buf, rc)) {
aerr << "Failed to write while dumping service " << service_name << ": "
<< strerror(errno) << endl;
error = true;
break;
}
}
if (timed_out) {
aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
}
if (timed_out || error) {
dump_thread.detach();
} else {
dump_thread.join();
}
if (N > 1) {
std::chrono::duration<double> elapsed_seconds =
std::chrono::steady_clock::now() - start;
aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
<< "was the duration of dumpsys " << service_name << endl;
}
} else {
aerr << "Can't find service: " << service_name << endl;
}
}
return 0;
}
从上面源码中可知
- sp< IServiceManager > sm = defaultServiceManager(); 获取ServiceManager Binder代理对象
- services = sm->listServices(); 通过ServiceManager获取所有的服务名称
- sp< IBinder > service = sm->checkService(service_name); 通过服务名称获取对应服务的Binder代理对象
- 通过服务的Binder代理对象调用各自的dump 函数
dumpsys调用ServiceManager服务的listServices来查询系统中的所有服务的名称,并且通过checkService方法获取对应服务的binder代理对象,然后通过每个服务binder代理对象调用dump函数来输出该服务的详细信息,因此dumpsys命令输出各个服务的详细信息是没有统一格式的,另外,dump方法提供一个用户输入参数的通道,利用此特性,可以动态修改服务中的某些参数。例如,安卓系统中native层的camera服务,其服务内部的调试打印信息由一个全局变量gLogLevel控制(源码:frameworks/av/services/camera/libcameraservice/CameraService.cpp)。在dump方法中提供了设置gLogLevel的接口:
status_t CameraService::dump(int fd, const Vector<String16>& args) {
//输出CameraService内部详细状态信息
int n = args.size();
for (int i = 0; i + 1 < n; i++) {
//-v 参数用于修改gLogLevel变量
String16 verboseOption("-v");
if (args[i] == verboseOption) {
String8 levelStr(args[i+1]);
int level = atoi(levelStr.string());
result = String8::format("\\nSetting log level to %d.\\n", level);
setLogLevel(level);
write(fd, result.string(), result.size());
}
}
return NO_ERROR;
}
以上是关于Android中AM、PM、dumpsys命令使用总结的主要内容,如果未能解决你的问题,请参考以下文章
Android 进阶——Framework 核心之dumpsys命令浅析