Android点将台:金科玉律[-AIDL-]

零、前言

本文接Android点将台:绝命暗杀官[-Service-]篇,本文图例见
本文通过AIDL实现了跨进程间调用Service(即App2调用App1的Service)
本篇将来探索一下AIDL自动生成的类,再重新审视一下ActivityManagerService


一、上一篇中AIDL自动生成的IMusicPlayerService分析
1.IMusicPlayerService的类结构

太多了,有点晃眼,打开结构图来分析一下



2.从IInterface开始

IMusicPlayerService是一个接口,并且继承于IInterface接口,那IInterface是何许人也?
就这两行代码,只有一个asBinder方法,返回一个IBinder对象,注意它在的包是android.os

package android.os;
public interface IInterface{
    public IBinder asBinder();
}
复制代码

3.IMusicPlayerService的分析

可见除去Stub,IMusicPlayerService里只是我们在IMusicPlayerService.aidl定义的接口
也没有什么太多要说明的地方,我们的终极目标是看一下它的实现类是什么

/*
 * This file is auto-generated.  DO NOT MODIFY.
    自动生成的,不要修改
 * Original file: J:\\Java\\Android\\LeverUp\\TolyService\\app\\src\\main\\aidl\\com\\toly1994\\tolyservice\\IMusicPlayerService.aidl
 原始文件在: J:\\Java\\Android\\LeverUp\\TolyService\\app\\src\\main\\aidl\\com\\toly1994\\tolyservice\\IMusicPlayerService.aidl
 */
package com.toly1994.tolyservice;
// Declare any non-default types here with import statements
//在这里使用import语句声明任何非默认类型

public interface IMusicPlayerService extends android.os.IInterface {
    //Stub类,暂略...
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
      说明一些在AIDL中可以用作参数和返回值的基本类型。
     */
    public void stop() throws android.os.RemoteException;
    public void pause() throws android.os.RemoteException;
    public void start() throws android.os.RemoteException;
    public void prev() throws android.os.RemoteException;
    public void next() throws android.os.RemoteException;
    public void release() throws android.os.RemoteException;
    public boolean isPlaying() throws android.os.RemoteException;
    public void seek(int pre_100) throws android.os.RemoteException;
    public void create(java.util.List<java.lang.String> filePaths) throws android.os.RemoteException;
}
复制代码

4.然后当然是深入一下,到Stub

英语Stub有存根的意思,看完本篇之后自己意会一下它的含义
它不仅继承Binder,而且实现了IMusicPlayerService,看起来挺牛的,可惜是个抽象类
它实现了Binder的一些东西,但并没有IMusicPlayerService的任何方法,就是挂个头而已
实现从成员变量来看,每个方法都对应了一个int常量,从switch来看应该是方法的标识
DESCRIPTOR对应了一个包名.IMusicPlayerService字符串,用于attachInterface

public static abstract class Stub extends android.os.Binder implements com.toly1994.tolyservice.IMusicPlayerService {
     private static final java.lang.String DESCRIPTOR = "com.toly1994.tolyservice.IMusicPlayerService";

     /**
      * Construct the stub at attach it to the interface.
        在将关联到接口时构造stub。----注意使用了DESCRIPTOR字符串
      */
     public Stub() {
         this.attachInterface(this, DESCRIPTOR);
     }

     /**
      * Cast an IBinder object into an com.toly1994.tolyservice.IMusicPlayerService interface,
      * generating a proxy if needed.
      */
     public static com.toly1994.tolyservice.IMusicPlayerService asInterface(android.os.IBinder obj) {
         if ((obj == null)) {
             return null;
         }
         android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
         if (((iin != null) && (iin instanceof com.toly1994.tolyservice.IMusicPlayerService))) {
             return ((com.toly1994.tolyservice.IMusicPlayerService) iin);
         }
         return new com.toly1994.tolyservice.IMusicPlayerService.Stub.Proxy(obj);
     }

     @Override
     public android.os.IBinder asBinder() {
         return this;
     }

     @Override
     public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
         java.lang.String descriptor = DESCRIPTOR;
         switch (code) {
             case INTERFACE_TRANSACTION: {
                 reply.writeString(descriptor);
                 return true;
             }
             case TRANSACTION_stop: {//暂略...
                 return true;
             }
             case TRANSACTION_pause: {//暂略...
                 return true;
             }
             case TRANSACTION_start: {//暂略...
                 return true;
             }
             case TRANSACTION_prev: {//暂略...
                 return true;
             }
             case TRANSACTION_next: {//暂略...
                 return true;
             }
             case TRANSACTION_release: {//暂略...
                 return true;
             }
             case TRANSACTION_isPlaying: {//暂略...
                 return true;
             }
             case TRANSACTION_seek: {//暂略...
                 return true;
             }
             case TRANSACTION_create: {//暂略...
                 return true;
             }
             default: {
                 return super.onTransact(code, data, reply, flags);
             }
         }
     }
     
     //Proxy类,暂略...
     static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
     static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
     static final int TRANSACTION_start = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
     static final int TRANSACTION_prev = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
     static final int TRANSACTION_next = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
     static final int TRANSACTION_release = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
     static final int TRANSACTION_isPlaying = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
     static final int TRANSACTION_seek = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
     static final int TRANSACTION_create = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
 }
复制代码

5.现在看最后一层奶油夹心:Proxy

现在把聚光灯打到Stub的内部类Proxy上,Proxy是个敲代码的都知道是代理的意思
既然是代理,它代理什么?成员变量有个IBinder mRemote,构造方法要传一个IBinder,so...
它实现了IMusicPlayerService,并且有所动作,而且动作基本一致

 private static class Proxy implements com.toly1994.tolyservice.IMusicPlayerService {
    private android.os.IBinder mRemote;

    Proxy(android.os.IBinder remote) {
        mRemote = remote;
    }

    @Override
    public android.os.IBinder asBinder() {
        return mRemote;
    }

    public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    @Override
    public void stop() throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0);
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }

    @Override
    public void pause() throws android.os.RemoteException {//暂略...
    }

    @Override
    public void start() throws android.os.RemoteException {//暂略...
    }

    @Override
    public void prev() throws android.os.RemoteException {//暂略...
    }

    @Override
    public void next() throws android.os.RemoteException {//暂略...
    }

    @Override
    public void release() throws android.os.RemoteException {//暂略...
    }

    @Override
    public boolean isPlaying() throws android.os.RemoteException {//暂略...
    }

    @Override
    public void seek(int pre_100) throws android.os.RemoteException {//暂略...
    }

    @Override
    public void create(java.util.List<java.lang.String> filePaths) throws android.os.RemoteException {//暂略...
    }
}
复制代码

到现在为止,它们几个的关系理清了,下面就来详细看看哪些//暂略...的方法


二、Binder和IBinder的个别方法

这里先列举出上面使用到的方法


1.目前IBinder台面上出现的方法
public interface 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.
     尝试检索此绑定器对象的本地接口实现。
     如果返回null,则需要通过transact()方法实例化一个代理类来调用。
     */
    public @Nullable IInterface queryLocalInterface(@NonNull String descriptor);

    /**
     * Perform a generic operation with the object.
     * 使用对象执行一般操作。
     * @param code The action to perform.  This should be a number between {@link #FIRST_CALL_TRANSACTION} and {@link #LAST_CALL_TRANSACTION}.
    code 操作的行为码  0x00000001 ~ 0x00ffffff 之间 1~16777215
     * @param data Marshalled data to send to the target.  Must not be null.If you are not sending any data, you must create an empty Parcel that is given here.
    data 发送到目标的编组数据。不能为空。如果您没有发送任何数据,则必须创建这里给出的空包。
     * @param reply Marshalled data to be received from the target.  May be null if you are not interested in the return value.
     从目标接收到的编组数据。如果您对返回值不感兴趣,则可能为null。
     * @param flags Additional operation flags.  Either 0 for a normal RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
   flags  额外的操作标志,对于普通RPC为0,对于单向RPC为1{@link #FLAG_ONEWAY}。
    
     * @return Returns the result from {@link Binder#onTransact}.  A successful call generally returns true; false generally means the transaction code was not understood.
   return  从Binder.onTransact()返回结果。成功调用通常返回true;false通常表示事务代码未被理解。
     */
    public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
        throws RemoteException;
    //其他...略
}
复制代码

2.目前Binder台面上出现的方法
---->[Binder]-------------
private IInterface mOwner;
private String mDescriptor;

---->[Binder#attachInterface]-------------
 Convenience method for associating a specific interface with the Binder. 
 After calling, queryLocalInterface() will be implemented for you to return
 the given owner IInterface when the corresponding descriptor is requested.
|--译:一个将特定接口与Binder关联的方便方法。调用后,将为你实现queryLocalInterface(),
|--以便在请求相应的描述符时返回owner (IInterface对象)。
public void attachInterface(@Nullable IInterface owner, @Nullable Stringdescriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}

---->[Binder#queryLocalInterface]-------------
 Use information supplied to attachInterface() to return the associated 
 IInterface if it matches the requested descriptor.
 如果提供的描述符,与通过attachInterface()方法进行关联的IInterface一致
 返回该IInterface,否则返回null
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
    if (mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

---->[Binder#onTransact]-------------
 * Default implementation is a stub that returns false.  You will want
 * to override this to do the appropriate unmarshalling of transactions.
 * 默认实现是stub返回false。您会想要覆谢它,以便对事务进行适当的反编组。
 * <p>If you want to call this, call transact().
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel
reply,int flags) throws RemoteException {
复制代码

3.再来看刚才暂略的方法
3.1:attachInterface

此方法在Stub的构造函数中调用,为成员变量mOwnermDescriptor赋值

---->[IMusicPlayerService.Stub#Stub]-------------
public Stub() {
    this.attachInterface(this, DESCRIPTOR);
}
|---这里调用了attachInterface方法,参数是自己和描述符

---->[Binder]-------------
private IInterface mOwner;
private String mDescriptor;

---->[Binder#attachInterface]-------------
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}
复制代码

3.2:asInterface

传入一个IBinder对象obj,调用obj的queryLocalInterface方法生成IInterface对象
再进行强转,如果强转不成功,才会创建Proxy代理对象

---->[IMusicPlayerService.Stub#asInterface]-------------
public static com.toly1994.tolyservice.IMusicPlayerService asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.toly1994.tolyservice.IMusicPlayerService))) {
        return ((com.toly1994.tolyservice.IMusicPlayerService) iin);
    }
    return new com.toly1994.tolyservice.IMusicPlayerService.Stub.Proxy(obj);
}
复制代码

3.3: asBinder

asBinder是IInterface接口的方法,把自己(Stub继承自Binder)返回去,没什么好说的

---->[IMusicPlayerService.Stub#asInterface]-------------
@Override
public android.os.IBinder asBinder() {
    return this;
}
复制代码

3.4: onTransact

此方法运行在服务端Binder线程池中,客户端发起跨进程请求时,远程请求通过系统底层封装后交由此方法处理。
处理的逻辑基本上都一样,通过判断code来调用方法,这里看两个startseek,

@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel
reply, int flags) throws android.os.RemoteException {
    java.lang.String descriptor = DESCRIPTOR;
    switch (code) {
    //略...
        case TRANSACTION_start: {
            data.enforceInterface(descriptor);//执行接口
            this.start();//调用start方法
            reply.writeNoException();//将计算结果写入reply中
            return true;
        }
        case TRANSACTION_seek: {
            data.enforceInterface(descriptor);//执行接口
            int _arg0;
            _arg0 = data.readInt();//获取数据
            this.seek(_arg0);//调用seek方法
            reply.writeNoException();//将计算结果写入reply中
            return true;
        }
  //略...
复制代码

3.5:Proxy中的实现方法

Proxy是代理类,运行在客户端,也就是Stub#asInterface中iin
无法强转成IMusicPlayerService是返回Proxy类对象

---->[IMusicPlayerService.Stub.Proxy#start]--------
@Override
public void start() throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
         //向_data中写入参数
        _data.writeInterfaceToken(DESCRIPTOR);
        //通过transact方法向服务端传递参数,并写入_reply
        mRemote.transact(Stub.TRANSACTION_start, _data, _reply, 0);
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}

@Override
public void seek(int pre_100) throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        _data.writeInt(pre_100);
        mRemote.transact(Stub.TRANSACTION_seek, _data, _reply, 0);
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}
复制代码

4.现在再来看我们在Service中画的最后一张图

ServiceConnection的onServiceConnected方法会回调一个IBinder对象service
并通过IMusicPlayerService.Stub.asInterface方法将service变成IMusicPlayerService对象
还记得asInterface里做了什么吗?下面再看一遍,aidl在使用层面的逻辑是不是清晰了一些?

这里要强调一下:
图中:蓝色区域可在任意app中使用,相当于客户端:只要连接就行了   
其他区域是服务端的逻辑,为客户端提供业务逻辑处理 
复制代码

至于Binder在底层怎么跑的,那是后话,那根钻石级的硬骨头还是最后啃吧


5.小结一下:现在回头再看
1.在一个aidl的服务中,业务逻辑的处理是在哪的?
|--- 这还用问吗,当然在MusicPlayerStub里面,不然还能在哪?

2.IMusicPlayerService和Stub有什么用
|--- IMusicPlayerService是可调用的接口
|--- Stub在台面上有一个功劳,用asInterface将IBinder对象转化为IMusicPlayerService对象

3.Proxy有什么用?
|---Proxy唯一出现的是在asInterface方法中,在inn无法强转成IMusicPlayerService时使用Proxy  

4.什么时候inn无法转成IMusicPlayerService?(见下图)
|--- 我做了一个实验,就是分别看一下客户端和服务端绑定时回调的IBinder对象类型
再调用queryLocalInterface方法得到inn,看一下它的类型
服务端是:MusicPlayerStub ,它何许人也? Stub之子,Stub实现了IMusicPlayerService,强转ok  
客户端是:BinderProxy对象queryLocalInterface后为null,使用Proxy  
复制代码


三、ActivityManagerService初探
1.对于系统级跨进程通信的Service如何分析
当我们研究源码时遇到这种代码应该怎么分析?(如ActivityManagerNative)
可以看出无论Stub和Proxy或Binder对代码的逻辑性的分析并没有太大的用处,
他们只是实现类跨进程通信的机制,这种机制和逻辑相关性不是非常大

IXXXService只是规定接口方法,需要了解一下,着重的业务逻辑全在XXXXStub的实现类当中,
一般XXXXStub是作为XXXXService的内部类,也就是说看到有关aidl的系统服务源码时,
直接分析XXXXService就行了,逻辑全在那里
复制代码

2.AIDL为何而生
|--- 一个字:懒...   
自动生成的那个类,自己敲出来也能跑,既然能自动生成,那就生成呗,AIDL就出来了
这样就简化了跨进程间通信,但是凡事都有两面性,一旦简化了,就很难玩花样
Binder可以很复杂,IBinder还有很多控制的方法,所以AIDL只是最简单的跨进程间通信机制  
就像快速生产的板凳和精心雕刻的板凳,虽然都能坐,但价值是天差地别的
复制代码

3.ActivityManagerNative分析

还记得第一篇中Activity启动时出场的ActivityManagerNative吗?
这就是传说中的ActivityManagerNative你可以和最上面的IMusicPlayerService对比一下


4.ActivityManagerNative的幕后大佬

一般来说都是调用ActivityManagerNative.getDefault()生成一个IActivityManager对象
然后调用IActivityManager的相应抽象方法,那具体的实现类是谁?
ActivityManagerNative的作用相当于上面的Stub,需要找到一个继承他的类
这便是ActivityManagerService,注意它并不是Service类对象,而是服务的核心逻辑
它的价值也就相当于我们上面的MusicPlayerStub,不是Service,却更似服务


5.ActivityManagerNative.getDefault()方法说了什么?

返回一个IActivityManager对象,实际类型为ActivityManagerService

---->[ActivityManagerNative#getDefault]--------------------
static public IActivityManager对象 getDefault() {
    return gDefault.get();
}

//|--这里通过gDefault成员变量的get()方法获取了一个IActivityManager对象
|----现在焦点在gDefault身上,来看一下他是什么

---->[ActivityManagerNativegetDefault.gDefault]--------------------
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        //通过ServiceManager获取activity的IBinder对象
        IBinder b = ServiceManager获取.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        //asInterface方法使用IBinder对象,获取IActivityManager对象
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

//|--gDefault的数据类型是Singleton<IActivityManager>,有点意思,看一下Singleton类
----单例辅助类啊!create()方法用于穿件对象,get方法获取单例对象,但它是@hide的,我们不能用
public abstract class Singleton<T> {
    private T mInstance;
    protected abstract T create();
    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

---->[ActivityManagerNativegetDefault.asInterface]--------------------
static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    //如果obj(即Bundle) queryLocalInterface 不为空,就使用in
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }
    //否则返回ActivityManagerProxy对象
    return new ActivityManagerProxy(obj);
}

---->[ActivityManagerNativegetDefault$ActivityManagerProxy]--------------------
class ActivityManagerProxy implements IActivityManager{
    public ActivityManagerProxy(IBinder remote){
        mRemote = remote;
    }
    public IBinder asBinder(){
        return mRemote;
    }
    //略...
        public int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle map,
            String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
            boolean sticky, int userId) throws RemoteException
    //略...
    }
复制代码

这样使用ActivityManagerNative.getDefault()便可以获得一个IActivityManager对象,
该对象的实现类型为ActivityManagerService,也就是传说中的AMS,
所以在看源码时ActivityManagerNative.getDefault(),就相当于看到了AMS


后记:捷文规范
1.本文成长记录及勘误表
项目源码日期附录
V0.1--无2018-2-25

发布名:Android点将台:金科玉律[-AIDL-]
捷文链接:juejin.im/post/5c73c0…

2.更多关于我
笔名QQ微信
张风捷特烈1981462002zdl1994328

我的github:github.com/toly1994328
我的简书:www.jianshu.com/u/e4e52c116…
我的简书:www.jianshu.com/u/e4e52c116…
个人网站:www.toly1994.com

3.声明

1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值