Android dumpsys介绍

这篇具有很好参考价值的文章主要介绍了Android dumpsys介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、需求

  1. 了解dumpsys原理,助于我们进一步了解Android系统的设计
  2. 帮助我们分析问题,定位系统状态
  3. 设计新功能的需要

二、环境

  1. 版本:Android 12
  2. 平台:SL8541E SPRD

三、相关概念

3.1 dumpsys

        dumpsys 是一种在 Android 设备上运行的工具,可提供有关系统服务的信息。可以使用 Android 调试桥 (adb) 从命令行调用 dumpsys,获取在连接的设备上运行的所有系统服务的诊断输出。

3.2 Binder

        Binder是Android提供的一套进程间相互通信框架。用来实现多进程间发送消息,同步和共享内存。
Android dumpsys介绍,Android,CSDN活动主题,1024程序员节

3.3 管道

        管道是一种IPC通信方式,分为有名管道和无名管道,无论是有名管道还是无名管道其原理都是在内核开辟一块缓存空间,这段缓存空间的操作是通过文件读写方式进行的。
有名管道与无名管道:
        有名管道: 有名管道的通信可以通过管道名进行通信,进程间不需要有关系。
        无名管道: 无名管道就是匿名管道,匿名管道通信的进程必须是父子进程。
管道为分半双工和全双工:
        半双工: 半双工管道是单向通信,进程1只能向管道写数据,进程2只能从管道读取数据。只有一个代表读或者写的FD(文件描述符)。
        全双工: 全双工管道是双向通信,有两个文件描述符,代表读和写。
Android dumpsys介绍,Android,CSDN活动主题,1024程序员节

四、dumpsys指令的使用

4.1 dumpsys使用

如下为执行"adb shell dumpsys"指令,控制台打印的内容,其使用如下:

dumpsys执行

4.2 dumpsys指令语法

(1)使用 dumpsys 的一般语法如下:

adb shell dumpsys [-t timeout] [--help | -l | --skip services | service [arguments] | -c | -h]

(2)如需获取所连接设备的所有系统服务的诊断输出,请运行 adb shell dumpsys。不过,这样输出的信息比您通常想要的信息多得多。若要使输出更加可控,您可以通过在命令中添加相应服务来指定要检查的服务。例如,下面的命令会提供输入组件(如触摸屏或内置键盘)的系统数据:

adb shell dumpsys input

(3)如需查看可与 dumpsys 配合使用的系统服务的完整列表,请使用以下命令:

adb shell dumpsys -l

(4)命令行选项如下:

选项 说明
-t timeout 指定超时期限(秒)。如果未指定,默认值为 10 秒。
–help 输出 dumpsys 工具的帮助文本。
-l 输出可与 dumpsys 配合使用的系统服务的完整列表。
–skip services 指定您不希望包含在输出中的 services。
service [arguments] 指定您希望输出的 service。某些服务可能允许您传递可选 arguments。如需了解这些可选参数,请将 -h 选项与服务一起传递:
adb shell dumpsys procstats -h
-c 指定某些服务时,附加此选项能以计算机可读的格式输出数据。
-h 对于某些服务,附加此选项可查看该服务的帮助文本和其他选项。

五、详细设计

5.1 dumpsys流程图

Android dumpsys介绍,Android,CSDN活动主题,1024程序员节

5.2 dumpsys查看电池信息

5.2.1 dumpsys battery指令

Android dumpsys介绍,Android,CSDN活动主题,1024程序员节

5.2.2 service->dump打印函数

@frameworks\base\services\core\java\com\android\server\BatteryService.java
private final class BinderService extends Binder {
    @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
            if (args.length > 0 && "--proto".equals(args[0])) {
                dumpProto(fd);
            } else {
                dumpInternal(fd, pw, args);
            }
        }
    ...
}

private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
    synchronized (mLock) {
        if (args == null || args.length == 0 || "-a".equals(args[0])) {
            pw.println("Current Battery Service state:");
            if (mUpdatesStopped) {
                pw.println("  (UPDATES STOPPED -- use 'reset' to restart)");
            }
            pw.println("  AC powered: " + mHealthInfo.chargerAcOnline);
            pw.println("  USB powered: " + mHealthInfo.chargerUsbOnline);
            pw.println("  Wireless powered: " + mHealthInfo.chargerWirelessOnline);
            pw.println("  Max charging current: " + mHealthInfo.maxChargingCurrent);
            pw.println("  Max charging voltage: " + mHealthInfo.maxChargingVoltage);
            pw.println("  Charge counter: " + mHealthInfo.batteryChargeCounter);
            pw.println("  status: " + mHealthInfo.batteryStatus);
            pw.println("  health: " + mHealthInfo.batteryHealth);
            pw.println("  present: " + mHealthInfo.batteryPresent);
            pw.println("  level: " + mHealthInfo.batteryLevel);
            pw.println("  scale: " + BATTERY_SCALE);
            pw.println("  voltage: " + mHealthInfo.batteryVoltage);
            pw.println("  temperature: " + mHealthInfo.batteryTemperature);
            pw.println("  technology: " + mHealthInfo.batteryTechnology);
        } else {
            Shell shell = new Shell();
            shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
        }
    }
}

5.3 dumpsys源码分析

5.3.1 dumpsys服务编译

        dumpsys是个二进制可执行程序,其通过bp进行编译,并最终打包到system分区(system/bin/dumpsys)。

@frameworks\native\cmds\dumpsys\android.bp
cc_binary {
    name: "dumpsys",

    defaults: ["dumpsys_defaults"],

    srcs: [
        "main.cpp",
    ],
}

5.3.2 dumpsys入口函数

        我们通过执行adb指令 “adb shell dumpsys”,可以启动dumpsys服务,其对应的入口函数如下:

@frameworks\native\cmds\dumpsys\main.cpp
int main(int argc, char* const argv[]) {
    signal(SIGPIPE, SIG_IGN);
    sp<IServiceManager> sm = defaultServiceManager();//获取SM对象
    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);//进入dumpsys服务
}

        这边比较关键的点是获取ServiceManager对象
        大家通过打印可以发现,dumpsys指令打印的数据是java进程的dump函数,而dumpsys也是独立的一个进程,那么dumpsys进程又是怎么和多个java进程通信的呢?没错,就是通过ServiceManager对象。
        那么,ServiceManager对象是什么呢?ServiceManager是Binder IPC通信的管家,本身也是一个Binder服务,他相当于 “DNS服务器”,内部存储了serviceName与其Binder Service的对应关系,管理Java层和native层的service,支持addService()、getService()、checkService、listServices()等功能。(Binder机制此处就不展开细说)

5.3.3 dumpsys服务打印

5.3.3.1 dumpsys解析参数

        当我们使用dumpsys指令,打印的数据太过冗长,一般会配合相关参数进行使用,例如:“dumpsys -l”、“dumpsys -t 100 battery”、“dumpsys --help”,第一步我们会先解析目标参数。

@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
    ...
    while (1) {
        ...
        c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex);//获取指令参数
        ...
        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")) {
                ...
            } else if (!strcmp(longOptions[optionIndex].name, "pid")) {//只显示服务的pid
                type = Type::PID;
            } else if (!strcmp(longOptions[optionIndex].name, "thread")) {//仅显示进程使用情况
                type = Type::THREAD;
            }
            break;
        case 't'://超时时间设置,默认10秒
            ...
            break;
        case 'T'://超时时间设置,默认10秒
            ...
            break;
        case 'l'://显示支持的服务列表
            showListOnly = true;
            break;
        default://其他参数
            fprintf(stderr, "\n");
            usage();
            return -1;
        }
    }
    ...
}
5.3.3.2 skippedServices列表构造

        dumpsys内部构造了skippedServices集合,用于记录需要忽略的服务。

@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
    ...
    for (int i = optind; i < argc; i++) {
    if (skipServices) {
        skippedServices.add(String16(argv[i]));//配置待忽略的服务
    } else {
        ...
    }
    ...
}
5.3.3.3 获取支持服务列表

        dumpsys通过ServiceManager获取支持的服务集合,并排序。

@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
    ...
    if (services.empty() || showListOnly) {
        services = listServices(priorityFlags, asProto);
        setServiceArgs(args, asProto, priorityFlags);
    }
    ...
}

Vector<String16> Dumpsys::listServices(int priorityFilterFlags, bool filterByProto) const {
    Vector<String16> services = sm_->listServices(priorityFilterFlags);//通过sm获取服务集合
    services.sort(sort_func);//集合排序
    ...
    return services;
}
5.3.3.4 打印支持服务列表

        在获取了服务集合后,会先检查服务是否存在,接着打印服务的名称,且如果当前指令设置了"-l"参数,仅打印服务集合,即流程结束。

@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
    ...
    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;
    }
    ...
}
5.3.3.5 打印目标服务

        先遍历所有需要打印的服务,如果参数有指定服务名,即N为对应服务的数量,否则N为所有支持的服务数量。接着,开启线程,通过servicemanager调用远端的dump函数,利用管道和poll机制监听远端数据。最后如果超时或者dump结束,则关闭线程,释放相关资源。

@frameworks\native\cmds\dumpsys\dumpsys.cpp
int Dumpsys::main(int argc, char* const argv[]) {
    ...
    for (size_t i = 0; i < N; i++) {
        const String16& serviceName = services[i];
        if (IsSkipped(skippedServices, serviceName)) continue;//跳过部分服务

        if (startDumpThread(type, serviceName, args) == OK) {//step 1.创建dump打印的线程
            ...
            std::chrono::duration<double> elapsedDuration;
            size_t bytesWritten = 0;
            status_t status =
                writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(timeoutArgMs),
                          asProto, elapsedDuration, bytesWritten);//step 2.dump执行打印操作

            if (status == TIMED_OUT) {//打印超时
                std::cout << std::endl
                     << "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs
                     << "ms) EXPIRED ***" << std::endl
                     << std::endl;
            }
            ...
            bool dumpComplete = (status == OK);
            stopDumpThread(dumpComplete);//step 3.结束dump打印线程
        }
    }
    ...
}

step 1. 创建dumpsys打印线程
        创建了一条管道,接着开启了一个线程,通过ServiceManager对象读取目标服务的dump函数,即dump打印数据。

@frameworks\native\cmds\dumpsys\dumpsys.cpp
status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
                                  const Vector<String16>& args) {
    sp<IBinder> service = sm_->checkService(serviceName);//通过SM获取service对象
    int sfd[2];
    if (pipe(sfd) != 0) {//创建管道,用于读取service端数据
        ...
    }
    ...
    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);//调用dump函数
            break;
        ...
        }
        ...
    });
    return OK;
}

step 2. dumpsys打印到终端
        通过poll机制用来监听管道的数据,并将读取到的dump数据,打印至控制台。同时,通过计算剩余的时间,来判断当前是否读取超时。

@frameworks\native\cmds\dumpsys\dumpsys.cpp
status_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout,
                            bool asProto, std::chrono::duration<double>& elapsedDuration,
                            size_t& bytesWritten) const {
    ...
    int serviceDumpFd = redirectFd_.get();
    struct pollfd pfd = {.fd = serviceDumpFd, .events = POLLIN};

    while (true) {
        ...
        int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));//poll机制检测管道数据
        if (rc < 0) {
           ...
        } else if (rc == 0 || time_left_ms() == 0) {
            status = TIMED_OUT;//计算剩余时间,来决定是否超时
            break;
        }

        char buf[4096];
        rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf)));//读取远端的数据
        ...
        if (!WriteFully(fd, buf, rc)) {//打印至控制台
            ...
            break;
        }
        totalBytes += rc;
    }
    ...
    return status;
}

step 3. 关闭dumpsys打印线程
        将dumpsys打印的线程detach掉,相关的fd句柄reset掉,释放资源。

六、dumpsys的应用

        如后续有什么应用dumpsys,或者有助于日常开发调试的场景,再补充,未完待续。

6.1 dumpsys常用指令

服务名 类名 指令 功能
activity ActivityManagerService 获取某个应用的Activity信息:
adb shell dumpsys activity a packagename
获取某个应用的Service信息:
adb shell dumpsys activity s packagename
获取某个应用的Broadcast信息:
adb shell dumpsys activity b packagename
获取某个应用的Provider信息:
adb shell dumpsys activity prov packagename
获取某个应用的进程状态:
adb shell dumpsys activity p packagename
获取当前界面的Activity信息:
adb shell dumpsys activity top | grep ACTIVITY
AMS相关信息
package PackageManagerService adb shell dumpsys package PMS相关信息
window WindowManagerService adb shell dumpsys window WMS相关信息
input InputManagerService adb shell dumpsys input IMS相关信息
power PowerManagerService adb shell dumpsys power PMS相关信息
batterystats BatterystatsService adb shell dumpsys batterystats 电池统计信息
battery BatteryService adb shell dumpsys battery 电池信息
alarm AlarmManagerService adb shell dumpsys alarm 闹钟信息
dropbox DropboxManagerService adb shell dumpsys dropbox 调试相关
procstats ProcessStatsService adb shell dumpsys procstats 进程统计
cpuinfo CpuBinder adb shell dumpsys cpuinfo CPU
meminfo MemBinder adb shell dumpsys meminfo 内存
gfxinfo GraphicsBinder adb shell dumpsys gfxinfo 图像
dbinfo DbBinder adb shell dumpsys dbinfo 数据库

七、参考资料

dumpsys指令介绍:
https://developer.android.google.cn/studio/command-line/dumpsys?hl=zh-cn
管道:
https://www.cnblogs.com/naray/p/15365954.html
Binder:
https://blog.csdn.net/shenxiaolinil/article/details/128972302文章来源地址https://www.toymoban.com/news/detail-712946.html

到了这里,关于Android dumpsys介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 好用且免费的CodeWhisperer,给1024程序员节送礼来了

          国庆期间没有胆量去人从众的景点,关在家里刷手机时意外在亚马逊的User Group公众号上发现了CodeWhisperer这么个好东西(bu yao qian),以后撸代码也可以提高生产力(fang yang mo yu)了,这还不赶紧上手试一下。看官方介绍说它支持流行的IDE开发工具,包括VS Code、Intelli

    2024年02月08日
    浏览(54)
  • 1024程序员节带你玩转图片Exif信息获取之JavaScript

    目录 一、前言 二、背景 三、Exif.js          1、Exif.js 简介 2、Exif.js 引入 四、多场景展示数据获取 1、原始图片直接获取  2、base64 编码文件加载  3、文件上传的方式加载  五、总结        1024是2的十次方,二进制计数的基本计量单位之一。1G=1024M,而1G与1级谐音,也有一

    2024年02月20日
    浏览(60)
  • 1024程序员节特辑 | Spring Boot实战 之 MongoDB分片或复制集操作

    Spring实战系列文章: Spring实战 | Spring AOP核心秘笈之葵花宝典 Spring实战 | Spring IOC不能说的秘密? 国庆中秋特辑系列文章: 国庆中秋特辑(八)Spring Boot项目如何使用JPA 国庆中秋特辑(七)Java软件工程师常见20道编程面试题 国庆中秋特辑(六)大学生常见30道宝藏编程面试题

    2024年02月08日
    浏览(82)
  • 1024程序员狂欢节 | IT前沿技术、人工智能、数据挖掘、网络空间安全技术

    一年一度的1024程序员狂欢节又到啦!成为更卓越的自己,坚持阅读和学习,别给自己留遗憾,行动起来吧! 那么,都有哪些好书值得入手呢?小编为大家整理了前沿技术、人工智能、集成电路科学与芯片技术、新一代信息与通信技术、网络空间安全技术,四大热点领域近期

    2024年02月06日
    浏览(67)
  • 1024程序员节特辑 | ELK+ 用户画像构建个性化推荐引擎,智能实现“千人千面”

    专栏集锦,大佬们可以收藏以备不时之需 Spring Cloud实战专栏:https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏:https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏:https://blog.csdn.net/superdangbo/category_9271502.html tensorflow专栏:https://blog.csdn.net/superdangbo/category_869

    2024年02月07日
    浏览(84)
  • 1024程序员节特辑 | 解密Spring Cloud Hystrix熔断提高系统的可用性和容错能力

    专栏集锦,大佬们可以收藏以备不时之需 Spring Cloud实战专栏:https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏:https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏:https://blog.csdn.net/superdangbo/category_9271502.html tensorflow专栏:https://blog.csdn.net/superdangbo/category_869

    2024年02月08日
    浏览(55)
  • 1024程序员节?我们整点AI绘图玩玩吧,一文教你配置stable-diffusion

    需提前准备:一台高性能的电脑(尤其是显存)、python、Git、梯子。 其实Github上有很多关于Stable diffusion的库,综合对比之后,我选取的是比较全面的AUTOMATIC1111这个,源码链接:Stable-diffusion(Github) 找到安装那块的教程,此教程以windows为例。 ps:如果你电脑上已经有了pyt

    2024年01月16日
    浏览(74)
  • PHP框架开发实践 | 1024 程序员节:通过index.php找到对应的controller是如何实现的

    🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于PHP专栏:PHP进阶实战教程。 🎉欢迎 👍点赞✍评论⭐收藏

    2024年02月08日
    浏览(72)
  • 1024程序员狂欢节有好礼 | 前沿技术、人工智能、集成电路科学与芯片技术、新一代信息与通信技术、网络空间安全技术

    🌹欢迎来到 爱书不爱输的程序猿 的博客, 本博客致力于知识分享,与更多的人进行学习交流 🚩🚩🚩 点击直达福利 一年一度的1024程序员狂欢节又到啦!成为更卓越的自己,坚持阅读和学习,别给自己留遗憾,行动起来吧! 那么,都有哪些好书值得入手呢?小编为大家整理

    2024年02月08日
    浏览(79)
  • 1024程序节|Android框架之一 BRVAH【BaseRecyclerViewAdapterHelper】使用demo

    BRVAH是一个强大的RecyclerAdapter框架(什么是RecyclerView?),它能节约开发者大量的开发时间,集成了大部分列表常用需求解决方案。为什么会有它?请查看「Android开源框架BRVAH由来篇」该框架于2016年4月10号发布的第1个版本到现在已经一年多了,经历了800多次代码提交,140多次版

    2024年02月01日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包