debug:am、cmd命令源码分析

am命令的实现

手机里的am

:/ # which am
/system/bin/am
:/ # file /system/bin/am
/system/bin/am: /system/bin/sh script
:/ # cat am
#!/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

aosp里的am代码位置

frameworks/base/cmds/am$

am命令是个shell脚本,非instrument时调用cmd命令。am.jar也在手机里,/system/framework/am.jar

am.jar

只有俩文件

frameworks/base/cmds/am/src/com/android/commands/am$ ls
Am.java Instrument.java

frameworks/base/cmds/am/src/com/android/commands/am/Am.java

 39 public class Am extends BaseCommand {
49 public static void main(String[] args) {
50 (new Am()).run(args);
51 }
------------------------------------------------------------------
62 @Override
63 public void onRun() throws Exception {
64
65 mAm = ActivityManager.getService();
71 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
77 String op = nextArgRequired();
78
79 if (op.equals("instrument")) {
80 runInstrument();
81 } else {
82 runAmCmd(getRawArgs());
------------------------------------------------------------------
138 void runAmCmd(String[] args) throws AndroidException {
139 final MyShellCallback cb = new MyShellCallback();
140 try {
141 mAm.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
142 args, cb, new ResultReceiver(null) { });
143 } catch (RemoteException e) {

50行的run是在父类BaseCommand里,然后又分发到子类onRun方法

如果是通过am命令来启动的话,这里只会走到80行,但是,am.jar也是可以完全支持cmd activity相同的效果。

直接运行am.jar时就走到82行了,在141行binder沟通ams。

cmd命令的实现

手机里的cmd

:/ # which cmd
/system/bin/cmd
:/ # file /system/bin/cmd
/system/bin/cmd: ELF shared object, 64-bit LSB arm64, dynamic (/system/bin/linker64), for Android 30, BuildID=ab0acb6f2e4ab587eb5166cd5c29e254, stripped

cmd是个二进制可执行程序

aosp里的cmd代码位置

frameworks/native/cmds/cmd

cmd activity

cmd activity发生了什么

frameworks/native/cmds/cmd/main.cpp

21 int main(int argc, char* const argv[]) {
22 signal(SIGPIPE, SIG_IGN);
23
24 std::vector<std::string_view> arguments;
25 arguments.reserve(argc - 1);
26 // 0th argument is a program name, skipping.
27 for (int i = 1; i < argc; ++i) {
28 arguments.emplace_back(argv[i]);
29 }
30
31 return cmdMain(arguments, android::aout, android::aerr, STDIN_FILENO, STDOUT_FILENO,
32 STDERR_FILENO, RunMode::kStandalone);
33 }

cmd.cpp#cmdMain

啥都没干,跳到cmd.cpp#cmdMain

frameworks/native/cmds/cmd/cmd.cpp

167 int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, TextOutput& errorLog,
168 int in, int out, int err, RunMode runMode) {
169 sp<ProcessState> proc = ProcessState::self();
170 proc->startThreadPool();
175 sp<IServiceManager> sm = defaultServiceManager();
215 sp<IBinder> service;
216 if(waitForService) {
217 service = sm->waitForService(serviceName);
218 } else {
219 service = sm->checkService(serviceName);
220 }
239 status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);

169、170、171行老三样,沟通binder驱动,拿到ServiceManager的代理

217、219行拿到传入参数的binder代理。我们传的是activity,所以这就是ams的代理。

239行,通过代理发起ipc调用。

Binder.cpp#shellCommand

frameworks/native/libs/binder/Binder.cpp

 66 status_t IBinder::shellCommand(const sp<IBinder>& target, int in, int out, int err,
67 Vector<String16>& args, const sp<IShellCallback>& callback,
68 const sp<IResultReceiver>& resultReceiver)
69 {
70 Parcel send;
71 Parcel reply;
72 send.writeFileDescriptor(in);
73 send.writeFileDescriptor(out);
74 send.writeFileDescriptor(err);
75 const size_t numArgs = args.size();
76 send.writeInt32(numArgs);
77 for (size_t i = 0; i < numArgs; i++) {
78 send.writeString16(args[i]);
79 }
80 send.writeStrongBinder(callback != nullptr ? IInterface::asBinder(callback) : nullptr);
81 send.writeStrongBinder(resultReceiver != nullptr ? IInterface::asBinder(resultReceiver) : nullptr);
82 return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply);
83 }

binder的流转细节就不说了,直接跳到服务端,看针对这个命令的处理SHELL_COMMAND_TRANSACTION。

Binder.java#onTransact

frameworks/base/core/java/android/os/Binder.java

 782     protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
783 int flags) throws RemoteException {
804 } else if (code == SHELL_COMMAND_TRANSACTION) {
805 ParcelFileDescriptor in = data.readFileDescriptor();
806 ParcelFileDescriptor out = data.readFileDescriptor();
807 ParcelFileDescriptor err = data.readFileDescriptor();
808 String[] args = data.readStringArray();
812 if (out != null) {
813 shellCommand(in != null ? in.getFileDescriptor() : null,
814 out.getFileDescriptor(),
815 err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
816 args, shellCallback, resultReceiver);
------------------------------------------------------------
925 public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
926 @Nullable FileDescriptor err,
927 @NonNull String[] args, @Nullable ShellCallback callback,
928 @NonNull ResultReceiver resultReceiver) throws RemoteException {
929 onShellCommand(in, out, err, args, callback, resultReceiver);

929行的实现在AMS里

ActivityManagerService.java#onShellCommand

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

10501     @Override
10502 public void onShellCommand(FileDescriptor in, FileDescriptor out,
10503 FileDescriptor err, String[] args, ShellCallback callback,
10504 ResultReceiver resultReceiver) {
10505 (new ActivityManagerShellCommand(this, false)).exec(
10506 this, in, out, err, args, callback, resultReceiver);
10507 }

继续跟10505

public abstract class ShellCommand extends BasicShellCommandHandler {
final class ActivityManagerShellCommand extends ShellCommand {

看一下继承关系,这里需要注意的是,10505的exec是调用到父类的父类,然后又返回返回到ActivityManagerShellCommand的onCommand

ActivityManagerShellCommand#onCommand

frameworks/base/services/core/java/com/android/server/am/ActivityManagerShellCommand

 176     @Override
177 public int onCommand(String cmd) {
183 switch (cmd) {
184 case "start":
185 case "start-activity":
186 return runStartActivity(pw);
......
203 case "trace-ipc":
204 return runTraceIpc(pw);
......

总结

总体流程比较简单,需要关注的点有

  • am和cmd的binder客户端实现,也就是怎么写一个binder客户端(java、native)。

  • binder的流转,对端在哪

  • 最后是shellcommand的命令分发。

以此做参考,可以添加一些自己的命令与实现,做一些调试小工具。

debug:am、cmd命令源码分析的更多相关文章

  1. debug:am trace-ipc源码分析

    debug:am trace-ipc源码分析 目录 debug:am trace-ipc源码分析 一.使用 官网介绍 命令提示 小结 二.源码分析 ActivityManagerShellComman ...

  2. memcached学习笔记——存储命令源码分析下篇

    上一篇回顾:<memcached学习笔记——存储命令源码分析上篇>通过分析memcached的存储命令源码的过程,了解了memcached如何解析文本命令和mencached的内存管理机制 ...

  3. memcached学习笔记——存储命令源码分析上篇

    原创文章,转载请标明,谢谢. 上一篇分析过memcached的连接模型,了解memcached是如何高效处理客户端连接,这一篇分析memcached源码中的process_update_command ...

  4. TiDB show processlist命令源码分析

    背景 因为丰巢自去年年底开始在推送平台上尝试了TiDB,最近又要将承接丰巢所有交易的支付平台切到TiDB上.我本人一直没有抽出时间对TiDB的源码进行学习,最近准备开始一系列的学习和分享.由于我本人没 ...

  5. golang初探与命令源码分析

    前段时间有群友在群里问一个go语言的问题: 就是有一个main.go的main函数里调用了另一个demo.go里的hello()函数.其中main.go和hello.go同属于main包.但是在mai ...

  6. storm shell命令源码分析-shell_submission.clj

    当我们在shell里执行storm shell命令时会调用shell_submission.clj里的main函数.shell_submission.clj如下: shell_submission.c ...

  7. Django(三)runserver 命令源码分析

    应用环境 windows7 pycharm2018 profession python3.6 django2.0 我们在pycharm 启动django项目时,常常有这么一个命令操作: python ...

  8. PHP扩展编写、PHP扩展调试、VLD源码分析、基于嵌入式Embed SAPI实现opcode查看

    catalogue . 编译PHP源码 . 扩展结构.优缺点 . 使用PHP原生扩展框架wizard ext_skel编写扩展 . 编译安装VLD . Debug调试VLD . VLD源码分析 . 嵌 ...

  9. redis源码分析之事务Transaction(下)

    接着上一篇,这篇文章分析一下redis事务操作中multi,exec,discard三个核心命令. 原文地址:http://www.jianshu.com/p/e22615586595 看本篇文章前需 ...

随机推荐

  1. 《python网络数据采集》笔记2

    1.网页表单与登陆窗口 Requests 库擅长处理那些复杂的 HTTP 请求.cookie.header(响应头和请求头)等内容. 1)表单提交 import requests #字段 params ...

  2. ES6中的数组常用方法

    数组在JS中虽然没有函数地位那么高,但是也有着举足轻重的地位,下面我就结合这ES5中的一些常用的方法,与ES6中的一些方法做一些说明和实际用途.大家也可以关注我的微信公众号,蜗牛全栈. 一.ES5中数 ...

  3. PEP 324 subprocess 新的进程模块 -- Python官方文档译文 [原创]

    PEP 324 -- subprocess 新的进程模块(subprocess - New process module) 英文原文:https://www.python.org/dev/peps/p ...

  4. 使用fiddler工具模拟弱网环境

    1.使用CTRL+R快捷键调出设置窗口 2.CTRL+F搜索"if (m_SimulateModem)",如下图   3.设置 // 这里修改每KB上传时候的延迟速度,以ms为单位 ...

  5. 【NX二次开发】Block UI 对象颜色选择器

    属性说明 常规         类型 描述     BlockID     String 控件ID     Enable     Logical 是否可操作     Group     Logical ...

  6. 【NX二次开发】Block UI 截面构建器

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  7. TopN算法,流式数据获取前N条数据

    背景:由于业务需求,用户想要统计每周,每月,几个月,一年之中的前N条数据. 根据已有的思路无非就是对全部的数据进行排序,然后取出前N条数据,可是这样的话按照目前最优的排序算法复杂度也在O(nlog(n ...

  8. 29、vi和vim用法详解

    vi类似于windows中的文本文件,用于普通的文本文件 vim:专家版的文件编辑器,用于shell程序型文件,带颜色,自检查语法 一般模式快捷键 O:光标到一行的首 $:光标到一行的尾 H:光标到整 ...

  9. 50、django工程(ajax)

    50.1.ajax介绍: 1.ajax是在不跳转当前url地址的情况偷偷的往后台发送数据做增删改数据的操作,如果成功返回结果刷新当前页面,失败则提醒, 使用 id 或 name 属性. 2.模态对话框 ...

  10. ctf实验吧逻辑问题

    ctf5.shiyanbar.com/web/5/index.php 绕开. php题,习惯先看源码,F12,结果发现了 url输入了一看 告诉了我们后台逻辑.分析一下,发现只要使得$row[&quo ...