源码基于:Android R
首先来看一下dumpsys的source code:
path:frameworks/native/cmds/dumpsys/
1. Android.bp
package {
default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
}
// Added automatically by a large-scale-change
// See: http://go/android-license-faq
license {
name: "frameworks_native_cmds_dumpsys_license",
visibility: [":__subpackages__"],
license_kinds: [
"SPDX-license-identifier-Apache-2.0",
],
license_text: [
"NOTICE",
],
}
cc_defaults {
name: "dumpsys_defaults",
cflags: [
"-Wall",
"-Werror",
],
srcs: [
"dumpsys.cpp",
],
shared_libs: [
"libbase",
"libutils",
"liblog",
"libbinder",
"libbinderdebug",
],
static_libs: [
"libserviceutils",
],
}
cc_library_static {
name: "libdumpsys",
defaults: ["dumpsys_defaults"],
export_include_dirs: ["."],
}
cc_binary {
name: "dumpsys",
defaults: ["dumpsys_defaults"],
srcs: [
"main.cpp",
],
}
cc_binary {
name: "dumpsys_vendor",
stem: "dumpsys",
vendor: true,
defaults: ["dumpsys_defaults"],
srcs: [
"main.cpp",
],
}
从Android.bp 知道:
- 系统会通过 dumpsys.cpp 编译一个静态库 libdumpsys.so;
- 系统会通过main.cpp 和 dumpsys.cpp 编译出 dumpsys 文件,在system/bin/和/vendor/bin 下都有;
2. main.cpp
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
sp<IServiceManager> sm = defaultServiceManager();
fflush(stdout);
if (sm == nullptr) {
ALOGE("Unable to get default service manager!");
std::cerr << "dumpsys: Unable to get default service manager!" << std::endl;
return 20;
}
Dumpsys dumpsys(sm.get());
return dumpsys.main(argc, argv);
}
没什么东西,获取 IServiceManager 对象,带入Dumpsys 构造出一个对象并启动main();
3. Dumpsys::main()
int Dumpsys::main(int argc, char* const argv[]) {
...
int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
static struct option longOptions[] = {{"pid", no_argument, 0, 0},
{"priority", required_argument, 0, 0},
{"proto", no_argument, 0, 0},
{"skip", no_argument, 0, 0},
{"help", no_argument, 0, 0},
{0, 0, 0, 0}};
optind = 1;
while (1) { //------ step1
int c;
int optionIndex = 0;
c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex);
if (c == -1) {
break;
}
switch (c) {
case 0: //-------- step2
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, "pid")) {
type = Type::PID;
}
break;
case 't': //-------- step3
{
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': //-------- step3
{
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': //-------- step4
showListOnly = true;
break;
default:
fprintf(stderr, "\n");
usage();
return -1;
}
}
for (int i = optind; i < argc; i++) { //-------- step5
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()) || //-------- step6
(showListOnly && (!services.empty() || !skippedServices.empty()))) {
usage();
return -1;
}
if (services.empty() || showListOnly) { //-------- step7
services = listServices(priorityFlags, asProto);
setServiceArgs(args, asProto, priorityFlags);
}
const size_t N = services.size();
if (N > 1) { //-------- step8
// 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) { //-------- step9
return 0;
}
for (size_t i = 0; i < N; i++) { //-------- step10
const String16& serviceName = services[i];
if (IsSkipped(skippedServices, serviceName)) continue;
if (startDumpThread(type, 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;
}
代码比较多,将其划分为10 个部分,分别从step1 ~ step10
step1. 启动while 循环,解析dumpsys 的命令的参数;
主要是启动一个死循环,通过 getopt_long() 解析命令行参数;
step2. 确认特殊命令
确认dumpsys 命令是否含有 --skip、--proto、--priority、--help、--skip
来看下dumpsys 的命令行参数选项:
static void usage() {
fprintf(stderr,
"usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
" dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--help | -l | --skip SERVICES "
"| SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
" -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
" -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
" --pid: dump PID instead of usual dump\n"
" --proto: filter services that support dumping data in proto format. Dumps\n"
" will be in proto format.\n"
" --priority LEVEL: filter services based on specified priority\n"
" LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
" --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
" SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
- --help:显示usage;
- --skip SERVICES:dumpsys 的时候过滤掉这些services;
- --priority LEVEL:传入给对应service(例如meminfo) 的参数,以--dump-priority 选项传入;
- --pid:以PID 的形式代替传统的 dump() 函数,下面 step10 会说明;
- --proto:类似与--prriority,这里会将 --proto 选项作为参数带入对应的service;
- -t:设置timeout,秒为单位;
- -T:设置timeout,毫秒为单位;
- -l:列出所有的services,但不取dump;
- SERVICE [ARGS]:可以直接指定service,只dump 指定的service
step3. 设定timeout
case 't': //-------- step3
{
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': //-------- step3
{
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;
通过-t 或 -T 传入 poll 所需要的timeout;
-t 设定的是以秒为单位,-T 设定的是以毫秒为单位;
默认值为10秒,如果 10 秒的时间还不足够 poll 响应,那么可以通过这两个参数适当的加大timeout 时长。
step4. 通过-l 列举所有可以dump 的services
case 'l': //-------- step4
showListOnly = true;
break;
如果有-l 这个参数,代码会将 showListOnly 置为true,用以确定是否进行打印;
step5. 确定需要skip 的services 和args
如果设定了 --skip,变量 skipServices 会被置为true;
如果没有设定 --skip,那就确认指定的service 和 其args;
step6. 确认命令是否出错
如果出现错误会打印 usage 作为提醒;
step7. 统计所有的services
if (services.empty() || showListOnly) { //-------- step7
services = listServices(priorityFlags, asProto);
setServiceArgs(args, asProto, priorityFlags);
}
当通过step5 确认之后,发现没有指定service,或者dumpsys 携带了 -l 的选项,会统计所有的servcies,并且指定args;
其中需要注意的是listServices() 的参数priorityFlags,这里列举的是符合该flags 的services,默认值为IServiceManager::DUMP_FLAG_PRIORITY_ALL,也就是说,如果某service(例如,meminfo) 需要通过dumpsys 命令进行dump 操作,必要将指定dump flag。
step8. 打印services
const size_t N = services.size();
if (N > 1) { //-------- step8
// 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;
}
}
}
如果不是指定的services,或者dumpsys 携带了-l,那么就会列举出来;
注意的是,如果某个service 在skip 中,则在列举的时候在最后加上 (skipped):
127|shift:/ # dumpsys --skip window SurfaceFlinger activity gfxinfo input package activity
Currently running services:
DockObserver
SurfaceFlinger (skipped)
accessibility
account
activity (skipped)
activity_task
step9. -l 的参数不进行dump
if (showListOnly) {
return 0;
}
如果携带了 -l 的参数,不会进入 dump 操作;
step10. dumpsys 的核心dump操作
for (size_t i = 0; i < N; i++) {
const String16& serviceName = services[i];
if (IsSkipped(skippedServices, serviceName)) continue;
if (startDumpThread(type, 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);
}
}
经过上面 step5 ~ step7 之后skip services 和目标service 已经统计完毕,如果没有指定service,那就是dumpsys 所有的符合dump flag 的service(不包括 --skip的),那么这里的 N 应该很大,通过for 循环进行dump;如果指定了service,例如dumpsys meminfo(详细的meminfo 可以查看:dumpsys meminfo 详解 ),那么这里的 N 应该是为 1.
meminfo 有三种命令模式:
- dumpsys meminfo (后面有可能加--skip)
- dumpsys meminfo com.android.launcher3
- dumpsys meminfo --pid 1925
第一种是查看系统所有的进程的内存使用情况;第二种是单独查看应用Luancher3 的内存使用情况;第三种是指定了Launcher3 的pid 通过pid 查询Launcher3 的内存使用情况;
IsSkipped() 用来确定当前的serviceName 是否在需要skip 的list 中,如果在就跳过,不去dump 操作;
startDumpThread() 会创建一个阻塞线程,等待dump 处理完成;
addSeparator 用来确认是否有多个service dump,如果有,在servcie 之间加上说明dump 到哪里了;
进入writeDump(),创建死循环,通过poll 机制等待service 端数据写入,如果有数据到来会输出到终端 STDOUT_FILENO;
下面一节来看下startDumpThread 做了什么操作。
4. startDumpThread()
status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
if (service == nullptr) {
std::cerr << "Can't find service: " << serviceName << std::endl;
return NAME_NOT_FOUND;
}
int sfd[2];
if (pipe(sfd) != 0) {
std::cerr << "Failed to create pipe to dump service info for " << serviceName << ": "
<< strerror(errno) << std::endl;
return -errno;
}
redirectFd_ = unique_fd(sfd[0]);
unique_fd remote_end(sfd[1]);
sfd[0] = sfd[1] = -1;
// dump blocks until completion, so spawn a thread..
activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
status_t err = 0;
switch (type) {
case Type::DUMP:
err = service->dump(remote_end.get(), args);
break;
case Type::PID:
err = dumpPidToFd(service, remote_end);
break;
default:
std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl;
return;
}
if (err != OK) {
std::cerr << "Error dumping service info status_t: " << statusToString(err) << " "
<< serviceName << std::endl;
}
});
return OK;
}
- 首先通过checkservice() 来确认serviceName 的正确性;
- 创建一个pipe 管道;
- 通过std::thread() 创建一个thread(C++11 特性),用以触发service dump;
dumpsys 创建了一个pipe,把pipe[1] 通过dump 方式传递到services端,然后在函数 writeDump() 中通过 poll 机制开始监听pipe[0],当产生通讯之后或者 timeout 之后会结束此次service dump。
由于时间原因, 其他的过程暂时不进行剖析了,总结下dumpsys 的流程大致如下:
5. 系统中所有的services
130|frost:/ # dumpsys -l
Currently running services:
DockObserver
SurfaceFlinger
accessibility
account
activity
activity_task
adb
alarm
android.frameworks.stats.IStats/default
android.hardware.light.ILights/default
android.hardware.power.IPower/default
android.hardware.vibrator.IVibrator/default
android.os.UpdateEngineService
android.os.UpdateEngineStableService
android.security.apc
android.security.authorization
android.security.compat
android.security.identity
android.security.legacykeystore
android.security.maintenance
android.security.metrics
android.service.gatekeeper.IGateKeeperService
android.system.keystore2.IKeystoreService/default
app_binding
app_hibernation
app_integrity
app_search
appops
appwidget
audio
auth
autofill
backup
battery
batteryproperties
batterystats
binder_calls_stats
biometric
blob_store
bluetooth_manager
bugreport
cacheinfo
carrier_config
clipboard
color_display
companiondevice
connectivity
connmetrics
consumer_ir
content
country_detector
cpuinfo
crossprofileapps
dataloader_manager
dbinfo
device_config
device_identifiers
device_policy
device_state
deviceidle
devicestoragemonitor
diskstats
display
dnsresolver
domain_verification
dpmservice
dreams
drm.drmManager
dropbox
dynamic_system
emergency_affordance
external_vibrator_service
extphone
file_integrity
fingerprint
font
game
gfxinfo
gpu
graphicsstats
hardware_properties
imms
incident
incidentcompanion
incremental
input
input_method
inputflinger
installd
ions
iphonesubinfo
ipsec
isms
isub
jobscheduler
launcherapps
legacy_permission
lights
location
location_time_zone_manager
lock_settings
looper_stats
manager
media.audio_flinger
media.audio_policy
media.camera
media.camera.proxy
media.extractor
media.metrics
media.player
media.resource_manager
media.resource_observer
media.wfd
media_communication
media_metrics
media_projection
media_resource_monitor
media_router
media_session
meminfo
memtrack.proxy
midi
mount
netd
netd_listener
netpolicy
netstats
network_management
network_score
network_stack
network_time_update_service
network_watchlist
notification
oem_lock
otadexopt
overlay
pac_proxy
package
package_native
people
performance_hint
perfservice
permission
permission_checker
permissionmgr
persistent_data_block
phone
pinner
platform_compat
platform_compat_native
power
powerstats
print
processinfo
procstats
qti.radio.extphone
reboot_readiness
recovery
restrictions
role
rollback
runtime
scheduling_policy
search
search_ui
sec_key_att_app_id_provider
secure_element
sensor_privacy
sensorservice
serial
servicediscovery
settings
shortcut
simphonebook
sip
slice
smartspace
soundtrigger
soundtrigger_middleware
speech_recognition
stats
statscompanion
statsmanager
statusbar
storaged
storaged_pri
storagestats
suspend_control
suspend_control_internal
system_config
system_server_dumper
system_update
telecom
telephony.registry
telephony_ims
testharness
tethering
textclassification
textservices
texttospeech
thermalservice
time_detector
time_zone_detector
tracing.proxy
trust
uce
uimode
updatelock
uri_grants
usagestats
usb
user
vcn_management
vendor.logagent
vendor.logserver
vendor.sysagent
vibrator_manager
voiceinteraction
vold
vpn_management
wallpaper
webviewupdate
wifi
wifiaware
wifinl80211
wifip2p
wifirtt
wifiscanner
window
下面来详细说明一下这个service。
1. meminfo
这个是比较常用的service,可以看一下:android 查看内存使用情况
2. cpuinfo
可以看一下:dumpsys cpuinfo
3. window
4. surfaceflinger