突然悟出在源码中分析Binder的玩法

首先我们可以去这样理解:(综合ActivityManagerService和ApplicationThread分析)
凡是在源码中和binder有关的最底层的抽象类都会去extends Binder并且实现Ixxxxxxx接口
就比如我们可以看到ActivityManagerService继承的ActivityManagerNative就是最底层的抽象类。
我们可以看到

 public abstract class ActivityManagerNative extends Binder implements IActivityManager

再比如ApplicationThread(注意这个类是在ActivityThread中定义的一个内部类)继承的ApplicationThreadNative也是最底层的抽象类,我们可以看到

public abstract class ApplicationThreadNative extends Binder implements IApplicationThread

OK,那么问题来了,还有的Service呢?跟AMS齐名的PMS呢,怎么不拿出来分析一下呢,来我们去看看PMS是怎么玩的?

public class PackageManagerService extends IPackageManager.Stub 

也就是说IPackageManager.Stub应该是PMS的最底层的抽象类,于是乎我们就去苦苦追寻这个IPackageManager.Stub东西了,结果你会发现你完!!全!!找!!不!!到!!
不要慌,让老夫领你去看个究竟。

源码的编译

实际上,如果源码里面翻多了,你会发现不单单是这个东西,很多东西都是没有的,飘红的。实际上android sdk manager帮我们下载的相应的api版本下的source文件都不是android的系统源码,只能满足你初步的查看,如果你真的想要去把源码看个究竟,单单通过sdk目录下的source是不够的,你需要做的是编译源码http://www.jianshu.com/writer#/notebooks/6954184/notes/8031957

改变源码的阅读方式

我们现在再次去看看能不能找得到IPackageManager,结果一搜就搜到了

public interface IPackageManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements android.content.pm.IPackageManager {

        .....
    }
    ...
}

我们看到这个Stub内部类也是extends 了Binder并且实现了IPackageManager
包括之前同样看不到的WindowManagerService继承的IWindowManager(就是我们常说的WMS)也是一模一样的。

为什么一开始找不到

为什么AMS可以找得到,是因为AMS的Binder相关都是直接定义在源码中的,区别于其他服务的定义,我们可以很清楚的看到AMS继承的ActivityManagerNative是直接定义在源码中的,而这个AMN就相当于后面出现的Stub,后面出现的IPackageManger或者是IWindowManager都是通过aidl的方式去生成的,都是我们通过编译源码的方式生成的,此处如果对aidl不了解可以去了学习一下aidl的知识。

Binder的结构(此处分别以AMS和PMS进行分析)

  1. AMS


    AMS的简易关系

    最最根部的是接口IActivityManager,这个接口定义了AMS所有需要用到的服务的方法,并且需要继承IInterface,我们可以把他理解为一个叫I的接口,因为所有的binder的东西都是跟这个前缀叫I的东西有关的,这个IInterface定义了一个asBinder的方法,可以把所有继承这个IInterface的类统统转化成IBinder。

/**
 * Base class for Binder interfaces.  When defining a new interface,
 * you must derive it from IInterface.
 */
public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.
     */
    public IBinder asBinder();
}

OK,我们继续往上一层看
ActivityManagerNative继承了Binder而Binder实现了IBinder这个接口,我们暂且不去分析这两个类事干什么用的,只需要知道跟binder机制有关系。
那么既然AMN最终实现了IBinder这个接口,又继承了IActivityManger这个类,那么上面所说的adBinder这个方法直接返回其本身就可以了,果不其然。

public IBinder asBinder() {
        return this;
    }

但是当我们在这个类中搜索asBinder这个方法的时候我们却发现实现的不止一处,还有一处也实现了这个方法,

public IBinder asBinder()
    {
        return mRemote;
    }

结果看到还有个代理类ActivityManagerProxy,于是乎就很好奇的去ctrl+G了。发现来自与ActivityManagerNative的方法asInterface:

/**
     * Cast a Binder object into an activity manager interface, generating
     * a proxy if needed.
     */
    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);
    }

我们看到注释已经写的相当明白了,把一个Binder对象转换成Activity Manager接口,如果有必要的话搞一个Activity Manager的代理出来。我们把其中的两个方法逐个击破,首先是obj.queryLocalInterface,这个是IBinder的方法:

/**
     * Attempt to retrieve a local implementation of an interface
     * for this Binder object.  If null is returned, you will need
     * to instantiate a proxy class to marshall calls through
     * the transact() method.
     */
    public IInterface queryLocalInterface(String descriptor);

其实就是要去获得这个binder接口的本地实现,上面也说了,如果获取不到,需要通过搞一个代理出来,直接看这个接口方法还是比较难理解这玩意儿到底是干嘛的,那我们就去找一找什么地方使用到了这个asInterface方法,全局一下(此处真的体会到导入源码的重要性),发现有三处调用,我们只看重要的一处:

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

这个是用的非常平凡的方法,ActivityManagerNative的gDefault变量,实际上就是维护这一个IActivityManager的单例,我们看到这个IBinder b是来自于ServiceManager的serviceMap(这个之前看过一点binder的服务注册的应该都会知道),但是我之前一直不知道到底是什么时候把activityManagerservice这个东西注册进去的,现在有了源码了,找了一下,果然就找到了,在ActivityManagerService中有这么一个方法,里面把AMS自生注册到了ServiceManager中:

public void setSystemProcess() {
        try {
            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
            ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
            ServiceManager.addService("meminfo", new MemBinder(this));
            ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
            ServiceManager.addService("dbinfo", new DbBinder(this));
            if (MONITOR_CPU_USAGE) {
                ServiceManager.addService("cpuinfo", new CpuBinder(this));
            }
            ServiceManager.addService("permission", new PermissionController(this));
            ServiceManager.addService("processinfo", new ProcessInfoService(this));
            ....
        }
        ....
    }
    ....
}

我们看到传的是this,这个时候我们终于要去点开那个神器的queryLocalInterface方法了,看看它是怎么实现的:

/**
     * Use information supplied to attachInterface() to return the
     * associated IInterface if it matches the requested
     * descriptor.
     */
    public IInterface queryLocalInterface(String descriptor) {
        if (mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }

很明显,做了一个字符串匹配,如果相同就把mOwner返回出去,我们在Binder.java中找到了这两个变量的定义:

public void attachInterface(IInterface owner, String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }

然后我们又在ActivityManagerNative中找到了这个方法的调用:

public ActivityManagerNative() {
        attachInterface(this, descriptor);
    }
    String descriptor = "android.app.IActivityManager";

水落石出了吧,捋一捋逻辑之后我们发现,实际上最初的那个queryLocalInterface方法,实际上就是去对穿进来的binder最一个教研,看这个binder是不是AMS,如果是AMS那么就去把它转换成IActivityManager,如果不是那么就搞一个ActivityManagerProxy代理出来。其实这里面就涉及到一个问题,大家会不会觉得这个queryLocalInterface方法永远都是有效的呢,其实不然,这里就要涉及到跨进程的东西了,在单进程中去理解事没有问题的,但是跨进程的时候就会有问题了,这里其实我们可以从ActivityManagerProxy的构造函数能够看的出来:

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

这个传进来的remote就是另外一个进程的binder,那么我们如何去理解呢?
queryLocalInterface这个方法实际上真正的用途是去判断一下,这个binder是否是在当前的进程,如果不在,那么就去搞一个代理,如果在当前进程,就直接把它转成IActivityManager进行使用(因为服务真正的方法都定义在了IActivityManager这个接口里面,那么转成接口就可以直接去使用它的方法了)。

抛开底层Binder不谈的整个framework层的IPC交互流程

我们在这里停一下,先来看一下整个涉及到binder的类的结构(以AMS和PMS这两个典型为例)

  1. AMS


    AMS结构

    我们可以看到系统基本在使用AMS的时候直接使用的是ActivityManagerNative.getDefault()去做调用,就跟标注的一样,如果AMS服务就在当前的进程中那么直接调用ActivityManagerService中的相应方法。如果不在一个进程中,那么就调用Proxy的方法,就要涉及到使用IPC通信了,我们可以看到Proxy的方法都会涉及到mRemote.transact方法,然后在远程进程的继承ActivityManagerNative的AMS会首先触发onTransact方法,并在onTransact中去调用相应的请求方法。
    我们以AMS的startActivity方法为例:
    (1) 如果在一个进程中,那么直接就去调用AMS的startActivity方法:

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

(2) 如果不在一个进程中,那么就先去调用ActivityManagerProxy的startActivity方法:

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.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

然后在另外一个进程中的ActivityMangerService接收到了transact请求,触发了onTransact方法(这个方法定义在了基类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方法中再去调用AMS中的startActivity方法。
基本frameWork级别的都是直接调用的ActivityManagerNative.getDefault()去处理的,而我们平时需要使用到AMS的服务的时候都是直接去使用ActivityManager的相应方法的(当然只会局限于部分方法,因为AMS里的大部分方法我们是用不到的),比如getDeviceConfigurationInfo方法:

/**
     * Get the device configuration attributes.
     */
    public ConfigurationInfo getDeviceConfigurationInfo() {
        try {
            return ActivityManagerNative.getDefault().getDeviceConfigurationInfo();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

很明显了,我们所使用到的ActivityManager实际上就是对ActivityManagerNative的一个封装,把常用的方法放出来给用户使用。

  1. PMS


    PMS结构

    与AMS有几点不同:
    (1)没有了类似于ActivityManagerNative这样的类,凡是使用aidl文件生成的Binder文件都是这样的结构,在IPackageManager中定义了内部类Stub和Proxy,分别对应ActivityMangaerNative和ActivityManagerNative.ActivityManagerProxy.
    (2) PackageMange是一个抽象类,具体的实现在ApplicationPackageManager中,而我们平时直接去使用PackageManger都是直接在Activity中调用getPackageManager:

@Override
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }

        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }

我们可以看到IPackageManger来自与 ActivityThread.getPackageManager():

public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        sPackageManager = IPackageManager.Stub.asInterface(b);
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }

而返回的PackageManger是new ApplicationPackageManager(this, pm)

ApplicationPackageManager(ContextImpl context,
                              IPackageManager pm) {
        mContext = context;
        mPM = pm;
    }

然后我们平时使用PackageManager的方法实际上都是类似于如下的调用:

@Override
    public ActivityInfo getActivityInfo(ComponentName className, int flags)
            throws NameNotFoundException {
        try {
            ActivityInfo ai = mPM.getActivityInfo(className, flags, mContext.getUserId());
            if (ai != null) {
                return ai;
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        throw new NameNotFoundException(className.toString());
    }

至此FrameWork层的Binder基本吃透,TBC。。。

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

推荐阅读更多精彩内容