IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android12 am命令的使用及实现流程分析 -> 正文阅读

[移动开发]Android12 am命令的使用及实现流程分析

文章托管在gitee上 Android Notes , 同步csdn
本文基于Android12 分析

am命令

在shell通过命令am,可以输出该命令的帮助信息,常用的命令如下
几大组件相关的命令,通过名字大概知道用途

  • start-activity 启动activity
  • start-service 启动服务
  • start-foreground-service 启动前台服务
  • stop-service 停止相关服务
  • broadcast 发送意图广播

还有其他比较有用的命令:

  • instrument 启动Instrumentation
  • dumpheap dump某个进程heap
  • force-stop 完全停止指定包名的应用
  • kill 杀死后台某指定进程
  • hang [–allow-restart] 挂起系统进程,冻屏效果
  • restart 用户空间层面重启
  • stack、task 操作activity stacks、tasks

在命令行执行am命令

$  am                                                  
Activity manager (activity) commands:
  help
      Print this help text.
  start-activity [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]
          [--sampling INTERVAL] [--streaming] [-R COUNT] [-S]
          [--track-allocation] [--user <USER_ID> | current] <INTENT>
      Start an Activity.  Options are:
      ...
  start-service [--user <USER_ID> | current] <INTENT>
      Start a Service.  Options are:
      --user <USER_ID> | current: Specify which user to run as; if not
          specified then run as the current user.
  start-foreground-service [--user <USER_ID> | current] <INTENT>
      Start a foreground Service.  Options are:
      --user <USER_ID> | current: Specify which user to run as; if not
          specified then run as the current user.
  stop-service [--user <USER_ID> | current] <INTENT>
      Stop a Service.  Options are:
      --user <USER_ID> | current: Specify which user to run as; if not
          specified then run as the current user.
  broadcast [--user <USER_ID> | all | current] <INTENT>
      Send a broadcast Intent.  Options are:
      --user <USER_ID> | all | current: Specify which user to send to; if not
          specified then send to all users.
      --receiver-permission <PERMISSION>: Require receiver to hold permission.
      --allow-background-activity-starts: The receiver may start activities
          even if in the background.
  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]
          [--user <USER_ID> | current]
          [--no-hidden-api-checks [--no-test-api-access]]
          [--no-isolated-storage]
          [--no-window-animation] [--abi <ABI>] <COMPONENT>
      Start an Instrumentation.  Typically this target <COMPONENT> is in the
...

am使用示例

以dumpheap命令为例,其可以指定进程的名字或pid:

dumpheap [--user <USER_ID> current] [-n] [-g] <PROCESS> <FILE>
    Dump the heap of a process.  The given <PROCESS> argument may
      be either a process name or pid.  Options are:
    -n: dump native heap instead of managed heap
    -g: force GC before dumping the heap
    --user <USER_ID> | current: When supplying a process name,
        specify user of process to dump; uses current user if not specified.

执行命令:

$ am dumpheap system_server
File: /data/local/tmp/heapdump-20221023-123406.prof

Exception occurred while executing 'dumpheap':
java.lang.IllegalArgumentException: Unknown process: system_server
        at com.android.server.am.ActivityManagerService.dumpHeap(ActivityManagerService.java:18596)
        at com.android.server.am.ActivityManagerShellCommand.runDumpHeap(ActivityManagerShellCommand.java:964)
        at com.android.server.am.ActivityManagerShellCommand.onCommand(ActivityManagerShellCommand.java:208)
        at android.os.BasicShellCommandHandler.exec(BasicShellCommandHandler.java:98)
        at android.os.ShellCommand.exec(ShellCommand.java:44)
        at com.android.server.am.ActivityManagerService.onShellCommand(ActivityManagerService.java:10521)
        at android.os.Binder.shellCommand(Binder.java:929)
        at android.os.Binder.onTransact(Binder.java:813)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:5027)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2883)
        at android.os.Binder.execTransactInternal(Binder.java:1159)
        at android.os.Binder.execTransact(Binder.java:1123)

当adb shell 进入后直接执行 am dumpheap system_server, 会抛出上面一个异常,说找不到这个进程,不过换成 system 就可以。从错误的调用栈可以知道,这个命令是通过 Binder#shellCommand 来实现的,am具体的实现在ActivityManagerService端。

通常我们使用pid来dump某个进程的heap,先通过pidof拿到某个进程的pid,然后执行dump

$ pidof system_server
5113
$ am dumpheap 5113
File: /data/local/tmp/heapdump-20221023-124412.prof
Waiting for dump to finish..
$ adb pull /data/local/tmp/heapdump-20221023-124412.prof
$ ~/Android/Sdk-linux/platform-tools/hprof-conv heapdump-20221023-124412.prof heapdump-20221023-124412.hprof

在dump完成后,将其pull出来。此时需要再使用hprof-conv做一下转换,才能在MAT工具中打开。

am命令解析

查看am命令的位置

$ which am
/system/bin/am

将此命令pull出来内容如下,在frameworks路径下也可以找到am,可以发现有两个情况

  • 使用 cmd 命令,binder调用到AMS,通过Binder#shellCommand 实现
  • 执行 app_process 启动虚拟机执行 Am 类,这个类后续仍然会通过Binder调用到AMS
/// @frameworks/base/cmds/am/am
#!/system/bin/sh

if [ "$1" != "instrument" ] ; then  // 第一个参数非 instrument
    cmd activity "$@"   // 通过 Binder#shellCommand 实现, $@ 表示后面的所有参数
else  // 执行 app_process 启动虚拟机执行 Am 类
    base=/system
    export CLASSPATH=$base/framework/am.jar
    exec app_process $base/bin com.android.commands.am.Am "$@"
fi

源码分析

首先分析第一种情况,cmd是一个命令,activity 是binder服务的名字,它对应的服务是ActivityManagerService

cmd activity "$@"   // 通过 Binder#shellCommand 实现, $@ 表示后面的所有参数

cmd activity …

cmd命令的源码在 frameworks/native/cmds/cmd,编译输出到/system/bin/cmd。从activity开始到结束的所有值将成为它的参数列表。首先看它的入口main方法:

main

/// @frameworks/native/cmds/cmd/main.cpp
int main(int argc, char* const argv[]) {
    signal(SIGPIPE, SIG_IGN); // 忽略pipe信号

    std::vector<std::string_view> arguments;
    arguments.reserve(argc - 1);
    // 0th argument is a program name, skipping.
    for (int i = 1; i < argc; ++i) {// 构造参数列表,0号参数是程序名,不加入
        arguments.emplace_back(argv[i]);
    }
    // 直接调用 cmdMain
    return cmdMain(arguments, android::aout, android::aerr, STDIN_FILENO, STDOUT_FILENO,
                   STDERR_FILENO, RunMode::kStandalone);
}

cmdMain

/// @frameworks/native/cmds/cmd/cmd.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(); // 初始化binder环境
    proc->startThreadPool();

#if DEBUG
    ALOGD("cmd: starting");
#endif
    sp<IServiceManager> sm = defaultServiceManager(); // 获取 ServiceManager
    if (runMode == RunMode::kStandalone) {
        fflush(stdout);
    }
    if (sm == nullptr) {
        ALOGW("Unable to get default service manager!");
        errorLog << "cmd: Unable to get default service manager!" << endl;
        return 20;
    }

    int argc = argv.size();

    if (argc == 0) { // 没有参数会输出如下提示
        errorLog << "cmd: No service specified; use -l to list all running services. Use -w to start and wait for a service." << endl;
        return 20;
    }

    if ((argc == 1) && (argv[0] == "-l")) {// -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"));// -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); // 获取binder服务代理
    }

    if (service == nullptr) {// 没有找到服务
        if (runMode == RunMode::kStandalone) {
            ALOGW("Can't find service %.*s", static_cast<int>(cmd.size()), cmd.data());
        }
        errorLog << "cmd: Can't find service: " << cmd << endl;
        return 20;
    }

    sp<MyShellCallback> cb = new MyShellCallback(errorLog); // shell回调监听
    sp<MyResultReceiver> result = new MyResultReceiver(); // 获取结果receiver

#if DEBUG
    ALOGD("cmd: Invoking %.*s in=%d, out=%d, err=%d",
          static_cast<int>(cmd.size()), cmd.data(), in, out, err);
#endif

    // TODO: block until a result is returned to MyResultReceiver.
    // 调用 binder service 的 shellCommand
    status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);
    if (error < 0) { // 处理通信错误
        const char* errstr;
        switch (error) {
            case BAD_TYPE: errstr = "Bad type"; break;
            case FAILED_TRANSACTION: errstr = "Failed transaction"; break;
            case FDS_NOT_ALLOWED: errstr = "File descriptors not allowed"; break;
            case UNEXPECTED_NULL: errstr = "Unexpected null"; break;
            default: errstr = strerror(-error); break;
        }
        if (runMode == RunMode::kStandalone) {
            ALOGW("Failure calling service %.*s: %s (%d)", static_cast<int>(cmd.size()), cmd.data(),
                  errstr, -error);
        }
        outputLog << "cmd: Failure calling service " << cmd << ": " << errstr << " (" << (-error)
                  << ")" << endl;
        return error;
    }

    cb->mActive = false;
    status_t res = result->waitForResult(); // 等待结果。
#if DEBUG
    ALOGD("result=%d", (int)res);
#endif
    return res;
}

IBinder::shellCommand

重点看该方法,向服务端发起请求。

/// @frameworks/native/libs/binder/Binder.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;
    // 写入 输入/输出/错误fd
    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]);
    }
    // 写入 callback 和 resultReceiver binder 对象
    send.writeStrongBinder(callback != nullptr ? IInterface::asBinder(callback) : nullptr);
    send.writeStrongBinder(resultReceiver != nullptr ? IInterface::asBinder(resultReceiver) : nullptr);
    // 对target服务发起调用,调用码是 SHELL_COMMAND_TRANSACTION
    // 对于客户端而言,target的本质是一个BpBinder对象
    return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply);
}

BpBinder::transact

/// @frameworks/native/libs/binder/BpBinder.cpp
// NOLINTNEXTLINE(google-default-arguments)
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) { // 如果服务还存活
        bool privateVendor = flags & FLAG_PRIVATE_VENDOR;
        // don't send userspace flags to the kernel
        flags = flags & ~FLAG_PRIVATE_VENDOR;

        // user transactions require a given stability level
        if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
            using android::internal::Stability;

            auto category = Stability::getCategory(this);
            Stability::Level required = privateVendor ? Stability::VENDOR
                : Stability::getLocalLevel();

            if (CC_UNLIKELY(!Stability::check(category, required))) {
                ALOGE("Cannot do a user transaction on a %s binder (%s) in a %s context.",
                    category.debugString().c_str(),
                    String8(getInterfaceDescriptor()).c_str(),
                    Stability::levelString(required).c_str());
                return BAD_TYPE;
            }
        }

        status_t status;
        if (CC_UNLIKELY(isRpcBinder())) {
            status = rpcSession()->transact(rpcAddress(), code, data, reply, flags);
        } else { // 此处,通过 IPCThreadState 发起 transact
            status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
        }
        // 通信返回状态码DEAD_OBJECT,说明服务已经挂了,将mAlive置为0
        if (status == DEAD_OBJECT) mAlive = 0;

        return status;
    }

    return DEAD_OBJECT;
}

IPCThreadState::transact

/// @frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    LOG_ALWAYS_FATAL_IF(data.isForRpc(), "Parcel constructed for RPC, but being used with binder.");

    status_t err;

    flags |= TF_ACCEPT_FDS;

    IF_LOG_TRANSACTIONS() {
        TextOutput::Bundle _b(alog);
        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
            << handle << " / code " << TypeCode(code) << ": "
            << indent << data << dedent << endl;
    }

    LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
        (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
    // 写入通信参数,此处发起的通信命令是 BC_TRANSACTION
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);

    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }

    if ((flags & TF_ONE_WAY) == 0) { /// 非oneway,需要等待对端响应
        if (UNLIKELY(mCallRestriction != ProcessState::CallRestriction::NONE)) {
            if (mCallRestriction == ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY) {
                ALOGE("Process making non-oneway call (code: %u) but is restricted.", code);
                CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(),
                    ANDROID_LOG_ERROR);
            } else /* FATAL_IF_NOT_ONEWAY */ {
                LOG_ALWAYS_FATAL("Process may not make non-oneway calls (code: %u).", code);
            }
        }

        if (reply) { // 与binder驱动通信并获取回复
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }

        IF_LOG_TRANSACTIONS() {
            TextOutput::Bundle _b(alog);
            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                << handle << ": ";
            if (reply) alog << indent << *reply << dedent << endl;
            else alog << "(none requested)" << endl;
        }
    } else {// oneway,无需等待,此处传递参数都是 nullptr
        err = waitForResponse(nullptr, nullptr);
    }

    return err;
}

IPCThreadState::waitForResponse

这个方法的名字容易造成误解,它会先与binder驱动进行通信,然后根据返回的具体的cmd去执行相关逻辑。我们这里发起的是一个同步请求,请求码是BC_TRANSACTION,在最后会收到来自驱动的BR_REPLY,说明服务端已经响应并处理了请求,在这里拿到执行返回的结果。

/// @frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;

    while (1) {
        /// talkWithDriver通过ioctl命令与binder驱动通信并获取返回命令与数据
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;

        cmd = (uint32_t)mIn.readInt32();
        switch (cmd) {
        case BR_ONEWAY_SPAM_SUSPECT:
            ALOGE("Process seems to be sending too many oneway calls.");
            CallStack::logStack("oneway spamming", CallStack::getCurrent().get(),
                    ANDROID_LOG_ERROR);
            [[fallthrough]];
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;
        ...
        case BR_REPLY: // 发起命令的最终,会收到一个回复
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                if (err != NO_ERROR) goto finish;

                if (reply) {
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t),
                            freeBuffer);
                    } else {
                        err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
                        freeBuffer(nullptr,
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t));
                    }
                } else {
                    freeBuffer(nullptr,
                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                        tr.data_size,
                        reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                        tr.offsets_size/sizeof(binder_size_t));
                    continue;
                }
            }
            goto finish;

        default:
            err = executeCommand(cmd); // 执行返回的其他命令
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    if (err != NO_ERROR) { // 处理错误。
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }

    return err;
}

上面,使用cmd命令获取了 ActivityManagerService 的代理对象,向AMS发起binder调用。到此时通信请求已经通过binder驱动发送给了服务端,服务端的空闲binder线程会处理此请求。接下来看服务端的处理。

IPCThreadState::joinThreadPool

一个典型的binder线程会在启动后调用joinThreadPool来开始处理binder事务,关键函数是getAndExecuteCommand。服务端是在此处被binder驱动唤醒,来处理相关请求的。

void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());

    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

    mIsLooper = true;
    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        result = getAndExecuteCommand(); // 与binder驱动通信,获取命令来处理

        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
        }

        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);

    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
        (void*)pthread_self(), getpid(), result);

    mOut.writeInt32(BC_EXIT_LOOPER);
    mIsLooper = false;
    talkWithDriver(false);
}

IPCThreadState::getAndExecuteCommand

status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;

    result = talkWithDriver(); // 与binder驱动通信,获取命令来处理
    if (result >= NO_ERROR) {
        size_t IN = mIn.dataAvail();
        if (IN < sizeof(int32_t)) return result;
        cmd = mIn.readInt32();
        IF_LOG_COMMANDS() {
            alog << "Processing top-level Command: "
                 << getReturnString(cmd) << endl;
        }

        pthread_mutex_lock(&mProcess->mThreadCountLock);
        mProcess->mExecutingThreadsCount++; // 已使用binder线程计数增加
        if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
                mProcess->mStarvationStartTimeMs == 0) { // 达到上限,后续通信无线程可用,造成饥饿状态
            mProcess->mStarvationStartTimeMs = uptimeMillis();
        }
        pthread_mutex_unlock(&mProcess->mThreadCountLock);

        result = executeCommand(cmd); // 执行命令。

        pthread_mutex_lock(&mProcess->mThreadCountLock);
        mProcess->mExecutingThreadsCount--;// 已使用binder线程计数减少
        if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
                mProcess->mStarvationStartTimeMs != 0) { // 打印饥饿持续时长
            int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
            if (starvationTimeMs > 100) {
                ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
                      mProcess->mMaxThreads, starvationTimeMs);
            }
            mProcess->mStarvationStartTimeMs = 0;
        }

        // Cond broadcast can be expensive, so don't send it every time a binder
        // call is processed. b/168806193
        if (mProcess->mWaitingForThreads > 0) { // 通知有线程可用
            pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
        }
        pthread_mutex_unlock(&mProcess->mThreadCountLock);
    }

    return result;
}

IPCThreadState::executeCommand

服务端收到请求会获取一个BR_TRANSACTION的命令,这个命令会进一步调用服务的transact方法

  status_t IPCThreadState::executeCommand(int32_t cmd)
  {
      BBinder* obj;
      RefBase::weakref_type* refs;
      status_t result = NO_ERROR;

      switch ((uint32_t)cmd) {
      //...
      case BR_TRANSACTION:
          {
              binder_transaction_data_secctx tr_secctx;
              binder_transaction_data& tr = tr_secctx.transaction_data;

              if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
                  result = mIn.read(&tr_secctx, sizeof(tr_secctx));
              } else {
                  result = mIn.read(&tr, sizeof(tr));
                  tr_secctx.secctx = 0;
              }

              ALOG_ASSERT(result == NO_ERROR,
                  "Not enough command data for brTRANSACTION");
              if (result != NO_ERROR) break;

              Parcel buffer;
              buffer.ipcSetDataReference(
                  reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                  tr.data_size,
                  reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                  tr.offsets_size/sizeof(binder_size_t), freeBuffer);
              //...

              // ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,
              //    (mCallingSid ? mCallingSid : "<N/A>"), mCallingUid);

              Parcel reply;
              status_t error;
              if (tr.target.ptr) {
                  // We only have a weak reference on the target object, so we must first try to
                  // safely acquire a strong reference before doing anything else with it.
                  if (reinterpret_cast<RefBase::weakref_type*>(
                          tr.target.ptr)->attemptIncStrong(this)) {
                      // 调用服务的transact函数。BBinder对象的实体是JavaBBinder,注册服务使用的是该对象指针
                      error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                              &reply, tr.flags);
                      reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
                  } else {
                      error = UNKNOWN_TRANSACTION;
                  }

              } else {
                  error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
              }
              //...
          }
          break;
      //...  
      return result;
  }

BBinder::transact

// NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);

    if (reply != nullptr && (flags & FLAG_CLEAR_BUF)) {
        reply->markSensitive();
    }

    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            err = pingBinder();
            break;
        case EXTENSION_TRANSACTION:
            err = reply->writeStrongBinder(getExtension());
            break;
        case DEBUG_PID_TRANSACTION:
            err = reply->writeInt32(getDebugPid());
            break;
        default:
            err = onTransact(code, data, reply, flags); // 其他code调用onTransact
            break;
    }

    // In case this is being transacted on in the same process.
    if (reply != nullptr) {
        reply->setDataPosition(0);
    }

    return err;
}

对于Java层的binder服务而言,它有一个中间层的JavaBBinder对象,作为native的Java服务代表。而对于native层,服务通常是直接继承自BBinder。

JavaBBinder::onTransact

status_t onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
{
    JNIEnv* env = javavm_to_jnienv(mVM);

    ALOGV("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");
    //回调java Binder 类的 execTransact 方法
    jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
        code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);

    if (env->ExceptionCheck()) { // 异常处理
        ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
        binder_report_exception(env, excep.get(),
                                "*** Uncaught remote exception!  "
                                "(Exceptions are not yet supported across processes.)");
        res = JNI_FALSE;
    }

    // Check if the strict mode state changed while processing the
    // call.  The Binder state will be restored by the underlying
    // Binder system in IPCThreadState, however we need to take care
    // of the parallel Java state as well.
    if (thread_state->getStrictModePolicy() != strict_policy_before) {
        set_dalvik_blockguard_policy(env, strict_policy_before);
    }

    if (env->ExceptionCheck()) {
        ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
        binder_report_exception(env, excep.get(),
                                "*** Uncaught exception in onBinderStrictModePolicyChange");
    }

    // Need to always call through the native implementation of
    // SYSPROPS_TRANSACTION.
    if (code == SYSPROPS_TRANSACTION) {
        BBinder::onTransact(code, data, reply, flags);
    }

    //aout << "onTransact to Java code; result=" << res << endl
    //    << "Transact from " << this << " to Java code returning "
    //    << reply << ": " << *reply << endl;
    return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}

以上方法主要用来回调java层服务的execTransact方法,我们执行 cmd activity,对端服务是 ActivityManagerService,而binder服务一般都是继承Binder类,先看它的execTransact。

Binder#execTransact

// 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 { // 内部调用 execTransactInternal
        return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
    } finally {
        ThreadLocalWorkSource.restore(origWorkSource);
    }
}

// 真正执行的地方
private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags,
        int callingUid) {
    // Make sure the observer won't change while processing a transaction.
    final BinderInternal.Observer observer = sObserver;
    final CallSession callSession =
            observer != null ? observer.callStarted(this, code, UNSET_WORKSOURCE) : null;
    Parcel data = Parcel.obtain(dataObj);
    Parcel reply = Parcel.obtain(replyObj);
    // theoretically, we should call transact, which will call onTransact,
    // but all that does is rewind it, and we just got these from an IPC,
    // so we'll just call it directly.
    boolean res;
    // Log any exceptions as warnings, don't silently suppress them.
    // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
    final boolean tracingEnabled = Binder.isTracingEnabled();
    try {
        final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
        if (heavyHitterWatcher != null) {
            // Notify the heavy hitter watcher, if it's enabled
            heavyHitterWatcher.onTransaction(callingUid, getClass(), code);
        }

        if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) { // appops 相关
            AppOpsManager.startNotedAppOpsCollection(callingUid);
            try {
                res = onTransact(code, data, reply, flags);
            } finally {
                AppOpsManager.finishNotedAppOpsCollection();
            }
        } else {
          // 调用onTransact,相关服务一般会重写此对方法
          // 当然,现在一般都是aidl自动生成,服务端只需复写接口的相关方法即可
            res = onTransact(code, data, reply, flags);
        }
    } catch (RemoteException|RuntimeException e) {
      // 异常处理。。
        res = true;
    } finally {
      ...
    }
    // 检查parcel 大小
    checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
    reply.recycle();
    data.recycle();
    //...
    return res;
}

Binder#onTransact

执行transact的默认实现,处理一些特殊的code。
注:ActivityManagerService有重写onTransact方法,不过调用super来让父类处理,这些特殊的code最终还是在Binder类中处理。

protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
        int flags) throws RemoteException {
    if (code == INTERFACE_TRANSACTION) { //获取接口描述符
        reply.writeString(getInterfaceDescriptor());
        return true;
    } else if (code == DUMP_TRANSACTION) { // 执行dump操作的。比如执行 dumpsys
        //...
    } else if (code == SHELL_COMMAND_TRANSACTION) { // 此处是我们关心的,执行 shell 命令
        ParcelFileDescriptor in = data.readFileDescriptor();
        ParcelFileDescriptor out = data.readFileDescriptor();
        ParcelFileDescriptor err = data.readFileDescriptor();
        String[] args = data.readStringArray();
        ShellCallback shellCallback = ShellCallback.CREATOR.createFromParcel(data);
        ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);
        try {
            if (out != null) { // 执行 shellCommand
                shellCommand(in != null ? in.getFileDescriptor() : null,
                        out.getFileDescriptor(),
                        err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
                        args, shellCallback, resultReceiver);
            }
        } finally {
            IoUtils.closeQuietly(in);
            IoUtils.closeQuietly(out);
            IoUtils.closeQuietly(err);
            // Write the StrictMode header.
            if (reply != null) {
                reply.writeNoException();
            } else {
                StrictMode.clearGatheredViolations();
            }
        }
        return true;
    }
    return false;
}

// shellCommand 实现比较简单,直接调用onShellCommand, 而后者一般都会被相关服务复写,用来实现特定的功能
public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
        @Nullable FileDescriptor err,
        @NonNull String[] args, @Nullable ShellCallback callback,
        @NonNull ResultReceiver resultReceiver) throws RemoteException {
    onShellCommand(in, out, err, args, callback, resultReceiver);
}

ActivityManagerService 复写了onShellCommand,接下来我们看它的实现

ActivityManagerService#onShellCommand

@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
        FileDescriptor err, String[] args, ShellCallback callback,
        ResultReceiver resultReceiver) {
    // 通过具体的类来处理cmd,业务逻辑拆分
    (new ActivityManagerShellCommand(this, false)).exec(
            this, in, out, err, args, callback, resultReceiver);
}

ActivityManagerShellCommand继承自 ShellCommand,执行exec会回调它的onCommand方法,接下来看此方法的实现

ActivityManagerShellCommand#onCommand

该方法根据不同的命令,去执行不同的功能。

/// frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@Override
public int onCommand(String cmd) {
    if (cmd == null) {
        return handleDefaultCommands(cmd);
    }
    final PrintWriter pw = getOutPrintWriter();
    try {
        switch (cmd) {
            case "start":
            case "start-activity":
                return runStartActivity(pw);
            case "startservice":
            case "start-service":
                return runStartService(pw, false);
            case "startforegroundservice":
            case "startfgservice":
            case "start-foreground-service":
            case "start-fg-service":
                return runStartService(pw, true);
            ...
            case "dumpheap":
            return runDumpHeap(pw);
  ...
}

当执行完命令,怎么通知客户端?在ShellCommand的exec方法中

public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
        String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
    mShellCallback = callback;
    mResultReceiver = resultReceiver;
    final int result = super.exec(target, in, out, err, args);

    if (mResultReceiver != null) {
        mResultReceiver.send(result, null); // 发送结果到客户端
    }

    return result;
}

实验:查看cmd调用栈

做一个实验,使用 cmd 命令hang住系统,此时系统和cmd都处于阻塞状态。

# cmd activity hang
Hanging the system...

使用debuggerd -b命令输出cmd的调用栈:

$ adb shell ps -Af|grep cmd     # 查找cmd进程
root           6366   6293 0 14:21:18 pts/1 00:00:00 cmd activity hang
$ adb shell debuggerd -b 6366 > 6366.txt  # 输出 cmd 进程的 trace
$ adb shell pidof system_server
520
$ adb shell debuggerd -j 520 > 520.txt    # 输出系统进程的 trace

pull出binder调用的log

$ adb root
restarting adbd as root
$ adb pull /dev/binderfs/binder_logs/
/dev/binderfs/binder_logs/: 101 files pulled. 3.6 MB/s (858138 bytes in 0.229s)

查看transactions文件,找到6366的通信记录

binder transactions:
proc 6366
context binder
  thread 6366: l 10 need_return 0 tr 0
   // 此行指示通信两端的 进程id:线程id
    outgoing transaction 109362: 0000000000000000 from 6366:6366 to 520:4420 code 5f434d44 flags 10 pri 0:120 r1
    node work 109363: u00000000f34c0690 c00000000f3500224
    node work 109365: u00000000f34c0530 c00000000f3400a94
    transaction complete

分别打开 6366.txt 和 520.txt ,查看cmd进程的6366线程和系统进程的4420线程

// cmd 进程执行binder调用,等待对端完成。
"cmd" sysTid=6366
    #00 pc 00000b97  [vdso] (__kernel_vsyscall+7)
    #01 pc 000cd46c  /apex/com.android.runtime/lib/bionic/libc.so (__ioctl+28) (BuildId: 6e3a0180fa6637b68c0d181c343e6806)
    #02 pc 00080e6a  /apex/com.android.runtime/lib/bionic/libc.so (ioctl+58) (BuildId: 6e3a0180fa6637b68c0d181c343e6806)
    #03 pc 0005113b  /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+331) (BuildId: 395e4893e4bc58851a34df93c2dd1b01)
    #04 pc 0005255c  /system/lib/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+124) (BuildId: 395e4893e4bc58851a34df93c2dd1b01)
    #05 pc 00052211  /system/lib/libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+177) (BuildId: 395e4893e4bc58851a34df93c2dd1b01)
    #06 pc 00049049  /system/lib/libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+153) (BuildId: 395e4893e4bc58851a34df93c2dd1b01)
    #07 pc 00046e83  /system/lib/libbinder.so (android::IBinder::shellCommand(android::sp<android::IBinder> const&, int, int, int, android::Vector<android::String16>&, android::sp<android::IShellCallback> const&, android::sp<android::IResultReceiver> const&)+643) (BuildId: 395e4893e4bc58851a34df93c2dd1b01)
    #08 pc 00005eef  /system/bin/cmd (cmdMain(std::__1::vector<std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::allocator<std::__1::basic_string_view<char, std::__1::char_traits<char> > > > const&, android::TextOutput&, android::TextOutput&, int, int, int, RunMode)+1551) (BuildId: 532cc6903869a7093a7676d1a1f756e9)
    #09 pc 00005798  /system/bin/cmd (main+264) (BuildId: 532cc6903869a7093a7676d1a1f756e9)
    #10 pc 000522e3  /apex/com.android.runtime/lib/bionic/libc.so (__libc_init+115) (BuildId: 6e3a0180fa6637b68c0d181c343e6806)

// 系统进程执行shell Command
"Binder:520_12" prio=5 tid=124 Blocked
| group="main" sCount=1 dsCount=0 flags=1 obj=0x12c40e08 self=0xb242a010
| sysTid=4420 nice=0 cgrp=foreground sched=0/0 handle=0xae7fc1e0
| state=S schedstat=( 258290515 8629757 1593 ) utm=17 stm=8 core=3 HZ=100
| stack=0xae701000-0xae703000 stackSize=1008KB
| held mutexes=
at com.android.server.am.ActivityManagerService.hang(ActivityManagerService.java:9341)
- waiting to lock <0x033c9ff3> (a com.android.server.am.ActivityManagerService) held by thread 118
at com.android.server.am.ActivityManagerShellCommand.runHang(ActivityManagerShellCommand.java:1693)
at com.android.server.am.ActivityManagerShellCommand.onCommand(ActivityManagerShellCommand.java:238)
at android.os.BasicShellCommandHandler.exec(BasicShellCommandHandler.java:98)
at android.os.ShellCommand.exec(ShellCommand.java:44)
at com.android.server.am.ActivityManagerService.onShellCommand(ActivityManagerService.java:10521)
at android.os.Binder.shellCommand(Binder.java:929)
at android.os.Binder.onTransact(Binder.java:813)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:5027)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2883)
at android.os.Binder.execTransactInternal(Binder.java:1159)
at android.os.Binder.execTransact(Binder.java:1123)

小结

大致总结一下上述流程

  • 执行cmd命令,查找对应服务,获取相关服务的代理BpBinder对象。cmd进程为客户端进程。
  • 通过该代理BpBinder对象向对应服务发起请求,指定通信吗为SHELL_COMMAND_TRANSACTION
  • binder驱动处理该事件,并把请求传递到服务端
  • 服务端收到请求,执行其onTransact方法处理请求
  • 在onTransact方法中,根据指定的code执行shellCommand方法,该方法会回调相关服务的onShellCommand方法实现
  • 在服务的onShellCommand方法中执行具体请求,并向发起端发送结果。
  • 客户端收到响应后执行相关逻辑退出,此次请求结束

exec app_process …

接下来看第二种情况,执行 app_process 启动虚拟机执行 Am 类,后面接的都会转换为参数列表

base=/system
export CLASSPATH=$base/framework/am.jar   // 指定classpath
exec app_process $base/bin com.android.commands.am.Am "$@"

执行 app_process ,父路径是 /system/bin , 指定的类是 com.android.commands.am.Am,它在am.jar 中。类后面的 $@ 是使用者传递的参数,会传递到 Am 类的main方法做参数。

app_main#main

// @frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
    if (!LOG_NDEBUG) { // debug 打印出所有参数
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
    }
    // 构建 runtime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    // ignore argv[0] // 参数0通常是命令自身,此处应该是app_process
    argc--;
    argv++;

    // Everything up to '--' or first non '-' arg goes to the vm.
    //
    // The first argument after the VM args is the "parent dir", which
    // is currently unused.
    //
    // After the parent dir, we expect one or more the following internal
    // arguments :
    //
    // --zygote : Start in zygote mode
    // --start-system-server : Start the system server.
    // --application : Start in application (stand alone, non zygote) mode.
    // --nice-name : The nice name for this process.
    //
    // For non zygote starts, these arguments will be followed by
    // the main class name. All remaining arguments are passed to
    // the main method of this class.
    //
    // For zygote starts, all remaining arguments are passed to the zygote.
    // main function.
    //
    // Note that we must copy argument string values since we will rewrite the
    // entire argument block when we apply the nice name to argv0.
    //
    // As an exception to the above rule, anything in "spaced commands"
    // goes to the vm even though it has a space in it.
    const char* spaced_commands[] = { "-cp", "-classpath" };
    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
    bool known_command = false;

    int i;
    for (i = 0; i < argc; i++) { // 解析虚拟机参数,包括匹配 spaced_commands 的参数
        if (known_command == true) {
          runtime.addOption(strdup(argv[i]));
          // The static analyzer gets upset that we don't ever free the above
          // string. Since the allocation is from main, leaking it doesn't seem
          // problematic. NOLINTNEXTLINE
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }

        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          if (strcmp(argv[i], spaced_commands[j]) == 0) {// 匹配上则进行标记,会将其后面的参数加入虚拟机参数
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        if (argv[i][0] != '-') { // 参数第一位需要是 -
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) { // 参数是单独 -- ,则会被跳过
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        // The static analyzer gets upset that we don't ever free the above
        // string. Since the allocation is from main, leaking it doesn't seem
        // problematic. NOLINTNEXTLINE
        ALOGV("app_process main add option '%s'", argv[i]);
    }

    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument. // 跳过parent dir,此处是$base/bin,即 /system/bin
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) { // 解析是否zygote模式
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) { // 是否启动 system_server
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {// 解析是否 application 模式
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) { // 是否指定名字
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) { // 其他内容被设置成 className, 此处是com.android.commands.am.Am
            className.setTo(arg);
            break; // className 后面一般是参数,不需要解析,跳出循环。
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) { // className 不为空
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool")); // 非application模式,指定为tool
        runtime.setClassNameAndArgs(className, argc - i, argv + i); // 设置className和参数

        if (!LOG_NDEBUG) { // 调试打印。
          String8 restOfArgs;
          char* const* argv_new = argv + i;
          int argc_new = argc - i;
          for (int k = 0; k < argc_new; ++k) {
            restOfArgs.append("\"");
            restOfArgs.append(argv_new[k]);
            restOfArgs.append("\" ");
          }
          ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
        }
    } else { // 下面是走zygote模式的
        // We're in zygote mode.
        maybeCreateDalvikCache();

        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }

        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) { // 有指定名字此时设置
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) { // 指定了className走此处,
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

AndroidRuntime::start

runtime启动虚拟机,并调用RuntimeInit类的main方法。此处className是com.android.internal.os.RuntimeInit

/// @frameworks/base/core/jni/AndroidRuntime.cpp
/*
 * Start the Android runtime.  This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method in the class
 * named by "className".
 *
 * Passes the main function two arguments, the class name and the specified
 * options string.
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());

    static const String8 startSystemServer("start-system-server");
    // Whether this is the primary zygote, meaning the zygote which will fork system server.
    bool primary_zygote = false;

    /*
     * 'startSystemServer == true' means runtime is obsolete and not run from
     * init.rc anymore, so we print out the boot start event here.
     */
    for (size_t i = 0; i < options.size(); ++i) {
        if (options[i] == startSystemServer) { // 如果配置启动 system_server
            primary_zygote = true;
           /* track our progress through the boot sequence */
           const int LOG_BOOT_PROGRESS_START = 3000;
           // 输出event log : boot_progress_start
           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    }

    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /system does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    const char* artRootDir = getenv("ANDROID_ART_ROOT");
    if (artRootDir == NULL) {
        LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
        return;
    }

    const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
    if (i18nRootDir == NULL) {
        LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
        return;
    }

    const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
    if (tzdataRootDir == NULL) {
        LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
        return;
    }

    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { // 启动虚拟机
        return;
    }
    onVmCreated(env);  // 通知mv创建完成

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {  // 注册系统jni函数
        ALOGE("Unable to register all android natives\n");
        return;
    }

    // 接下来,创建参数数组,然后调用指定类的main方法,此处是RuntimeInit#main
    /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); // 创建String数组
    assert(strArray != NULL);
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    for (size_t i = 0; i < options.size(); ++i) { // 填充参数到新数组
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {  // 调用主类的main方法,此处是RuntimeInit#main
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    free(slashClassName);
    // main 方法退出后销毁虚拟机
    ALOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)
        ALOGW("Warning: VM did not shut down cleanly\n");
}

RuntimeInit#main

做一些初始化,之后调用指定类的main方法

/// @frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
@UnsupportedAppUsage
public static final void main(String[] argv) {
    preForkInit();
    if (argv.length == 2 && argv[1].equals("application")) {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
        redirectLogStreams();
    } else {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool");
    }

    commonInit(); // 做一些基础初始化,比如设置异常处理器

    /*
     * Now that we're running in interpreted code, call back into native code
     * to run the system.
     */
    nativeFinishInit(); // native 方法

    if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}

nativeFinishInit方法的实现在哪呢?可以看其对应jni函数注册函数,在AndroidRuntime.cpp中

/// @frameworks/base/core/jni/AndroidRuntime.cpp
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
            {"nativeFinishInit", "()V",
             (void*)com_android_internal_os_RuntimeInit_nativeFinishInit},
            {"nativeSetExitWithoutCleanup", "(Z)V",
             (void*)com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup},
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
        methods, NELEM(methods));
}

com_android_internal_os_RuntimeInit_nativeFinishInit

/// @frameworks/base/core/jni/AndroidRuntime.cpp
/*
 * Code written in the Java Programming Language calls here from main().
 */
static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onStarted(); // 回调AndroidRuntime的onStarted
}

AppRuntime#onStarted

AndroidRuntime的onStarted函数是纯虚函数,因此具体实现在其子类AppRuntime。
在onVmCreated加载指定的类,在onStarted中调用指定类的main方法

class AppRuntime : public AndroidRuntime
{
public:
    ...
    // 创建虚拟机后回调,如指定了主类,则会在此处去加载
    virtual void onVmCreated(JNIEnv* env)
    {
        if (mClassName.isEmpty()) {
            return; // Zygote. Nothing to do here.
        }

        /*
         * This is a little awkward because the JNI FindClass call uses the
         * class loader associated with the native method we're executing in.
         * If called in onStarted (from RuntimeInit.finishInit because we're
         * launching "am", for example), FindClass would see that we're calling
         * from a boot class' native method, and so wouldn't look for the class
         * we're trying to look up in CLASSPATH. Unfortunately it needs to,
         * because the "am" classes are not boot classes.
         *
         * The easiest fix is to call FindClass here, early on before we start
         * executing boot class Java code and thereby deny ourselves access to
         * non-boot classes.
         */
        char* slashClassName = toSlashClassName(mClassName.string());
        mClass = env->FindClass(slashClassName);
        if (mClass == NULL) {
            ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
        }
        free(slashClassName);

        mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
    }

    // 接上,gCurRuntime->onStarted 实际调用到此处。
    virtual void onStarted()
    {   // 初始化binder环境,开启binder线程池
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();

        AndroidRuntime* ar = AndroidRuntime::getRuntime();
        ar->callMain(mClassName, mClass, mArgs); // 调用主类(即com.android.commands.am.Am)的main方法,
        // 执行到此处,说明主main方法已退出,此时需要结束进程,进行一些清理。
        IPCThreadState::self()->stopProcess();
        hardware::IPCThreadState::self()->stopProcess();
    }
    ...

AndroidRuntime::callMain

此处的className是com.android.commands.am.Am

frameworks/base/core/jni/AndroidRuntime.cpp
status_t AndroidRuntime::callMain(const String8& className, jclass clazz,
    const Vector<String8>& args)
{
    JNIEnv* env;
    jmethodID methodId;

    ALOGD("Calling main entry %s", className.string());

    env = getJNIEnv();
    if (clazz == NULL || env == NULL) {
        return UNKNOWN_ERROR;
    }
    // 获取主类的main方法id
    methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
    if (methodId == NULL) {
        ALOGE("ERROR: could not find method %s.main(String[])\n", className.string());
        return UNKNOWN_ERROR;
    }

    /*
     * We want to call main() with a String array with our arguments in it.
     * Create an array and populate it.
     */
    jclass stringClass;
    jobjectArray strArray;
    // 构造参数列表
    const size_t numArgs = args.size();
    stringClass = env->FindClass("java/lang/String");
    strArray = env->NewObjectArray(numArgs, stringClass, NULL);

    for (size_t i = 0; i < numArgs; i++) {
        jstring argStr = env->NewStringUTF(args[i].string());
        env->SetObjectArrayElement(strArray, i, argStr);
    }

    // 调用主类com.android.commands.am.Am的main方法
    env->CallStaticVoidMethod(clazz, methodId, strArray);
    return NO_ERROR;
}

Am#main

/// @frameworks/base/cmds/am/src/com/android/commands/am/Am.java
/**
 * Command-line entry point.
 *
 * @param args The command-line arguments
 */
public static void main(String[] args) {
    (new Am()).run(args);
}

Am 继承 BaseCommand,会调用其run方法

/// @frameworks/base/core/java/com/android/internal/os/BaseCommand.java
/**
 * Call to run the command.
 */
public void run(String[] args) {
    if (args.length < 1) {
        onShowUsage(System.out); // 没有指定参数,显示帮助
        return;
    }

    mRawArgs = args;
    mArgs.init(null, null, null, null, args, 0); // 初始化参数

    try {
        onRun(); /// 回调 Am#onRun
    } catch (IllegalArgumentException e) {
        onShowUsage(System.err);
        System.err.println();
        System.err.println("Error: " + e.getMessage());
    } catch (Exception e) {
        e.printStackTrace(System.err);
        System.exit(1);
    }
}

Am#onRun

@Override
public void onRun() throws Exception {

    mAm = ActivityManager.getService();
    if (mAm == null) {
        System.err.println(NO_SYSTEM_ERROR_CODE);
        throw new AndroidException("Can't connect to activity manager; is the system running?");
    }

    mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
    if (mPm == null) {
        System.err.println(NO_SYSTEM_ERROR_CODE);
        throw new AndroidException("Can't connect to package manager; is the system running?");
    }

    String op = nextArgRequired();

    if (op.equals("instrument ")) {
        runInstrument();  // 指定 instrument 走此逻辑
    } else {
        runAmCmd(getRawArgs()); // 否则还是直接cmd,使用shellCommand
    }
}

Am#runInstrument

public void runInstrument() throws Exception {
    Instrument instrument = new Instrument(mAm, mPm);

    String opt;
    while ((opt=nextOption()) != null) {  // 参数解析
        if (opt.equals("-p")) {
            instrument.profileFile = nextArgRequired();
        } else if (opt.equals("-w")) {
            instrument.wait = true;
        } else if (opt.equals("-r")) {
            instrument.rawMode = true;
        } else if (opt.equals("-m")) {
            instrument.protoStd = true;
        } else if (opt.equals("-f")) {
            instrument.protoFile = true;
            if (peekNextArg() != null && !peekNextArg().startsWith("-"))
                instrument.logPath = nextArg();
        } else if (opt.equals("-e")) {
            final String argKey = nextArgRequired();
            final String argValue = nextArgRequired();
            instrument.args.putString(argKey, argValue);
        } else if (opt.equals("--no_window_animation")
                || opt.equals("--no-window-animation")) {
            instrument.noWindowAnimation = true;
        } else if (opt.equals("--no-hidden-api-checks")) {
            instrument.disableHiddenApiChecks = true;
        } else if (opt.equals("--no-test-api-access")) {
            instrument.disableTestApiChecks = false;
        } else if (opt.equals("--no-isolated-storage")) {
            instrument.disableIsolatedStorage = true;
        } else if (opt.equals("--user")) {
            instrument.userId = parseUserArg(nextArgRequired());
        } else if (opt.equals("--abi")) {
            instrument.abi = nextArgRequired();
        } else if (opt.equals("--no-restart")) {
            instrument.noRestart = true;
        } else {
            System.err.println("Error: Unknown option: " + opt);
            return;
        }
    }

    if (instrument.userId == UserHandle.USER_ALL) {
        System.err.println("Error: Can't start instrumentation with user 'all'");
        return;
    }

    instrument.componentNameArg = nextArgRequired();
    instrument.run(); // 启动 instrument
}

Instrument#run

/// @frameworks/base/cmds/am/src/com/android/commands/am/Instrument.java
/**
 * Run the instrumentation.
 */
public void run() throws Exception {
    StatusReporter reporter = null;
    float[] oldAnims = null;

    try {
        // Choose which output we will do.
        if (protoFile || protoStd) {
            reporter = new ProtoStatusReporter();
        } else if (wait) {
            reporter = new TextStatusReporter(rawMode);
        }

        // Choose whether we have to wait for the results.
        InstrumentationWatcher watcher = null;
        UiAutomationConnection connection = null;
        if (reporter != null) {
            watcher = new InstrumentationWatcher(reporter);
            connection = new UiAutomationConnection();
        }

        // Set the window animation if necessary
        if (noWindowAnimation) {
            oldAnims = mWm.getAnimationScales();
            mWm.setAnimationScale(0, 0.0f);
            mWm.setAnimationScale(1, 0.0f);
            mWm.setAnimationScale(2, 0.0f);
        }

        // Figure out which component we are trying to do.
        final ComponentName cn = parseComponentName(componentNameArg);

        // Choose an ABI if necessary
        if (abi != null) {
            final String[] supportedAbis = Build.SUPPORTED_ABIS;
            boolean matched = false;
            for (String supportedAbi : supportedAbis) {
                if (supportedAbi.equals(abi)) {
                    matched = true;
                    break;
                }
            }
            if (!matched) {
                throw new AndroidException(
                        "INSTRUMENTATION_FAILED: Unsupported instruction set " + abi);
            }
        }

        // Start the instrumentation
        int flags = 0;
        if (disableHiddenApiChecks) {
            flags |= INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
        }
        if (disableTestApiChecks) {
            flags |= INSTR_FLAG_DISABLE_TEST_API_CHECKS;
        }
        if (disableIsolatedStorage) {
            flags |= INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
        }
        if (noRestart) {
            flags |= INSTR_FLAG_NO_RESTART;
        }

        /// 关键点,通过startInstrumentation binder调用到AMS,之后AMS开始对某应用执行instrument
        if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
                    abi)) {
            throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
        }

        // If we have been requested to wait, do so until the instrumentation is finished.
        if (watcher != null) {
            if (!watcher.waitForFinish()) {
                reporter.onError("INSTRUMENTATION_ABORTED: System has crashed.", false);
                return;
            }
        }
    } catch (Exception ex) {
        // Report failures
        if (reporter != null) {
            reporter.onError(ex.getMessage(), true);
        }

        // And re-throw the exception
        throw ex;
    } finally {
        // Clean up
        if (oldAnims != null) {
            mWm.setAnimationScales(oldAnims);
        }
    }
}

小结

大致总结一下上述流程:

  • exec app_process 启动虚拟机,执行com.android.internal.os.RuntimeInit的main方法。
  • RuntimeInit的main方法做一些初始化,并调用nativeFinishInit去执行Am的main方法
  • Am的main方法执行IActivityManager#startInstrumentation向AMS发起请求
  • AMS处理instrument请求。
  • Am的main方法执行结束后,停止虚拟机,app_process进程结束
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:39:30  更:2022-11-05 00:42:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 23:22:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码