作为一个Android开发者,对adb的使用都不会陌生。
Android 调试桥 (adb) 是一种功能多样的命令行工具,可让您与设备进行通信。adb 命令可用于执行各种设备操作(例如安装和调试应用),并提供对 Unix shell(可用来在设备上运行各种命令)的访问权限。这里就不做更多介绍了。更多adb 命令使用请访问 https://developer.android.com/studio/command-line/adb 进一步了解。
今天想说的是adb shell命令的使用 ,shell 模式下有很多可以使用的命令,可以通过adb shell ls /system/bin/ 查看,也可以先adb shell进入交互模式,然后再进入/system/bin/ 查看
我们可以发现很多命令和我们平常使用的Linux命令很相识。比如chomd ,cat 等等。其实一些常用的命令就可以解决我们平时遇到的绝大多数的问题。
adb shell dumpsys
adb shell settings
adb shell am/pm
adb shell setprop/getprop
我们先以dumpsys命令为例,其他命令过程类似。
dumpsys介绍
dumpsys 是一种在 Android 设备上运行的工具,可提供有关系统服务的信息。获取在连接的设备上运行的所有系统服务的诊断输出。此输出通常比想要的更详细,因此需要使用命令行选项进行过滤,仅获取感兴趣的系统服务的输出。
语法
使用 dumpsys 的一般语法如下:
获取所连接设备的所有系统服务的诊断输出,只需运行 adb shell dumpsys。
例如:
- dumpsys activity //查询AMS服务相关信息
- dumpsys window //获取所有window相关的信息
- dumpsys cpuinfo //查询CPU情况
- dumpsys meminfo //查询内存情况
可查询的服务有很多,可通过下面任一命令查看当前系统所支持的dump服务:
- adb shell dumpsys -l
- adb shell service list
果要使输出更加可控,还需要在命令中添加相应服务来进行指定。
命令行选项
下表列出了使用 dumpsys 时的可用选项。
选项 | 说明 |
-t timeout | 指定超时期限(秒)。如果未指定,默认值为 10 秒。 |
--help | 输出 dumpsys 工具的帮助文本。 |
-l | 输出可与 dumpsys 配合使用的系统服务的完整列表。 |
--skip services | 指定您不希望包含在输出中的 services。 |
service [arguments] | 指定您希望输出的 service。某些服务可能允许您传递可选 arguments。您可以通过将 -h 选项与服务名称一起传递来了解这些可选参数,如下所示: |
-c | 指定某些服务时,附加此选项能以计算机可读的格式输出数据。 |
dumpsys方法在分析服务状态和信息十分有用。那我们执行命令后,系统是怎么响应我们把信息dump出来的呢?
dumpsys 实现原理
既然dumpsys 是一个可执行文件,必然是先找到其mk文件:/frameworks/native/cmds/dumpsys/Android.mk
1.int main(int argc, char* const argv[]){
2. ...
3. sp<IServiceManager> sm = defaultServiceManager();
4. ...
5. Vector<String16> services;
6. ...
7. services = sm->listServices();
8. ...
9. const size_t N = services.size();
10.
11. for (size_t i = 0; i < N; i++) {
12. const String16& serviceName = services[i];
13. sp<IBinder> service = sm_->checkService(serviceName);
14. if (service == nullptr) {
15. std::cerr << "Can't find service: " << serviceName << std::endl;
16. return NAME_NOT_FOUND;
17. }
18. err = service->dump(remote_end.get(), args); //这里调用的是java层服务对应的dump方法
19. }
20. });
21. }
22.
23. return 0;}
先通过defaultServiceManager()函数获得ServiceManager对象,然后根据dumpsys传进来的参数通过函数checkService来找到具体的service, 并执行该service的dump方法,然后执行该service的dump函数,达到dump service的目的。
以我们最熟悉的adb shell dumpsys activity 为例,这条命令将输入大量信息
这些信息在源码中的位置在哪里呢?
我们知道系统服务的调用经常通过ServiceManager.getService(xx)的形式获取,
系统核心服务在SystemServer 被启动和注册(注册通过ServiceManager.addService)
adb shell dumpsys activity 查找的就是被注册为activity的服务即ActivityManagerService即为要找到的服务。
SystemServer.java
// Set up the Application instance for the system process and get started.
t.traceBegin("SetSystemProcess");
mActivityManagerService.setSystemProcess();
t.traceEnd();
ActivityManagerService.java
public static final String ACTIVITY_SERVICE = "activity";
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this), /*
..........................
}
}
在代码中通过 快捷键 ctrl + f12搜索dump()方法,
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
核心信息打印的实现都在 mPriorityDumper 这个实例对象中。
/**
* Helper class which strips out priority and proto arguments then calls the dump function with
* the appropriate arguments. If priority arguments are omitted, function calls the legacy
* dump command.
* If priority arguments are omitted all sections are dumped, otherwise sections are dumped
* according to their priority.
*/
private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
@Override
public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args,
boolean asProto) {
if (asProto) return;
doDump(fd, pw, new String[]{"activities"}, asProto);
doDump(fd, pw, new String[]{"service", "all-platform-critical"}, asProto);
}
@Override
public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
doDump(fd, pw, new String[]{"-a", "--normal-priority"}, asProto);
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
doDump(fd, pw, args, asProto);
}
};
小结
通过熟悉dumpsys的流程,可以帮助我们更深入的理解和使用这些命令工具,提高开发效率。通过对dumpsys执行流程的分析,我们知道某些参数是如何打印出来的,不清楚什么意思也可以在对应的xxManagerService中找到对应的dump方法。然后后结合源码加深理解或者进行二次开发。