文章托管在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
#!/system/bin/sh
if [ "$1" != "instrument" ] ; then
cmd activity "$@"
else
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
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
std::vector<std::string_view> arguments;
arguments.reserve(argc - 1);
for (int i = 1; i < argc; ++i) {
arguments.emplace_back(argv[i]);
}
return cmdMain(arguments, android::aout, android::aerr, STDIN_FILENO, STDOUT_FILENO,
STDERR_FILENO, RunMode::kStandalone);
}
cmdMain
int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, TextOutput& errorLog,
int in, int out, int err, RunMode runMode) {
sp<ProcessState> proc = ProcessState::self();
proc->startThreadPool();
#if DEBUG
ALOGD("cmd: starting");
#endif
sp<IServiceManager> sm = defaultServiceManager();
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")) {
Vector<String16> services = sm->listServices();
services.sort(sort_func);
outputLog << "Currently running services:" << endl;
for (size_t i=0; i<services.size(); i++) {
sp<IBinder> service = sm->checkService(services[i]);
if (service != nullptr) {
outputLog << " " << services[i] << endl;
}
}
return 0;
}
bool waitForService = ((argc > 1) && (argv[0] == "-w"));
int serviceIdx = (waitForService) ? 1 : 0;
const auto cmd = argv[serviceIdx];
Vector<String16> args;
String16 serviceName = String16(cmd.data(), cmd.size());
for (int i = serviceIdx + 1; i < argc; i++) {
args.add(String16(argv[i].data(), argv[i].size()));
}
sp<IBinder> service;
if(waitForService) {
service = sm->waitForService(serviceName);
} else {
service = sm->checkService(serviceName);
}
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);
sp<MyResultReceiver> result = new MyResultReceiver();
#if DEBUG
ALOGD("cmd: Invoking %.*s in=%d, out=%d, err=%d",
static_cast<int>(cmd.size()), cmd.data(), in, out, err);
#endif
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
重点看该方法,向服务端发起请求。
status_t IBinder::shellCommand(const sp<IBinder>& target, int in, int out, int err,
Vector<String16>& args, const sp<IShellCallback>& callback,
const sp<IResultReceiver>& resultReceiver)
{
Parcel send;
Parcel reply;
send.writeFileDescriptor(in);
send.writeFileDescriptor(out);
send.writeFileDescriptor(err);
const size_t numArgs = args.size();
send.writeInt32(numArgs);
for (size_t i = 0; i < numArgs; i++) {
send.writeString16(args[i]);
}
send.writeStrongBinder(callback != nullptr ? IInterface::asBinder(callback) : nullptr);
send.writeStrongBinder(resultReceiver != nullptr ? IInterface::asBinder(resultReceiver) : nullptr);
return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply);
}
BpBinder::transact
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
bool privateVendor = flags & FLAG_PRIVATE_VENDOR;
flags = flags & ~FLAG_PRIVATE_VENDOR;
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 {
status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
}
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
IPCThreadState::transact
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");
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) {
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 {
LOG_ALWAYS_FATAL("Process may not make non-oneway calls (code: %u).", code);
}
}
if (reply) {
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 {
err = waitForResponse(nullptr, nullptr);
}
return err;
}
IPCThreadState::waitForResponse
这个方法的名字容易造成误解,它会先与binder驱动进行通信,然后根据返回的具体的cmd去执行相关逻辑。我们这里发起的是一个同步请求,请求码是BC_TRANSACTION,在最后会收到来自驱动的BR_REPLY,说明服务端已经响应并处理了请求,在这里拿到执行返回的结果。
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
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();
result = getAndExecuteCommand();
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);
}
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();
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++;
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--;
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;
}
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);
Parcel reply;
status_t error;
if (tr.target.ptr) {
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
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
@UnsupportedAppUsage
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
final int callingUid = Binder.getCallingUid();
final long origWorkSource = ThreadLocalWorkSource.setUid(callingUid);
try {
return execTransactInternal(code, dataObj, replyObj, flags, callingUid);
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
}
}
private boolean execTransactInternal(int code, long dataObj, long replyObj, int flags,
int callingUid) {
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);
boolean res;
final boolean tracingEnabled = Binder.isTracingEnabled();
try {
final BinderCallHeavyHitterWatcher heavyHitterWatcher = sHeavyHitterWatcher;
if (heavyHitterWatcher != null) {
heavyHitterWatcher.onTransaction(callingUid, getClass(), code);
}
if ((flags & FLAG_COLLECT_NOTED_APP_OPS) != 0) {
AppOpsManager.startNotedAppOpsCollection(callingUid);
try {
res = onTransact(code, data, reply, flags);
} finally {
AppOpsManager.finishNotedAppOpsCollection();
}
} else {
res = onTransact(code, data, reply, flags);
}
} catch (RemoteException|RuntimeException e) {
res = true;
} finally {
...
}
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) {
} else if (code == SHELL_COMMAND_TRANSACTION) {
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(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);
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
}
return true;
}
return false;
}
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
该方法根据不同的命令,去执行不同的功能。
@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" 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)
"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
int main(int argc, char* const argv[])
{
if (!LOG_NDEBUG) {
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());
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
argc--;
argv++;
const char* spaced_commands[] = { "-cp", "-classpath" };
bool known_command = false;
int i;
for (i = 0; i < argc; i++) {
if (known_command == true) {
runtime.addOption(strdup(argv[i]));
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;
break;
}
runtime.addOption(strdup(argv[i]));
ALOGV("app_process main add option '%s'", argv[i]);
}
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i;
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
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 {
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);
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true );
}
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (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
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");
bool primary_zygote = false;
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
primary_zygote = true;
const int LOG_BOOT_PROGRESS_START = 3000;
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;
}
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
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);
}
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
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方法
@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();
nativeFinishInit();
if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}
nativeFinishInit方法的实现在哪呢?可以看其对应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
static void com_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onStarted();
}
AppRuntime#onStarted
AndroidRuntime的onStarted函数是纯虚函数,因此具体实现在其子类AppRuntime。 在onVmCreated加载指定的类,在onStarted中调用指定类的main方法
class AppRuntime : public AndroidRuntime
{
public:
...
virtual void onVmCreated(JNIEnv* env)
{
if (mClassName.isEmpty()) {
return;
}
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));
}
virtual void onStarted()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
AndroidRuntime* ar = AndroidRuntime::getRuntime();
ar->callMain(mClassName, mClass, mArgs);
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;
}
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;
}
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);
}
env->CallStaticVoidMethod(clazz, methodId, strArray);
return NO_ERROR;
}
Am#main
public static void main(String[] args) {
(new Am()).run(args);
}
Am 继承 BaseCommand,会调用其run方法
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();
} 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();
} else {
runAmCmd(getRawArgs());
}
}
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#run
public void run() throws Exception {
StatusReporter reporter = null;
float[] oldAnims = null;
try {
if (protoFile || protoStd) {
reporter = new ProtoStatusReporter();
} else if (wait) {
reporter = new TextStatusReporter(rawMode);
}
InstrumentationWatcher watcher = null;
UiAutomationConnection connection = null;
if (reporter != null) {
watcher = new InstrumentationWatcher(reporter);
connection = new UiAutomationConnection();
}
if (noWindowAnimation) {
oldAnims = mWm.getAnimationScales();
mWm.setAnimationScale(0, 0.0f);
mWm.setAnimationScale(1, 0.0f);
mWm.setAnimationScale(2, 0.0f);
}
final ComponentName cn = parseComponentName(componentNameArg);
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);
}
}
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;
}
if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
if (watcher != null) {
if (!watcher.waitForFinish()) {
reporter.onError("INSTRUMENTATION_ABORTED: System has crashed.", false);
return;
}
}
} catch (Exception ex) {
if (reporter != null) {
reporter.onError(ex.getMessage(), true);
}
throw ex;
} finally {
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进程结束
|