赞
踩
dumpsys是一个在安卓设备上运行的工具,提供关于系统服务的信息。使用安卓调试桥(ADB)从命令行调用dumpsys,以获得连接设备上运行的所有系统服务的诊断输出。
这个输出通常比你想要的更粗略,所以使用本页的命令行选项,只获得你想要的系统服务的输出。本页还描述了如何使用dumpsys来完成常见的任务,例如检查输入、RAM、电池或网络诊断。
dumpsys的一般语法如下:
[adb shell] dumpsys [-t timeout] [--help | -l | --skip services | service [arguments] | -c | -h]
要获得你所连接设备的所有系统服务的诊断输出,可以运行adb shell dumpsys。然而,这输出的信息远比你通常想要的多。为了获得更易于管理的输出,在命令中指定你要检查的服务。例如,下面的命令提供了输入组件的系统数据,如触摸屏或内置键盘:
[adb shell] dumpsys input
关于你可以用dumpsys使用的系统服务的完整列表,请使用以下命令。
[adb shell] dumpsys -l
下表列出了使用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 package [-h][-f][--checkin][cmd]…
其中子命令:
命令格式:
dumpsys activity [-h][-a][-c][-p]…
子命令:
Activity使用例子
安卓系统网络连接和管理服务由四个系统服务ConnectivityService,NetworkPolicyManagerService,NetworkManagementService,NetworkStatsService共同配合完成网络连接和管理功能。因此,要查看设备网络相关信息,就需要使用dumpsys命令分别查看设备中这些服务的详细信息:
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所示服务“句柄”管理机制:
int Dumpsys::main(int argc, char* const argv[]) { Vector<String16> services; Vector<String16> args; String16 priorityType; Vector<String16> skippedServices; Vector<String16> protoServices; bool showListOnly = false; bool skipServices = false; bool asProto = false; int dumpTypeFlags = 0; int timeoutArgMs = 10000; int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL; static struct option longOptions[] = { {"help", no_argument, 0, 0}, {"clients", no_argument, 0, 0}, {"dump", no_argument, 0, 0}, {"pid", no_argument, 0, 0}, {"priority", required_argument, 0, 0}, {"proto", no_argument, 0, 0}, {"skip", no_argument, 0, 0}, {"stability", no_argument, 0, 0}, {"thread", no_argument, 0, 0}, {0, 0, 0, 0}}; // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but // happens on test cases). optind = 1; while (1) { int c; int optionIndex = 0; c = getopt_long(argc, argv, "+t: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, "proto")) { asProto = true; } else if (!strcmp(longOptions[optionIndex].name, "help")) { usage(); return 0; } else if (!strcmp(longOptions[optionIndex].name, "priority")) { priorityType = String16(String8(optarg)); if (!ConvertPriorityTypeToBitmask(priorityType, priorityFlags)) { fprintf(stderr, "\n"); usage(); return -1; } } else if (!strcmp(longOptions[optionIndex].name, "dump")) { dumpTypeFlags |= TYPE_DUMP; } else if (!strcmp(longOptions[optionIndex].name, "pid")) { dumpTypeFlags |= TYPE_PID; } else if (!strcmp(longOptions[optionIndex].name, "stability")) { dumpTypeFlags |= TYPE_STABILITY; } else if (!strcmp(longOptions[optionIndex].name, "thread")) { dumpTypeFlags |= TYPE_THREAD; } else if (!strcmp(longOptions[optionIndex].name, "clients")) { dumpTypeFlags |= TYPE_CLIENTS; } break; case 't': { char* endptr; timeoutArgMs = strtol(optarg, &endptr, 10); timeoutArgMs = timeoutArgMs * 1000; if (*endptr != '\0' || timeoutArgMs <= 0) { fprintf(stderr, "Error: invalid timeout(seconds) number: '%s'\n", optarg); return -1; } } break; case 'T': { char* endptr; timeoutArgMs = strtol(optarg, &endptr, 10); if (*endptr != '\0' || timeoutArgMs <= 0) { fprintf(stderr, "Error: invalid timeout(milliseconds) number: '%s'\n", optarg); return -1; } } break; case 'l': showListOnly = true; break; default: fprintf(stderr, "\n"); usage(); return -1; } } if (dumpTypeFlags == 0) { dumpTypeFlags = TYPE_DUMP; } for (int i = optind; i < argc; i++) { if (skipServices) { skippedServices.add(String16(argv[i])); } else { if (i == optind) { services.add(String16(argv[i])); } else { const String16 arg(argv[i]); args.add(arg); // For backward compatible, if the proto argument is passed to the service, the // dump request is also considered to use proto. if (!asProto && !arg.compare(String16(PriorityDumper::PROTO_ARG))) { asProto = true; } } } } if ((skipServices && skippedServices.empty()) || (showListOnly && (!services.empty() || !skippedServices.empty()))) { usage(); return -1; } if (services.empty() || showListOnly) { services = listServices(priorityFlags, asProto); setServiceArgs(args, asProto, priorityFlags); } const size_t N = services.size(); if (N > 1 || showListOnly) { // first print a list of the current services std::cout << "Currently running services:" << std::endl; for (size_t i=0; i<N; i++) { sp<IBinder> service = sm_->checkService(services[i]); if (service != nullptr) { bool skipped = IsSkipped(skippedServices, services[i]); std::cout << " " << services[i] << (skipped ? " (skipped)" : "") << std::endl; } } } if (showListOnly) { return 0; } for (size_t i = 0; i < N; i++) { const String16& serviceName = services[i]; if (IsSkipped(skippedServices, serviceName)) continue; if (startDumpThread(dumpTypeFlags, serviceName, args) == OK) { bool addSeparator = (N > 1); if (addSeparator) { writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags); } std::chrono::duration<double> elapsedDuration; size_t bytesWritten = 0; status_t status = writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(timeoutArgMs), asProto, elapsedDuration, bytesWritten); if (status == TIMED_OUT) { std::cout << std::endl << "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs << "ms) EXPIRED ***" << std::endl << std::endl; } if (addSeparator) { writeDumpFooter(STDOUT_FILENO, serviceName, elapsedDuration); } bool dumpComplete = (status == OK); stopDumpThread(dumpComplete); } } return 0; }
从上面源码中可知
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; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。