我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android dumpsys介绍

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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提供的一套进程间相互通信框架。用来实现多进程间发送消息,同步和共享内存。
请添加图片描述

3.3 管道

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

四、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流程图

请添加图片描述

5.2 dumpsys查看电池信息

5.2.1 dumpsys battery指令

请添加图片描述

5.2.2 service->dump打印函数

@frameworks\base\services\core\java\com\android\server\BatteryService.javaprivate 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.bpcc_binary {    name: "dumpsys",    defaults: ["dumpsys_defaults"],    class="lazy" data-srcs: [        "main.cpp",    ],}

5.3.2 dumpsys入口函数

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

@frameworks\native\cmds\dumpsys\main.cppint 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.cppint 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.cppint 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.cppint Dumpsys::main(int argc, char* const argv[]) {    ...    if (services.empty() || showListOnly) {        services = listServices(priorityFlags, asProto);        setServiceArgs(args, asProto, priorityFlags);    }    ...}Vector Dumpsys::listServices(int priorityFilterFlags, bool filterByProto) const {    Vector services = sm_->listServices(priorityFilterFlags);//通过sm获取服务集合    services.sort(sort_func);//集合排序    ...    return services;}
5.3.3.4 打印支持服务列表

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

@frameworks\native\cmds\dumpsys\dumpsys.cppint 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 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.cppint 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 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.cppstatus_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.cppstatus_t Dumpsys::writeDump(int fd, const String16& serviceName, std::chrono::milliseconds timeout,bool asProto, std::chrono::duration& 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常用指令

服务名类名指令功能
activityActivityManagerService获取某个应用的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相关信息
packagePackageManagerServiceadb shell dumpsys packagePMS相关信息
windowWindowManagerServiceadb shell dumpsys windowWMS相关信息
inputInputManagerServiceadb shell dumpsys inputIMS相关信息
powerPowerManagerServiceadb shell dumpsys powerPMS相关信息
batterystatsBatterystatsServiceadb shell dumpsys batterystats电池统计信息
batteryBatteryServiceadb shell dumpsys battery电池信息
alarmAlarmManagerServiceadb shell dumpsys alarm闹钟信息
dropboxDropboxManagerServiceadb shell dumpsys dropbox调试相关
procstatsProcessStatsServiceadb shell dumpsys procstats进程统计
cpuinfoCpuBinderadb shell dumpsys cpuinfoCPU
meminfoMemBinderadb shell dumpsys meminfo内存
gfxinfoGraphicsBinderadb shell dumpsys gfxinfo图像
dbinfoDbBinderadb 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://blog.csdn.net/u013320490/article/details/134008928

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android dumpsys介绍

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android中dumpsys命令用法简单介绍

在Android手机上, 通过使用adb shell命令可以进入android系统的shell, 该shell除支持一些常用的标准命令之外,还支持一些和android系统相关的其他命令, 这些命令可以打印出系统当前的状态信息。 dumpsy
2022-06-06

Android中的dumpsys命令怎么用

这篇文章主要介绍“Android中的dumpsys命令怎么用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Android中的dumpsys命令怎么用”文章能帮助大家解决问题。一、dumpsys命令介
2023-06-30

android AsyncTask详细介绍

AsyncTask和Handler对比 1 ) AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可
2022-06-06

android CursorLoader用法介绍

工作内容集中到Contact模块,这个应用查询数据的地方很多,其使用了CursorLoader这个工具大大简化了代码复杂度。android自3.0提供了Loader机制,当时google的API只是简单的介绍了一下没有给出用法,大家很少有关
2022-06-06

Android Bitmap详细介绍

代码如下: package com.testbitmapscale; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream;
2022-06-06

Android录屏 MediaRecorder介绍

Android录屏 MediaRecorder介绍 Android录屏的三种方案 1、adb shell命令screenrecord 2、MediaRecorder, MediaProjection 3、MediaCodec和MediaMu
2022-06-06

android之ContentResolver与ContentProvider介绍

android中对数据操作包含有: file, sqlite3, Preferences, ContectResolver与ContentProvider前三种数据操作方式都只是针对本应用内数据,程序不能通过这三种方法去操作别的应用内的数
2022-06-06

Android Handler的详细介绍

Handler的定义  主要接受子线程发送的数据, 并用此数据配合主线程更新UI.  解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发。比如说, 你要是点击一个
2022-06-06

Android Thread 介绍与实例

Android中很重要的一个机制就是线程+消息,当然线程并不是android独有的,下面,简单的说说使用线程的时候应该注意的地方 我们采用最简单的方法来建立一个android的线程+消息的例子 1.Thread + Handler [jav
2022-06-06

Android View Binding使用介绍

前言 Android Studio稳定版发布了3.6版本,带来了一些新变化:首先外观,启动页变了,logo改了,更显现代化;增加Multi Preview功能,能同时预览多个尺寸屏幕的显示效果;模拟器支持多屏;也终于支持全新的视图绑定组件V
2022-06-06

android WebView加载html5介绍

Android设备多分辨率的问题 Android浏览器默认预览模式浏览 会缩小页面 WebView中则会以原始大小显示 Android浏览器和WebView默认为mdpi。hdpi相当于mdpi的1.5倍 ldpi相当于0.75倍 三种解决
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录