Android12 am命令的使用及实现流程分析
Posted pecuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 以上是关于Android12 am命令的使用及实现流程分析的主要内容,如果未能解决你的问题,请参考以下文章
Android 插件化Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )
android 11/12的 framework 框架systemserver源码中的AMS和WMS部分ProtoLog相关log的开放命令
android 11/12的 framework 框架systemserver源码中的AMS和WMS部分ProtoLog相关log的开放命令