文章托管在gitee上 Android Notes , 同步csdn
本文基于Android12 分析
在shell通过命令am,可以输出该命令的帮助信息,常用的命令如下
几大组件相关的命令,通过名字大概知道用途
还有其他比较有用的命令:
在命令行执行am命令
$ am
Activity manager (activity) commands:
help
Print this help text.
start-activity [-D] [-N] [-W] [-P ] [--start-profiler ]
[--sampling INTERVAL] [--streaming] [-R COUNT] [-S]
[--track-allocation] [--user | current]
Start an Activity. Options are:
...
start-service [--user | current]
Start a Service. Options are:
--user | current: Specify which user to run as; if not
specified then run as the current user.
start-foreground-service [--user | current]
Start a foreground Service. Options are:
--user | current: Specify which user to run as; if not
specified then run as the current user.
stop-service [--user | current]
Stop a Service. Options are:
--user | current: Specify which user to run as; if not
specified then run as the current user.
broadcast [--user | all | current]
Send a broadcast Intent. Options are:
--user | all | current: Specify which user to send to; if not
specified then send to all users.
--receiver-permission : Require receiver to hold permission.
--allow-background-activity-starts: The receiver may start activities
even if in the background.
instrument [-r] [-e ] [-p ] [-w]
[--user | current]
[--no-hidden-api-checks [--no-test-api-access]]
[--no-isolated-storage]
[--no-window-animation] [--abi ]
Start an Instrumentation. Typically this target is in the
...
以dumpheap命令为例,其可以指定进程的名字或pid:
dumpheap [--user current] [-n] [-g]
Dump the heap of a process. The given 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 | 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命令的位置
$ which am
/system/bin/am
将此命令pull出来内容如下,在frameworks路径下也可以找到am,可以发现有两个情况
/// @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命令的源码在 frameworks/native/cmds/cmd,编译输出到/system/bin/cmd。从activity开始到结束的所有值将成为它的参数列表。首先看它的入口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);
}
/// @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;
}
重点看该方法,向服务端发起请求。
/// @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);
}
/// @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;
}
/// @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;
}
这个方法的名字容易造成误解,它会先与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线程会处理此请求。接下来看服务端的处理。
一个典型的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);
}
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;
}
服务端收到请求会获取一个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 : ""), 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;
}
// 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。
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(&data), reinterpret_cast(reply), flags);
if (env->ExceptionCheck()) { // 异常处理
ScopedLocalRef 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 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。
// 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;
}
执行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,接下来我们看它的实现
@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方法,接下来看此方法的实现
该方法根据不同的命令,去执行不同的功能。
/// 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 命令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)
大致总结一下上述流程
接下来看第二种情况,执行 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方法做参数。
// @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.");
}
}
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");
}
做一些初始化,之后调用指定类的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));
}
/// @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
}
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();
}
...
此处的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;
}
/// @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);
}
}
@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
}
}
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
}
/// @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);
}
}
}
大致总结一下上述流程: