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 看本篇文章前需 ...
随机推荐
- mybatis学习——日志工厂
为什么要使用日志工厂? 我们想一下,我们在测试SQL的时候,要是能够在控制台输出 SQL 的话,是不是就能够有更快的排错效率?答案是肯定的,如果一个 数据库相关的操作出现了问题,我们就可以根据输出的S ...
- Unreal如何进行材质优化?
Hello,大家好,今天给大家带来实用的材质优化,我是木偶心没.优化在每个游戏项目里面都会涉及到,是一种为了达成相同目标,寻求并采用消耗更少资源的办法.一般会在CPU,GPU,网络和内存方便进行优化. ...
- mybatis-generator的使用心得
之前开发了一个亚健康测评系统,使用的是SSM框架,里面第一次使用到了mybatis-generator逆向代码生成工具,很方便,省去了基本的增删改查的mapper文件及sql的编写,还能避免错误,这里 ...
- 痞子衡嵌入式:超级下载算法RT-UFL v1.0发布,附J-Link下安装教程
痞子衡主导的"学术"项目 <RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计> 历时 8 个月终于迎来了 v1.0 版发布,因为是第一个正式版,为了保证质 ...
- Python分析44130条用户观影数据,挖掘用户与电影之间的隐藏信息!
01.前言 很多电影也上映,看电影前很多人都喜欢去 『豆瓣』 看影评,所以我爬取44130条 『豆瓣』 的用户观影数据,分析用户之间的关系,电影之间的联系,以及用户和电影之间的隐藏关系. 02.爬取观 ...
- Redis配置统计字典
本章将对Redis的系统状态信息(info命令结果)和Redis的所有配置(包括Standalone.Sentinel.Cluster三种模式)做一个全面的梳理,希望本章能够成为Redis配置统计字典 ...
- 服务器通信REST、gRPC,Swagger/OpenAPI,Consul
服务间的通信方式是在采用微服务架构时需要做出一个最基本的决策.默认的选项是通过 HTTP 发送 JSON,也就是所谓的 REST API.我们也是从 REST 开始的,但最近我们决定改用 gRPC. ...
- 『无为则无心』Python序列 — 18、Python列表概念及常用操作API
目录 1.列表的概念 (1)列表的定义 (2)列表的应用场景 (3)列表的定义格式 2.列表的常用操作 (1)列表的查找 1)通过下标查找 2)通过方法查找 3)判断是否存在 (2)列表的增加 @1. ...
- AvtiveMQ与SpringBoot结合
首先来了解下ActivieMQ的应用场景,消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题.实现高性能,高可用,可伸缩和最终一致性架构是大型分布式系统不可缺少的中间件 ...
- 【spring源码系列】之【Bean的属性赋值】
每次进入源码的世界,就像完成一场奇妙的旅行! 1. 属性赋值概述 上一篇讲述了bean实例化中的创建实例过程,实例化后就需要对类中的属性进行依赖注入操作,本篇将重点分析属性赋值相关流程.其中属性赋值, ...