debug:am、cmd命令源码分析
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命令源码分析的更多相关文章
- debug:am trace-ipc源码分析
		debug:am trace-ipc源码分析 目录 debug:am trace-ipc源码分析 一.使用 官网介绍 命令提示 小结 二.源码分析 ActivityManagerShellComman ... 
- memcached学习笔记——存储命令源码分析下篇
		上一篇回顾:<memcached学习笔记——存储命令源码分析上篇>通过分析memcached的存储命令源码的过程,了解了memcached如何解析文本命令和mencached的内存管理机制 ... 
- memcached学习笔记——存储命令源码分析上篇
		原创文章,转载请标明,谢谢. 上一篇分析过memcached的连接模型,了解memcached是如何高效处理客户端连接,这一篇分析memcached源码中的process_update_command ... 
- TiDB show processlist命令源码分析
		背景 因为丰巢自去年年底开始在推送平台上尝试了TiDB,最近又要将承接丰巢所有交易的支付平台切到TiDB上.我本人一直没有抽出时间对TiDB的源码进行学习,最近准备开始一系列的学习和分享.由于我本人没 ... 
- golang初探与命令源码分析
		前段时间有群友在群里问一个go语言的问题: 就是有一个main.go的main函数里调用了另一个demo.go里的hello()函数.其中main.go和hello.go同属于main包.但是在mai ... 
- storm shell命令源码分析-shell_submission.clj
		当我们在shell里执行storm shell命令时会调用shell_submission.clj里的main函数.shell_submission.clj如下: shell_submission.c ... 
- Django(三)runserver 命令源码分析
		应用环境 windows7 pycharm2018 profession python3.6 django2.0 我们在pycharm 启动django项目时,常常有这么一个命令操作: python ... 
- PHP扩展编写、PHP扩展调试、VLD源码分析、基于嵌入式Embed SAPI实现opcode查看
		catalogue . 编译PHP源码 . 扩展结构.优缺点 . 使用PHP原生扩展框架wizard ext_skel编写扩展 . 编译安装VLD . Debug调试VLD . VLD源码分析 . 嵌 ... 
- redis源码分析之事务Transaction(下)
		接着上一篇,这篇文章分析一下redis事务操作中multi,exec,discard三个核心命令. 原文地址:http://www.jianshu.com/p/e22615586595 看本篇文章前需 ... 
随机推荐
- InnoDB 静态数据加密的常见问题合集
			1. 数据是否为有权查看数据的用户解密? 是的.InnoDB静态数据加密旨在透明地在数据库中应用加密,而不会影响现有应用程序.以加密格式返回数据会破坏大多数现有应用程序. InnoDB静态数据加密提供 ... 
- 【NX二次开发】 删除面操作
			录制修改封装删除面 DeleteFaces 1 #include <uf_defs.h> 2 #include <NXOpen/NXException.hxx> 3 #incl ... 
- 配置IPv6公网地址DDNS并开放外网访问端口
			目前使用三大运营商宽带服务都会下发公网IPv6地址,这样我们想要在外网访问家里的路由.NAS等设备就可以直接通过IPv6地址来访问了.但是每次重新拨号后IPv6地址都会改变,而且IPv6的地址很长,这 ... 
- MySQL 最佳实践 —— 高效插入数据
			当你需要在 MySQL 数据库中批量插入数百万条数据时,你就会意识到,逐条发送 INSERT 语句并不是一个可行的方法. MySQL 文档中有些值得一读的 INSERT 优化技巧. 在这篇文章里,我将 ... 
- canvas小画板——(3)笔锋效果
			画线准备 准备一个canvas <canvas id="canvasId" width="1000" height="800"> ... 
- Linux网络命令与脚本使用
			作为系统管理员,经常需要诊断和解决网络问题,而配置.监控与保护网络有助于发现问题并在事情范围扩大前得意解决,并且网络的性能与安全也是管理与诊断网络的重要部分.这里总结一下常用与Linux网络管理的命令 ... 
- Kubernetes在生产环境中的一些讨论
			pod是所有一切资源的中心,毫无疑问是Kubernetes中最重要的资源.毕竟, 每个应用都运行在pod中.为了确保知道如何开发能充分利用应用所在环境资源的应用,最后再从应用的角度来仔细看一下pod. ... 
- 2、linux防火墙的使用(firewalld)
			2.1.说明: 1.在 RHEL7 里有几种防火墙共存,firewalld.iptables,默认是使用 firewalld 来管理 netfilter 子系统,不过底层调用的命令仍然是 iptabl ... 
- 详细解释  使用FileReference类加载和保存本地文件
			一般而言,用户不希望web浏览器中运行的应用程序访问电脑硬盘里的文件.然而,随着基于浏览器(browser-based)的富因特网应用程序的增多,一些应用程序迫切需要访问用户所选择的文件,或者将文件保 ... 
- 13.3示例:抽象的Number类
			要点提示:Number类是数值包装类.BigInteger以及BigDecimal的抽象父类. 
