Posts dumpsys源码流程分析
Post
Cancel

dumpsys源码流程分析

1.源码入口

  1. frameworks/native/cmds/dumpsys/main.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    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);
    }
    

    从入口看,每次调用都是新建了一个Dumpsys,并传入了IServiceManager,并把argc,和argv传入main函数中

  2. frameworks/native/cmds/dumpsys/dumpsys.cpp

直接看main函数,这里是用getopt_long来解析传入的参数 (注:getopt_long和getopt都是用来解析参数的,但是getopt_long可以解析长参数,都是glibc库中)

1
2
3
4
5
6
7
8
9
int Dumpsys::main(int argc, char* const argv[]) {

    while (1) {
        int c;
        int optionIndex = 0;
        c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex);
    }
}

2.命令分析

2.1 dumpsys -l

dumpsys -l 可以把当前正在运行的服务都枚举出来,如下:

1
2
3
4
5
6
7
8
9
10
11
console:/ # dumpsys -l
Currently running services:
  DockObserver
  SkgSystemUI
  SurfaceFlinger
  SurfaceFlingerAIDL
  accessibility
  account
  activity
  activity_task
//省略...

首先在main中就能看到找到 -l 的定义,并不带参数

1
2
3
4
5
6
7
 switch (c) {
     //省略
    case 'l':
            showListOnly = true;
            break;
     //省略
 }   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Vector<String16> services;
//省略
int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;

//因为showListOnly为true
if (services.empty() || showListOnly) {
        //获取当前所有正在运行的服务的名字
        services = listServices(priorityFlags, asProto);
        setServiceArgs(args, asProto, priorityFlags);
}

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++) {
            //这里的sm_其实就是在main.cpp中传入的IServiceManager
            //这里根据服务的名字去获取对应的IBinder
            //Retrieve an existing service, non-blocking.
            sp<IBinder> service = sm_->checkService(services[i]);

            if (service != nullptr) {
                bool skipped = IsSkipped(skippedServices, services[i]);
                //输出服务的名字
                std::cout << "  " << services[i] << (skipped ? " (skipped)" : "") << std::endl;
            }
        }
    }

来看看下listServices函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vector<String16> Dumpsys::listServices(int priorityFilterFlags, bool filterByProto) const {
    //这里sm_同上,返回当前存在的服务的列表
    //Return list of all existing services.
    Vector<String16> services = sm_->listServices(priorityFilterFlags);
    services.sort(sort_func);
    if (filterByProto) {
        Vector<String16> protoServices = sm_->listServices(IServiceManager::DUMP_FLAG_PROTO);
        protoServices.sort(sort_func);
        Vector<String16> intersection;
        std::set_intersection(services.begin(), services.end(), protoServices.begin(),
                              protoServices.end(), std::back_inserter(intersection));
        services = std::move(intersection);
    }
    return services;
}

如上述代码,遍历了正在运行的服务。 看到这里就可以提前给出总结: dumpsys其实也是一个外壳,负责解析传入参数的逻辑,都是调用的sm_,而sm_在 frameworks/native/cmds/dumpsys/dumpsys.h中有定义,如下,可以看到sm_就是一个IServiceManager

1
2
3
4
5
6
7
8
9
public:
    explicit Dumpsys(android::IServiceManager* sm) : sm_(sm) {
    }
//省略
private:
    android::IServiceManager* sm_;
    std::thread activeThread_;
    mutable android::base::unique_fd redirectFd_;

这里就看到在new一个dumpsys的时候,就传入了一个IServiceManager,可以回到第一部分源码入口中看下

2.2 dumpsys usb

可以在dumpsys -l中可以找到usb服务,那么用dumpsys usb就可以打印出当前usb相关状态的信息,在从dumpsys.cpp中看,usb并没有在longOptions和optstring中定义,那么getopt_long返回-1,退出循环 (注:可以查看man里的解释 If there are no more option characters, getopt() returns -1 ,getopt_long就是扩展getopt,返回值定义也是一样的)

1
2
3
4
5
6
7
8
9
10
11
12
    while (1) {
        int c;
        int optionIndex = 0;

        c = getopt_long(argc, argv, "+t:T:l", longOptions, &optionIndex);

        if (c == -1) {
            //退出循环
            break;
        }
        //省略
    }    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
Vector<String16> services;

//此时,optind=1,argc=2 , argv[]={"dumpsys","usb"}
for (int i = optind; i < argc; i++) {
        if (skipServices) {
            skippedServices.add(String16(argv[i]));
        } else {
            if (i == optind) {
                //i=1, 往services中添加usb
                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;
                }
            }
        }
    }

//services不是空的, showListOnly=false,就跳过以下的操作
if (services.empty() || showListOnly) {
//省略
}
//N=1,showListOnly=false ,也跳过以下的操作 
const size_t N = services.size();
    if (N > 1 || showListOnly) {
//省略
    }

    //N=1,也就一次循环
    for (size_t i = 0; i < N; i++) {
        // serviceName 就是"usb"
        const String16& serviceName = services[i];
        if (IsSkipped(skippedServices, serviceName)) continue;//这里跳过
        //这里startDumpThread就是开启一个线程去打印一个指定服务的信息
        if (startDumpThread(dumpTypeFlags, 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);
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
*开始一个线程去连接服务,并得到dump的输出,这个线程会重新指向输出到一个管道,
*在随后调用的stopDumpThread函数后,必须去暂停这个线程
     * Starts a thread to connect to a service and get its dump output. The thread redirects
     * the output to a pipe. Thread must be stopped by a subsequent call to {@code
     * stopDumpThread}.
     * @param dumpTypeFlags operations to perform
     * @param serviceName
     * @param args list of arguments to pass to service dump method.
     * @return {@code OK} thread is started successfully.
     *         {@code NAME_NOT_FOUND} service could not be found.
     *         {@code != OK} error
     */
status_t Dumpsys::startDumpThread(int dumpTypeFlags, 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块完成,所以生成一个线程
    // dump blocks until completion, so spawn a thread..
    activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
        if (dumpTypeFlags & TYPE_PID) {
            status_t err = dumpPidToFd(service, remote_end, dumpTypeFlags == TYPE_PID);
            reportDumpError(serviceName, err, "dumping PID");
        }
        if (dumpTypeFlags & TYPE_STABILITY) {
            status_t err = dumpStabilityToFd(service, remote_end);
            reportDumpError(serviceName, err, "dumping stability");
        }
        if (dumpTypeFlags & TYPE_THREAD) {
            status_t err = dumpThreadsToFd(service, remote_end);
            reportDumpError(serviceName, err, "dumping thread info");
        }
        if (dumpTypeFlags & TYPE_CLIENTS) {
            status_t err = dumpClientsToFd(service, remote_end);
            reportDumpError(serviceName, err, "dumping clients info");
        }
        //因为dumpTypeFlags=1, 进入以下操作,
        //这里拿的是usb服务,不带参数,args是null的
        // other types always act as a header, this is usually longer
        if (dumpTypeFlags & TYPE_DUMP) {
            status_t err = service->dump(remote_end.get(), args);
            reportDumpError(serviceName, err, "dumping");
        }
    });
    return OK;
}

关键操作 status_t err = service->dump(remote_end.get(), args);注意这里的service是一个实际调用的BpBinder 可以在frameworks/native/libs/binder/include/binder/BpBinder.h看到 BpBinder继承的IBinder。 frameworks/native/libs/binder/BpBinder.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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);
    //这里把要传入的参数args都转给Parcel做序列化
    for (size_t i = 0; i < numArgs; i++) {
        send.writeString16(args[i]);
    }
    //这里就是上报到jni里
    status_t err = transact(DUMP_TRANSACTION, send, &reply);
    return err;
}

status_t BpBinder::transact(
//省略
status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
//省略
}

在这个dump函数中,主要的工作就是把传入的参数给打包序列化,用过transact函数去上报,注意看下DUMP_TRANSACTION这个int常量 在frameworks/native/libs/binder/include/binder/IBinder.h可以看到

1
2
3
4
5
6
7
8
9
10
11
#define B_PACK_CHARS(c1, c2, c3, c4) \
    ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
//省略
public:
    enum {
        //省略
        DUMP_TRANSACTION = B_PACK_CHARS('_', 'D', 'M', 'P'),
        //省略
}
//省略
}

这DUMP_TRANSACTION打印出来值是1598311760,到这里,先暂停一下,接下来从java层开始看,找到一个相对应处理DUMP_TRANSACTION地方,就能打通上下层

3.在java层分析dump流程

最直接就是看,在java层添加了dump信息后,是如何被回调的,例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class XXXXService extends XXXX.Stub{

    @Override
    protected void dump(FileDescriptor fd, PrintWriter out, String[] args) {
            int size = args.length;
            out.println("start dump!!");
            for(int i=0 ; i < size ; i++){
                out.println("args[" + i +"]="+ args[i]);
            }
            out.println("end dump!!");
        }
    
}

在XXXX.aidl生产的IXXXX.java文件中可以看到XXXX.Stub就是继承的frameworks/base/core/java/android/os/Binder.java frameworks/base/core/java/android/os/IBinder.java IBinder.java是一个接口类,Binder.java实现了IBinder.java接口,在这里也发现了DUMP_TRANSACTION的定义,打印出来也是1598311760,和上面cpp里的DUMP_TRANSACTION对应上了,也定义dump接口

1
2
3
int DUMP_TRANSACTION        = ('_'<<24)|('D'<<16)|('M'<<8)|'P';

public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) throws RemoteException;

在Binder.java中看到有针对DUMP_TRANSACTION的处理,并且能看到在XXXX.Stub能找到对onTransact方法的重写,也是根据code来判断如何处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
            int flags) throws RemoteException {
    //省略
    else if (code == DUMP_TRANSACTION) {
            ParcelFileDescriptor fd = data.readFileDescriptor();
            //反序列化拿到参数
            String[] args = data.readStringArray();
            if (fd != null) {
                try {
                    //传递参数
                    dump(fd.getFileDescriptor(), args);
                } finally {
                    IoUtils.closeQuietly(fd);
                }
            }
            // Write the StrictMode header.
            if (reply != null) {
                reply.writeNoException();
            } else {
                StrictMode.clearGatheredViolations();
            }
            return true;
        }
    //省略
}

    public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) {
        FileOutputStream fout = new FileOutputStream(fd);
        PrintWriter pw = new FastPrintWriter(fout);
        try {
            doDump(fd, pw, args);
        } finally {
            pw.flush();
        }
    }

 void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
     //Control whether dump() calls are allowed.   
     final String disabled = sDumpDisabled;
        if (disabled == null) {
            try {
                
                dump(fd, pw, args);
            } catch (SecurityException e) {
                pw.println("Security exception: " + e.getMessage());
                throw e;
            } catch (Throwable e) {
                // Unlike usual calls, in this case if an exception gets thrown
                // back to us we want to print it back in to the dump data, since
                // that is where the caller expects all interesting information to
                // go.
                pw.println();
                pw.println("Exception occurred while dumping:");
                e.printStackTrace(pw);
            }
        } else {
            pw.println(sDumpDisabled);
        }
    }

protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
            @Nullable String[] args) {
}

从上面代码就很直观的看出来在XXXX.Stub中重写dump方法被调用的流程,

那么接下就是找onTransact方法如何被调用的,还是在Binder.java中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 // Entry point from android_util_Binder.cpp's onTransact
    @UnsupportedAppUsage
    private boolean execTransact(int code, long dataObj, long replyObj,
            int flags) {
        // At that point, the parcel request headers haven't been parsed so we do not know what
        // WorkSource the caller has set. Use calling uid as the default.
        final int callingUid = Binder.getCallingUid();
        final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid);
        try {
            return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
        } finally {
            ThreadLocalWorkSource.restore(origWorkSource);
        }
    }

在上面的注释中,就能确认execTransact是被那native层调用的,接着往下看execTransactInternal里的就能找到调用了onTransact了

4.cpp上报到java

frameworks/base/core/jni/android_util_Binder.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const char* const kBinderPathName = "android/os/Binder";

static int int_register_android_os_Binder(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderPathName);

    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    //这里初始化映射到java中Binder.java中的execTransact
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
    gBinderOffsets.mGetInterfaceDescriptor = GetMethodIDOrDie(env, clazz, "getInterfaceDescriptor",
        "()Ljava/lang/String;");
    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");

    return RegisterMethodsOrDie(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}

可以看到jni初始化,映射到了Binder.java的execTransact函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
    {
        JNIEnv* env = javavm_to_jnienv(mVM);

        LOG_ALWAYS_FATAL_IF(env == nullptr,
                            "Binder thread started or Java binder used, but env null. Attach JVM?");

        ALOGI("onTransact() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);

        IPCThreadState* thread_state = IPCThreadState::self();
        const int32_t strict_policy_before = thread_state->getStrictModePolicy();

        //printf("Transact from %p to Java code sending: ", this);
        //data.print();
        //printf("\n");
        // 这里就是cpp调用java的地方
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);

        //省略
    }

这里就是被BpBinder.cpp中transact后调用jni里的onTransact,就调用到上层了

5.流程图

This post is licensed under CC BY 4.0 by the author.

01背包-滚动数组

不同路径