欢迎光临散文网 会员登陆 & 注册

安卓车机系统adb shell cmd 源码原理分析

2023-01-19 11:27 作者:千里马学框架  | 我要投稿

hi,粉丝朋友们大家好!

      上一次视频分享了input专题课中input命令在android 12的更新,因为原来课程是基于android 10  (可以加我扣:2102309716 优惠购买)

      [https://ke.qq.com/course/package/77595?tuin=7d4eb354](https://ke.qq.com/course/package/77595?tuin=7d4eb354)

      [https://www.bilibili.com/video/BV1aK41117mw/](https://www.bilibili.com/video/BV1aK41117mw/)

      具体input命令的更新大家看以上视频既可以,顺便补充一下视频中流程图:

      


本文主要来补充一下视频中没有详细讲解的cmd命令

一般cmd命令使用格式一般是:

adb shell cmd xxxx

这里xxx其实一般是我们的系统服务名字,其[跨进程课](https://ke.qq.com/course/package/77595?tuin=7d4eb354)中servicemanager列表中保存的所有服务名字


然后他就会触发对应服务的onShellCommand方法,这个时候相当于和dumpsys命令非常类似,dumpsys命令是会触发到对应的服务的dump方法

[https://blog.csdn.net/learnframework/article/details/122596598](https://blog.csdn.net/learnframework/article/details/122596598)

那么下面来源码级别分析一下cmd命令,因为上面都是大概的讲解,没有拿出源码来证明。


代码路径:

frameworks/native/cmds/cmd/main.cpp


```cpp

#include <unistd.h>


#include "cmd.h"


int main(int argc, char* const argv[]) {

    signal(SIGPIPE, SIG_IGN);


    std::vector<std::string_view> arguments;

    arguments.reserve(argc - 1);

    // 0th argument is a program name, skipping.

    for (int i = 1; i < argc; ++i) {

        arguments.emplace_back(argv[i]);

    }


    return cmdMain(arguments, android::aout, android::aerr, STDIN_FILENO, STDOUT_FILENO,

                   STDERR_FILENO, RunMode::kStandalone);

}


```

这里可以看出主要执行的是cmdMain方法


```cpp

int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, TextOutput& errorLog,

            int in, int out, int err, RunMode runMode) {

    sp<ProcessState> proc = ProcessState::self();

    proc->startThreadPool();


#if DEBUG

    ALOGD("cmd: starting");

#endif

    sp<IServiceManager> sm = defaultServiceManager();

    //ignoe

    if ((argc == 1) && (argv[0] == "-l")) {

        Vector<String16> services = sm->listServices();

        services.sort(sort_func);

        outputLog << "Currently running services:" << endl;


        for (size_t i=0; i<services.size(); i++) {

            sp<IBinder> service = sm->checkService(services[i]);

            if (service != nullptr) {

                outputLog << "  " << services[i] << endl;

            }

        }

        return 0;

    }


    bool waitForService = ((argc > 1) && (argv[0] == "-w"));

    int serviceIdx = (waitForService) ? 1 : 0;

    const auto cmd = argv[serviceIdx];


    Vector<String16> args;

    String16 serviceName = String16(cmd.data(), cmd.size());

    for (int i = serviceIdx + 1; i < argc; i++) {

        args.add(String16(argv[i].data(), argv[i].size()));

    }

    sp<IBinder> service;

    if(waitForService) {

        service = sm->waitForService(serviceName);

    } else {

        service = sm->checkService(serviceName);

    }


    //ignoe

    sp<MyShellCallback> cb = new MyShellCallback(errorLog);

    sp<MyResultReceiver> result = new MyResultReceiver();

    // TODO: block until a result is returned to MyResultReceiver.

    status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);

     //ignoe

    cb->mActive = false;

    status_t res = result->waitForResult();

#if DEBUG

    ALOGD("result=%d", (int)res);

#endif

    return res;

}


```

cmdMain的代码其实也简单,主要做了以下几步工作:

1、解析出cmd命令后面的服务字符,根据这个服务字符去servicemanager寻找对应service,返回对应的BpBinder

2、获取了BpBinder后调用IBinder::shellCommand方法,这个方法是最为关键,它会调用到服务端的onShellCommand方法

3、等带服务返回结果


这里继续看看IBinder::shellCommand怎么调用的到服务端的:


```cpp

status_t IBinder::shellCommand(const sp<IBinder>& target, int in, int out, int err,

    Vector<String16>& args, const sp<IShellCallback>& callback,

    const sp<IResultReceiver>& resultReceiver)

{

    Parcel send;

    Parcel reply;

    send.writeFileDescriptor(in);

    send.writeFileDescriptor(out);

    send.writeFileDescriptor(err);

    const size_t numArgs = args.size();

    send.writeInt32(numArgs);

    for (size_t i = 0; i < numArgs; i++) {

        send.writeString16(args[i]);

    }

    send.writeStrongBinder(callback != nullptr ? IInterface::asBinder(callback) : nullptr);

    send.writeStrongBinder(resultReceiver != nullptr ? IInterface::asBinder(resultReceiver) : nullptr);

    return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply);

}

```

这里大家如果学习过跨进程专题应该非常熟悉这个,可以看到最后其实是构造了一个Parcel调用了transact方法进行传递,当transact调用完成后就会到服务端的transact再调用到onShellCommand


安卓车机系统adb shell cmd 源码原理分析的评论 (共 条)

分享到微博请遵守国家法律