android framework系统源码分析之dumpsys原理分析-千里马带你学framework
Posted learnframework
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android framework系统源码分析之dumpsys原理分析-千里马带你学framework相关的知识,希望对你有一定的参考价值。
背景:
hi,粉丝朋友们大家好!
我们学习android framework实战开发过程中经常会用到一些辅助的shell命令,比如最经典就是我们常见的dumpsys啦,还记我给大家讲解的入门课,实战课,跨进程专题课其实都用用到这个命令;当时我只是给大家讲解怎么使用这种dumpsys一些命令,并没有给大家讲解它的一个原理,但是对于对android系统充满好奇小伙伴们,肯定不满足与简单使用,还是想搞明白他到到底什么原理,那么搞懂它到底有什么好处么?那当然是好处多多,我这里给大家主要罗列一下几点:
1、分析出dumpsys实现原理,可以知道他是怎么实现的整套系统各个调试运作,方便我们以后自己取实现新调试系统的参考
2、可以分析dumpsys架构源码,推断出要dump某个类信息时候是使用哪个命令,而不是现在的完全靠经验记住几个常用dumpsys命令
3、在自己开发模块过程中也可以自己借助dump来多打印一些自己的调试信息
。。。。
好了大概有以上几点的好处,其他不一一列举,我相信以上3点就对大家非常非常有用了,毕竟你已经和不懂dumpsys的小伙伴已经差距拉开了,好了下面开始我们的分析dumpsys之旅。
1 首先来看看dumpsys这里命令源码在哪里?
路径:frameworks/native/cmds/dumpsys/
里面有如下几个文件:
这里其实核心就是dumpsys.cpp
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include <chrono>
#include <iomanip>
#include <thread>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/TextOutput.h>
#include <serviceutils/PriorityDumper.h>
#include <utils/Log.h>
#include <utils/Vector.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "dumpsys.h"
using namespace android;
using ::android::base::StringAppendF;
using ::android::base::StringPrintf;
using ::android::base::unique_fd;
using ::android::base::WriteFully;
using ::android::base::WriteStringToFd;
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 timeoutArgMs = 10000;
int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
static struct option longOptions[] = "priority", required_argument, 0, 0,
"proto", no_argument, 0, 0,
"skip", no_argument, 0, 0,
"help", 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)
//省略大部分
for (size_t i = 0; i < N; i++)
const String16& serviceName = services[i];
if (IsSkipped(skippedServices, serviceName)) continue;
if (startDumpThread(serviceName, args) == OK)
//省略部分
return 0;
可以看到dumpsys会根据传递来的参数调用startDumpThread(serviceName, args)方法,这里serviceName就是我们跨进程中有讲到的ServiceManager中的serviceName,这里核心其实也就是
startDumpThread方法:
status_t Dumpsys::startDumpThread(const String16& serviceName, const Vector<String16>& args)
sp<IBinder> service = sm_->checkService(serviceName);//检测是否有这个serviceName,取到对应IBinder对象
if (service == nullptr)
aerr << "Can't find service: " << serviceName << endl;
return NAME_NOT_FOUND;
int sfd[2];
if (pipe(sfd) != 0)
aerr << "Failed to create pipe to dump service info for " << serviceName << ": "
<< strerror(errno) << 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_endstd::move(remote_end)]() mutable
int err = service->dump(remote_end.get(), args);//调用对应service的dump方法
// It'd be nice to be able to close the remote end of the socketpair before the dump
// call returns, to terminate our reads if the other end closes their copy of the
// file descriptor, but then hangs for some reason. There doesn't seem to be a good
// way to do this, though.
remote_end.reset();
if (err != 0)
aerr << "Error dumping service info: (" << strerror(err) << ") "
<< serviceName << endl;
);
return OK;
这里其实就干了2件事:
1、ServiceManager获取到对应的IBinder代理,这里其实跨进程里面也有讲解大家都知道
2、然后调用IBinder对应的dump方法,这里dump方法就会调用到我们对应service的dump,比如dumpsys activity就会调用到ActivityManagerSerivice的dump方法,但是为什么呢?凭啥调用一下IBinder native层面的dump就会调用到Java层面的dump,如果是C++层面的我们都还可以理解,这直接就到Java层面那就有点难理解了,那么我们就来看看
dumpsys发起binder调用时候,它实际是BpBinder的角色,即客户端,它调用dump,看看BpBinder的dump实现:
// 路径:frameworks/native/libs/binder/BpBinder.cpp
status_t BpBinder::dump(int fd, const Vector<String16>& args)
Parcel send;
Parcel reply;
send.writeFileDescriptor(fd);
const size_t numArgs = args.size();
send.writeInt32(numArgs);
for (size_t i = 0; i < numArgs; i++)
send.writeString16(args[i]);
status_t err = transact(DUMP_TRANSACTION, send, &reply);
return err;
这里可以看到其实他是transact了code为DUMP_TRANSACTION的数据,到此dumpsys作为客户端就已经非常清楚了,本质就是通过binder给服务段发送了一个code为DUMP_TRANSACTION的数据。
接下来看服务端接受部分:
在跨进程通讯就讲解过,Java中的Binder对象实现其实在底层也有一个类似的BBinder对象,他就是我们的JavaBBinder类:
//路径:frameworks/base/core/jni/android_util_Binder.cpp
class JavaBBinder : public BBinder
public:
//省略部分
status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
//省略部分
//这里是重点,这里就是会调用到Java层面了
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
//省略部分
status_t dump(int fd, const Vector<String16>& args) override
return 0;
private:
JavaVM* const mVM;
jobject const mObject; // GlobalRef to Java Binder
mutable std::once_flag mPopulateDescriptor;
mutable String16 mDescriptor;
;
所以这里其实binder驱动传递数据后后就是会到这个native的JavaBBinder类里面的onTransact方法,这个方法就完全没有什么自己业务,就是立即jni调用到了Java层面的onTransact:
frameworks/base/core/java/android/os/Binder.java
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
int flags) throws RemoteException
if (code == INTERFACE_TRANSACTION)
//省略部分
else if (code == DUMP_TRANSACTION) //这里就是核心,会有一个dump的code传递过来
ParcelFileDescriptor fd = data.readFileDescriptor();
String[] args = data.readStringArray();
if (fd != null)
try
dump(fd.getFileDescriptor(), args);//正式调用到了对应Binder服务段Serivce的dump方法
finally
IoUtils.closeQuietly(fd);
// Write the StrictMode header.
if (reply != null)
reply.writeNoException();
else
StrictMode.clearGatheredViolations();
return true;
else if (code == SHELL_COMMAND_TRANSACTION)
//省略部分
return false;
这里就可以看出来Java层面的onTransact里面会调用到dump方法,到此我们就清楚了dumpsys的dump怎么一步步调用到我们的Java层面的dump,这里我们以AMS为例子来看看dump方法:
//路径frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args)
PriorityDump.dump(mPriorityDumper, fd, pw, args);
好了那最后总结一下把,给大家画一幅图方便记忆:
csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论
以上是关于android framework系统源码分析之dumpsys原理分析-千里马带你学framework的主要内容,如果未能解决你的问题,请参考以下文章
android framework开发之广播broadcast源码分析-千里马
Android Framework 之 Window / WindowManager基本概念及addView源码分析
Android Framework 之 Window / WindowManager基本概念及addView源码分析
Android FrameWork开发之binder驱动的源码分析1