adb shell源码浅析

adb常用命令一文中有提到adb shell的指令在/system/bin路径下,现在本文以am指令为例,解析一条指令的执行流程

以 adb shell am broadcast -a zhihe.factorytest.action.PASS -f 0x1000000 为例

在android11中用adb发送广播不加后面的 -f 0x1000000,应用中接受不到广播,也顺便追溯一下 -f  0x1000000带表的什么意思

1.am的源码路径

 如图所示在frameworks/base/cmds/路径下看到了很多平时常用的命令程序am,pm等指令

2.源码流程

程序主入口为Am的main函数

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

public class Am extends BaseCommand {

    private IActivityManager mAm;
    private IPackageManager mPm;

    /**
     * Command-line entry point.
     *
     * @param args The command-line arguments
     */
    public static void main(String[] args) {
        (new Am()).run(args);
    }
    ...
}    

Am继承了BaseCommand,在Am中没有run这个方法,看看他的父类BaseCommand的run方法做了什么

./frameworks/base/core/java/com/android/internal/os/BaseCommand.java

public abstract class BaseCommand {

	...
    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);
        }
    }
    ...
}  

在BaseCommand的run方法中,判断了如果参数长度小于1,就会调onShowUsage方法(什么样的情况是参数小于1呢,例如adb shell am broadcast -a zhihe.factorytest.action.PASS -f 0x1000000中am是指令后面跟着的broadcast -a zhihe.factorytest.action.PASS -f 0x1000000才是参数,如果输入adb shell am就是参数长度小于1)。把参数存在mRawArgs中,和调onRun方法

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

public class Am extends BaseCommand {

	...
    @Override
    public void onShowUsage(PrintStream out) {
        try {
            runAmCmd(new String[] { "help" });//------>发送help指令
        } catch (AndroidException e) {
            e.printStackTrace(System.err);
        }
    }

    @Override
    public void onRun() throws Exception {

        mAm = ActivityManager.getService();//------>初始化mAm
        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());//------>发送全参数指令
        }
    }
    ...
    
    void runAmCmd(String[] args) throws AndroidException {
        final MyShellCallback cb = new MyShellCallback();
        try {
            mAm.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
                    args, cb, new ResultReceiver(null) { });
        } catch (RemoteException e) {
            System.err.println(NO_SYSTEM_ERROR_CODE);
            throw new AndroidException("Can't call activity manager; is the system running?");
        } finally {
            cb.mActive = false;
        }
    }
    ...
}    

Am重载onShowUsage方法,就是发了一个help的指令,在重载onRun中发了一个全参数的指令,可以看到发送指令的是mAm.asBinder().shellCommand这样去发送的,其实这里mAm.asBinder()可以猜测到这个就是 ActivityManagerService,如何通过代码mAm.asBinder()就是ActivityManagerService呢?在onRun中mAm = ActivityManager.getService();

./frameworks/base/core/java/android/app/ActivityManager.java

public class ActivityManager {

	...
    /**
     * @hide
     */
    @UnsupportedAppUsage
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static IActivityTaskManager getTaskService() {
        return ActivityTaskManager.getService();
    }

    @UnsupportedAppUsage
    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
    ...
}  

am就是被保存到ServiceManager的名字为Context.ACTIVITY_SERVICE的一个服务,但是在ActivityManagerService中没有找到shellCommand这个方法,只能找它的父类Binder了

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

    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);
    }

调了onShellCommand,这个方法ActivityManagerService有重载

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

public class ActivityManagerService extends IActivityManager.Stub

	...
    public void setSystemProcess() {
        try {
            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
            ...        
        }
        ...
    }
	...
    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out,
            FileDescriptor err, String[] args, ShellCallback callback,
            ResultReceiver resultReceiver) {
        (new ActivityManagerShellCommand(this, false)).exec(
                this, in, out, err, args, callback, resultReceiver);
    }
    ...
}   

在setSystemProcess方法中可以看到在初始化的过程中确实是把ActivityManagerService以Context.ACTIVITY_SERVICE的名字保存到ServiceManager中去了,onShellCommand中又把具体的事情交给ActivityManagerShellCommand去做了,但是ActivityManagerShellCommand没有重载exec,他的父类ShellCommand的exec又调了父类BasicShellCommandHandler的exec,BasicShellCommandHandler的exec中调了onCommand,而ActivityManagerShellCommand重载了此方法

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

final class ActivityManagerShellCommand extends ShellCommand {

	...
	    @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 "stopservice":
                case "stop-service":
                    return runStopService(pw);
                case "broadcast"://---------------------->正式我们追踪的参数
                    return runSendBroadcast(pw);
                default:
                    return handleDefaultCommands(cmd);
            }
        } catch (RemoteException e) {
            pw.println("Remote exception: " + e);
        }
        return -1;
    }
    ...
    int runSendBroadcast(PrintWriter pw) throws RemoteException {
        Intent intent;
        try {
            intent = makeIntent(UserHandle.USER_CURRENT);//---------------------->看看intent包含了什么
        } catch (URISyntaxException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        intent.addFlags(Intent.FLAG_RECEIVER_FROM_SHELL);
        IntentReceiver receiver = new IntentReceiver(pw);
        String[] requiredPermissions = mReceiverPermission == null ? null
                : new String[] {mReceiverPermission};
        pw.println("Broadcasting: " + intent);
        pw.flush();
        Bundle bundle = mBroadcastOptions == null ? null : mBroadcastOptions.toBundle();
        mInterface.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null,
                requiredPermissions, android.app.AppOpsManager.OP_NONE, bundle, true, false,
                mUserId);//--------------->发送广播
        receiver.waitForFinish();
        return 0;
    }
    
    private Intent makeIntent(int defUser) throws URISyntaxException {
        mStartFlags = 0;
        mWaitOption = false;
        mStopOption = false;
        mRepeat = 0;
        mProfileFile = null;
        mSamplingInterval = 0;
        mAutoStop = false;
        mStreaming = false;
        mUserId = defUser;
        mDisplayId = INVALID_DISPLAY;
        mWindowingMode = WINDOWING_MODE_UNDEFINED;
        mActivityType = ACTIVITY_TYPE_UNDEFINED;
        mTaskId = INVALID_TASK_ID;
        mIsTaskOverlay = false;
        mIsLockTask = false;
        mBroadcastOptions = null;

        return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
            @Override
            public boolean handleOption(String opt, ShellCommand cmd) {
				...
            }
        });
    }
}  

 在onCommand中可以看到我们的参数如果是broadcast,就会调runSendBroadcast,在runSendBroadcast中会把广播发送出去,这就完成了adb发送广播的流程,前面提到的-f是什么呢,在runSendBroadcast中有一个makeIntent,在makeIntent中又会进一步的解析参数,Intent.parseCommandArgs

./frameworks/base/core/java/android/content/Intent.java

public class Intent implements Parcelable, Cloneable {

	...
    /** @hide */
    @UnsupportedAppUsage
    public static Intent parseCommandArgs(ShellCommand cmd, CommandOptionHandler optionHandler)
            throws URISyntaxException {
        Intent intent = new Intent();
        Intent baseIntent = intent;
        boolean hasIntentInfo = false;

        Uri data = null;
        String type = null;

        String opt;
        while ((opt=cmd.getNextOption()) != null) {
            switch (opt) {
				...
                case "-f":
                    String str = cmd.getNextArgRequired();
                    intent.setFlags(Integer.decode(str).intValue());
                    break;
                ...    
    }
}    

 在parseCommandArgs中可以看到-f代表的的是flags,在Intent中0x1000000的定义为如下

    /**
     * If set, the broadcast will always go to manifest receivers in background (cached
     * or not running) apps, regardless of whether that would be done by default.  By
     * default they will only receive broadcasts if the broadcast has specified an
     * explicit component or package name.
     *
     * NOTE: dumpstate uses this flag numerically, so when its value is changed
     * the broadcast code there must also be changed to match.
     *
     * @hide
     */
    public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值