android framework系统源码分析之dumpsys原理分析-千里马带你学framework

107 篇文章 10 订阅
72 篇文章 0 订阅

背景:

hi,粉丝朋友们大家好!
我们学习android framework实战开发过程中经常会用到一些辅助的shell命令,比如最经典就是我们常见的dumpsys啦,还记我给大家讲解的入门课,实战课,跨进程专题课其实都用用到这个命令;当时我只是给大家讲解怎么使用这种dumpsys一些命令,并没有给大家讲解它的一个原理,但是对于对android系统充满好奇小伙伴们,肯定不满足与简单使用,还是想搞明白他到到底什么原理,那么搞懂它到底有什么好处么?那当然是好处多多,我这里给大家主要罗列一下几点:
1、分析出dumpsys实现原理,可以知道他是怎么实现的整套系统各个调试运作,方便我们以后自己取实现新调试系统的参考
2、可以分析dumpsys架构源码,推断出要dump某个类信息时候是使用哪个命令,而不是现在的完全靠经验记住几个常用dumpsys命令
3、在自己开发模块过程中也可以自己借助dump来多打印一些自己的调试信息
。。。。

好了大概有以上几点的好处,其他不一一列举,我相信以上3点就对大家非常非常有用了,毕竟你已经和不懂dumpsys的小伙伴已经差距拉开了,好了下面开始我们的分析dumpsys之旅。

入门课,实战课,跨进程专题
ps需要学习深入framework课程和课程优惠
(可以加我qq:2102309716 优惠购买)

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_end{std::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跨进程通信实战视频课程(加群获取优惠)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值