Framework 源码解析知识梳理(1) - 应用程序与 AMS 的通信实现

一、前言

我们在许多和Framework解析相关的文章中,都会看到ActivityManagerService这个类,但是在上层的应用开发中,却很少直接会使用到他。

那么我们为什么要学习它的呢,一个最直接的好处就是它是我们理解应用程序启动过程的基础,只有把和ActivityManagerService以及和它相关的类的关系都理解透了,我们才能理清应用程序启动的过程。

今天这篇文章,我们就来对ActivityManagerService与应用进程之间的通信方式做一个简单的总结,这里我们根据进程之间的通信方向,分为两个部分来讨论:

  • 从应用程序进程到管理者进程

    (a) IActivityManager
    (b) ActivityManagerNative
    (c) ActivityManagerProxy
    (d) ActivityManagerService

  • 从管理者进程到应用程序进程

    (a) IApplicationThread
    (b) ApplicationThreadNative
    (c) ApplicationThreadProxy
    (d) ApplicationThread

二、从应用程序进程到管理者进程

在这一方向上的通信,应用程序进程作为客户端,而管理者进程则作为服务端。举一个最简单的例子,当我们启动一个Activity,就需要通知全局的管理者,让它去负责启动,这个全局的管理者就运行在另外一个进程,这里就涉及到了从应用程序进程到管理者进程的通信。

这一个方向上通信过程所涉及到的类包括:


2.1 应用程序进程向管理者进程发送消息

当我们想要启动一个Activity,会首先调用到Activity的:

    @Override
    public void startActivityForResult(
            String who, Intent intent, int requestCode, @Nullable Bundle options) {
        //...
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, who,
                intent, requestCode, options);
        //...
    }

之后调用到Instrumentation的:

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
            //....
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            //...
    }

这里我们看到了上面UML图中ActivityManagerNative,它的getDefault()方法返回的是一个IActivityManager的实现类:

    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            //1.得到一个代理对象
            IBinder b = ServiceManager.getService("activity");
            //2.将这个代理对象再经过一层封装
            IActivityManager am = asInterface(b);
            return am;
        }
    };

    static public IActivityManager getDefault() {
        return gDefault.get();
    }

这里,对于gDefault变量有两点说明:

  • 这是一个static类型的变量,因此在程序中的任何地方调用getDefault()方法访问的是内存中的同一个对象
  • 这里采用了Singleton模式,也就是懒汉模式的单例,只有第一次调用get()方法时,才会通过create()方法来创建一个对象

create()做了两件事:

  • 通过ServieManager得到IBinder,这个IBinder是管理进程在应用程序进程的代理对象,通过IBindertransact方法,我们就可以向管理进程发送消息:
public boolean transact(int code, Parcel data, Parcel reply, int flags)
  • IBinder传入asInterface(IBinder b)构建一个IActivityManager的实现类,可以看到,这里返回的是一个ActivityManagerProxy对象:
    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        //这一步先忽略....
        IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        return new ActivityManagerProxy(obj);
    }

下面,我们在来看一下这个ActivityManagerProxy,它实现了IActivityManager接口,我们可以看到它所实现的IActivityManager接口方法都是通过构造这个对象时所传入的IBinder.transact(xxxx)来调用的,这些方法之间的区别就在于消息的类型以及参数。

class ActivityManagerProxy implements IActivityManager {

    public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
    }

    public IBinder asBinder() {
        return mRemote;
    }

    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        //这个也很重要,我们之后分析..
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        //发送消息到管理者进程...
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }
 }

经过上面的分析,我们用一句话总结:

应用程序进程通过ActivityManagerProxy内部的IBinder.transact(...)向管理者进程发送消息,这个IBinder是管理者进程在应用程序进程的一个代理对象,它是通过ServieManager获得的。

2.2 管理者进程处理消息

下面,我们看一下管理者进程对于消息的处理,在管理者进程中,最终是通过ActivityManagerService对各个应用程序进行管理的。

它继承了ActivityManagerNative类,并重写了Binder类的onTransact(...)方法,我们前面通过ActivityManagerProxyIBinder对象发送的消息最终会调用到管理者进程中的这个函数当中,ActivityManagerNative对该方法进行了重写:

  @Override
  public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    switch (code) {
        case START_ACTIVITY_TRANSACTION:
            data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
            IApplicationThread app = ApplicationThreadNative.asInterface(b);
            String callingPackage = data.readString();
            Intent intent = Intent.CREATOR.createFromParcel(data);
            String resolvedType = data.readString();
            IBinder resultTo = data.readStrongBinder();
            String resultWho = data.readString();
            int requestCode = data.readInt();
            int startFlags = data.readInt();
            ProfilerInfo profilerInfo = data.readInt() != 0
                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
            Bundle options = data.readInt() != 0
                    ? Bundle.CREATOR.createFromParcel(data) : null;
            //这里在管理者进程进行处理操作....
            int result = startActivity(app, callingPackage, intent, resolvedType,
                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
            reply.writeNoException();
            reply.writeInt(result);
            return true;
      //...
  }

onTransact(xxx)方法中,会根据收到的消息类型,调用IActivityManager接口中所定义的不同接口,而ActivityManagerNative是没有实现这些接口的,真正的处理在ActivityManagerService中,ActivityManagerService开始进行一系列复杂的操作,这里之后我们介绍应用程序启动过程的时候再详细分析。

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

同样的,我们也用一句话总结:

管理者进程通过onTransact(xxxx)处理应用程序发送过来的消息

三、从管理者进程到应用程序进程

接着,我们考虑另一个方向上的通信方式,从管理者进程到应用程序进程,这一方向上的通信过程涉及到下面的类:


可以看到,ApplicationThread的整个框架和上面很类似,只不过在这一个方向上,管理者进程作为客户端,而应用程序进行则作为服务端。

3.1 管理者进程向应用程序进程发送消息

前面我们分析的时候,应用程序进程向管理者进程发送消息的时候,是通过IBinder这个管理者进程在应用程序进程中的代理对象来实现的,而这个IBinder则是通过ServiceManager获取的:

IBinder b = ServiceManager.getService("activity");

同理,如果管理者进程希望向应用程序进程发送消息,那么它也必须设法得到一个应用程序进程在它这边的代理对象。

我们回忆一下,在第二节的分析中,应用者进程向管理者进程发送消息的同时,通过writeStringBinder,放入了下面这个对象:

public int startActivity(IApplicationThread caller, ...) {
    //...
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    //...
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
}

这个caller是在最开始调用startActivityForResult时传入的:

    ActivityThread mMainThread;

    @Override
    public void startActivityForResult(
            String who, Intent intent, int requestCode, @Nullable Bundle options) {
        //...
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, who,
                intent, requestCode, options);
        //...
    }

通过查看ActivityThread的代码,我们可以看到它其实是一个定义在ApplicationThread中的ApplicationThread对象,它的asBinder实现是在ApplicationThreadNative当中:

   public IBinder asBinder() {
       return this;
   }

在管理者进程接收消息的时候,就可以通过readStrongBinder获得这个ApplicationThread对象在管理者进程的代理对象IBinder

  @Override
  public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
      switch (code) {
        case START_ACTIVITY_TRANSACTION:
            //取出传入的ApplicationThread对象,之后调用asInterface方法..
            IBinder b = data.readStrongBinder();
            IApplicationThread app = ApplicationThreadNative.asInterface(b);
            //...
            int result = startActivity(app, callingPackage, intent, resolvedType,
                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
            return true;
     }
  }

接着,它再通过asInterface(IBinder xx)方法把传入的代理对象通过ApplicationThreadProxy进行了一层封装:

    static public IApplicationThread asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IApplicationThread in = (IApplicationThread) obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        return new ApplicationThreadProxy(obj);
    }

之后,管理者进程就可以通过这个代理对象的transact(xxxx)方法向应用程序进程发送消息了:

class ApplicationThreadProxy implements IApplicationThread {

    private final IBinder mRemote;

    public ApplicationThreadProxy(IBinder remote) {
        mRemote = remote;
    }

    public final IBinder asBinder() {
        return mRemote;
    }

    public final void schedulePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {
        //....
        mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
        //...
    }

这一个过程可以总结为:

管理者进程通过ApplicationThreadProxy内部的IBinder向应用程序进程发送消息,这个IBinder是应用程序进程在管理者进程的代理对象,它是在管理者进程接收应用程序进程发送过来的消息中获得的。

3.2 用户进程接收消息

在用户程序进程中,ApplicationThreadonTransact(....)就可以收到管理者进程发送的消息,之后再调用ApplicationThread所实现的IApplicationThread的接口方法进行消息的处理:

  @Override
  public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
        case SCHEDULE_PAUSE_ACTIVITY_TRANSACTION: 
            data.enforceInterface(IApplicationThread.descriptor);
            IBinder b = data.readStrongBinder();
            boolean finished = data.readInt() != 0;
            boolean userLeaving = data.readInt() != 0;
            int configChanges = data.readInt();
            boolean dontReport = data.readInt() != 0;
            schedulePauseActivity(b, finished, userLeaving, configChanges, dontReport);
            return true;
  }

三、小结

以上就是应用程序进程和管理者进程之间的通信方式,究其根本,都是通过获取对方进程的代理对象的transact(xxxx)方法发送消息,而对方进程则在onTransact(xxxx)方法中进行消息的处理,从而实现了进程之间的通信。


更多文章,欢迎访问我的 Android 知识梳理系列:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容