前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android点将台:金科玉律[-AIDL-]

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

作者头像
张风捷特烈
发布2024-02-08 07:59:42
930
发布2024-02-08 07:59:42
举报

个人所有文章整理在此篇,将陆续更新收录:知无涯,行者之路莫言终(我的编程之路)

零、前言

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

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

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

类结构.png
类结构.png

IMusicPlayerService.png
IMusicPlayerService.png
2.从IInterface开始

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

代码语言:javascript
复制
package android.os;
public interface IInterface{
    public IBinder asBinder();
}
3.IMusicPlayerService的分析

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

代码语言:javascript
复制
/*
 * 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

Stub分析.png
Stub分析.png
代码语言:javascript
复制
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,并且有所动作,而且动作基本一致

Proxy.png
Proxy.png
代码语言:javascript
复制
 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的个别方法

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

binder与Ibinder.png
binder与Ibinder.png
1.目前IBinder台面上出现的方法
代码语言:javascript
复制
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台面上出现的方法
代码语言:javascript
复制
---->[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赋值

attachInterface.png
attachInterface.png
代码语言:javascript
复制
---->[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代理对象

asInterface.png
asInterface.png
代码语言:javascript
复制
---->[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)返回去,没什么好说的

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

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

onTransact.png
onTransact.png
代码语言:javascript
复制
@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类对象

代码语言:javascript
复制
---->[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在使用层面的逻辑是不是清晰了一些?

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

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

5.小结一下:现在回头再看
代码语言:javascript
复制
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  
客户端与服务端绑定服务的区别.png
客户端与服务端绑定服务的区别.png
queryLocalInterface.png
queryLocalInterface.png
三、ActivityManagerService初探
1.对于系统级跨进程通信的Service如何分析
代码语言:javascript
复制
当我们研究源码时遇到这种代码应该怎么分析?(如ActivityManagerNative)
可以看出无论Stub和Proxy或Binder对代码的逻辑性的分析并没有太大的用处,
他们只是实现类跨进程通信的机制,这种机制和逻辑相关性不是非常大

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

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

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

ActivityManagerNative分析.png
ActivityManagerNative分析.png
4.ActivityManagerNative的幕后大佬

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

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

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

ActivityManagerNative.getDefalut.png
ActivityManagerNative.getDefalut.png
代码语言:javascript
复制
---->[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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-02-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 零、前言
  • 一、上一篇中AIDL自动生成的IMusicPlayerService分析
    • 1.IMusicPlayerService的类结构
      • 2.从IInterface开始
        • 3.IMusicPlayerService的分析
          • 4.然后当然是深入一下,到Stub
            • 5.现在看最后一层奶油夹心:Proxy
            • 二、Binder和IBinder的个别方法
              • 1.目前IBinder台面上出现的方法
                • 2.目前Binder台面上出现的方法
                  • 3.再来看刚才暂略的方法
                    • 3.1:attachInterface
                    • 3.2:asInterface
                    • 3.3: asBinder
                    • 3.4: onTransact
                    • 3.5:Proxy中的实现方法
                  • 4.现在再来看我们在Service中画的最后一张图
                    • 5.小结一下:现在回头再看
                    • 三、ActivityManagerService初探
                      • 1.对于系统级跨进程通信的Service如何分析
                        • 2.AIDL为何而生
                          • 3.ActivityManagerNative分析
                            • 4.ActivityManagerNative的幕后大佬
                              • 5.ActivityManagerNative.getDefault()方法说了什么?
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档