【Binder 机制】AIDL 分析 ( AIDL 通信完整流程梳理 )

简介: 【Binder 机制】AIDL 分析 ( AIDL 通信完整流程梳理 )

文章目录

AIDL 跨进程通信完整流程梳理

1、AIDL 文件编译

2、注册服务

3、IMyAidlInterface.Stub.asInterface 方法获取远程服务

4、IMyAidlInterface.Stub.Proxy 代理类

5、IMyAidlInterface.Stub.Proxy 代理类方法执行

6、Binder.transact 方法执行

7、IMyAidlInterface.Stub.onTransact 方法执行

8、调用 Service 中实现的 IMyAidlInterface.Stub 抽象方法





AIDL 跨进程通信完整流程梳理



1、AIDL 文件编译


AIDL 文件 IMyAidlInterface.aidl 在客户端和服务端都有 , 编译时 , 都会在 " build\generated\aidl_source_output_dir\debug\out\kim\hsl\aidl_demo " 目录生成 IMyAidlInterface.java 源文件 ;


这样在客户端与服务器端都可以调用 IMyAidlInterface.Stub 类的相关方法 , 主要是 asInterface 方法 , 用于获取远程服务或代理 ;



2、注册服务


在应用中 , 通过绑定 Service 注册服务 ;


   

// 通过 Action 和 包名 , 绑定远程服务
        Intent intent = new Intent("android.intent.action.MyService");
        intent.setPackage("kim.hsl.aidl_demo");
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);



3、IMyAidlInterface.Stub.asInterface 方法获取远程服务


开启一个 ServiceConnection , 在 ServiceConnection 的 onServiceConnected 方法中 ,


调用 IMyAidlInterface.Stub.asInterface 方法 ,


在 IMyAidlInterface.Stub.asInterface 方法中 , 传入我们需要的 Service 远程服务 ; 这里涉及到跨进程调用 , 拿到的是一个代理 ;


Stub 中定义了 asInterface 方法 , 该方法的作用是将 android.os.IBinder 对象转为 AIDL 接口对象 ; 传入的 DESCRIPTOR 描述符 , 用于描述用户想要哪个 Binder , android.os.IBinder 对象调用 queryLocalInterface 方法 , 检查本地服务是否存在 ;


如果可以找到本地服务对应的接口 , 可以直接返回本地服务 ;

如果没有找到本地服务 , 就会返回一个 Stub 代理 ;

详细的过程参考下面的代码 :


 

/**
     * 将IBinder对象强制转换为kim.hsl.aidl_demo.IMyAidlInterface接口,必要时生成代理。
     */
    public static kim.hsl.aidl_demo.IMyAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      // 传入 DESCRIPTOR 描述符 , 用于描述用户想要哪个 Binder
      // android.os.IBinder 对象调用 queryLocalInterface 方法 , 检查本地服务
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      // 如果可以找到本地服务对应的接口 , 可以直接返回本地服务 
      if (((iin!=null)&&(iin instanceof kim.hsl.aidl_demo.IMyAidlInterface))) {
        return ((kim.hsl.aidl_demo.IMyAidlInterface)iin);
      }
      // 如果没有找到本地服务 , 就会返回一个 Stub 代理 
      return new kim.hsl.aidl_demo.IMyAidlInterface.Stub.Proxy(obj);
    }



4、IMyAidlInterface.Stub.Proxy 代理类


上述 IMyAidlInterface.Stub.asInterface 方法 , 最终返回一个代理 , 代理如下 :


在 IMyAidlInterface.java 中的代理中 , 实现了 3 33 个 AIDL 接口方法 ;


 

private static class Proxy implements kim.hsl.aidl_demo.IMyAidlInterface
    {
      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 basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
      {
      }
      /**
           * in 写入, out 输出, inout 写入和输出
           */
      @Override public void addStudent(kim.hsl.aidl_demo.Student student) throws android.os.RemoteException
      {
      }
      /**
           * 获取 Student 集合
           */
      @Override public java.util.List<kim.hsl.aidl_demo.Student> getStudents() throws android.os.RemoteException
      {
        return _result;
      }
    }


5、IMyAidlInterface.Stub.Proxy 代理类方法执行


在主应用中 , 调用 IMyAidlInterface aidl 也就是 IMyAidlInterface.Stub.asInterface 方法返回的代理对象的 addStudent 方法 , 分析代理中的该方法 , 首先生成输入和输出数据 , 传参和反参都会传入 mRemote.transact 方法中 , 这是 Binder 的方法 ;


 

/**
           * in 写入, out 输出, inout 写入和输出
           */
      @Override public void addStudent(kim.hsl.aidl_demo.Student student) throws android.os.RemoteException
      {
        // 通过 Parcel 池获得两个对象 , 分别用于输入和输出
        // 输入对象
        android.os.Parcel _data = android.os.Parcel.obtain();
        // 输出对象
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((student!=null)) {
            _data.writeInt(1);
            student.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          // 调用 Binder 的 transact 方法 
          boolean _status = mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addStudent(student);
            return;
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            student.readFromParcel(_reply);
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }



6、Binder.transact 方法执行


Binder 中的 transact 方法执行后 , 会回调 IMyAidlInterface.java 中的 Stub 内部类的 onTransact 方法 ,


Binder 的 transact 方法 ; 进入该方法后 , 会将原来的线程挂起 , 直到返回 , 原来的线程才会继续执行 , 这里非常容易出现 ANR ;


/**
 * 远程对象的基类,由{@link IBinder}定义的轻量级远程过程调用机制的核心部分。
 * 此类是IBinder的一个实现,它提供了此类对象的标准本地实现。
 *
 * <p>大多数开发人员不会直接实现这个类,
 * 而是使用<a href=“{@docRoot}guide/components/aidl.html”>aidl</a>工具来描述所需的接口,
 * 让它生成适当的Binder子类。
 * 然而,您可以直接从Binder派生来实现您自己的定制RPC协议,
 * 或者直接实例化一个原始Binder对象,将其用作可以跨进程共享的令牌。
 *
 * <p>这个类只是一个基本的IPC原语;
 * 它对应用程序的生命周期没有影响,并且只有创建它的进程继续运行时才有效。
 * 要正确使用此功能,您必须在顶级应用程序组件(a{@link android.app.Service}、
 * {@link android.app.Activity}或{@link android.content.ContentProvider})
 * 的上下文中执行此操作,该组件应保持运行。</p>
 *
 * <p>您必须记住流程可能会消失的情况,因此需要稍后重新创建新的活页夹,
 * 并在流程再次启动时重新附加它。
 * 例如,如果您在{@link android.app.Activity}中使用此函数,
 * 则您的活动的进程可能会在活动未启动时被终止;
 * 如果以后重新创建活动,则需要创建新的活页夹,
 * 并再次将其交回正确的位置;
 * 您需要注意的是,您的流程可能由于其他原因(例如接收广播)而启动,
 * 这将不涉及重新创建活动,因此运行其代码以创建新的绑定。</p>
 *
 * @see IBinder
 */
public class Binder implements IBinder {
    /**
     * 默认实现回放地块并调用onTransact。在远程端,transact调用绑定器来执行IPC。
     */
    public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
            int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);
        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }
}



7、IMyAidlInterface.Stub.onTransact 方法执行


在 IMyAidlInterface.Stub.onTransact 方法中 , 通过方法对应的 ID 常量值匹配方法 , 在该方法中就会调用 IMyAidlInterface.Stub 中没有实现的抽象方法 ;


 

@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_basicTypes:
        {
          return true;
        }
        case TRANSACTION_addStudent:
        {
          return true;
        }
        case TRANSACTION_getStudents:
        {
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }



8、调用 Service 中实现的 IMyAidlInterface.Stub 抽象方法


IMyAidlInterface.Stub 中的抽象方法 , 在 Service 中实现 ;


 

/**
     * 创建 IMyAidlInterface.Stub 抽象类子类对象 , 实现其中的 3 个抽象方法
     * Binder 调用 transact 方法时 , 会调用 IMyAidlInterface.Stub 的 onTransact 方法
     * 在 IMyAidlInterface.Stub.onTransact 方法中会调用下面实现的抽象方法
     */
    private IMyAidlInterface.Stub stub = new IMyAidlInterface.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong,
                               boolean aBoolean, float aFloat, double aDouble,
                               String aString) throws RemoteException {
            Log.i(TAG, "anInt=" + anInt + " , aLong=" + aLong +
                    " , aBoolean=" + aBoolean + " , aFloat=" + aFloat +
                    " , aDouble=" + aDouble + " , aString=" + aString);
        }
        @Override
        public void addStudent(Student student) throws RemoteException {
            if (students != null) {
                students.add(student);
            }
        }
        @Override
        public List<Student> getStudents() throws RemoteException {
            return students;
        }
    };
目录
相关文章
|
5月前
|
Android开发 移动开发 小程序
binder机制原理面试,安卓app开发教程
binder机制原理面试,安卓app开发教程
binder机制原理面试,安卓app开发教程
|
5月前
|
安全 Java 定位技术
Android 浅度解析:AIDL & Binder (1)
Android 浅度解析:AIDL & Binder (1)
156 0
|
5月前
|
数据采集 Python SQL
2024年校花转学到我们班,于是我用Python把她空间给爬了个遍!(1),binder机制面试题
2024年校花转学到我们班,于是我用Python把她空间给爬了个遍!(1),binder机制面试题
2024年校花转学到我们班,于是我用Python把她空间给爬了个遍!(1),binder机制面试题
|
存储 Java Android开发
听说你Binder机制学的不错,来面试下这几个问题(二)
听说你Binder机制学的不错,来面试下这几个问题(二)
290 0
听说你Binder机制学的不错,来面试下这几个问题(二)
|
存储 缓存 Java
听说你Binder机制学的不错,来面试下这几个问题(三)
听说你Binder机制学的不错,来面试下这几个问题(三)
261 0
听说你Binder机制学的不错,来面试下这几个问题(三)
|
存储 Java 大数据
听说你Binder机制学的不错,来面试下这几个问题(一)
听说你Binder机制学的不错,来面试下这几个问题(一)
696 0
听说你Binder机制学的不错,来面试下这几个问题(一)
|
消息中间件 存储 缓存
Android进程间通信之一:Binder机制学习
Android进程间通信之一:Binder机制学习
213 0
Android进程间通信之一:Binder机制学习
|
Java Android开发
Binder机制中的收发消息及线程池
在阅读《深入理解android内核设计思想》的有关Binder章节的时候,发现书中有部分问题没有很清晰的描述清楚,所以这篇文章主要是针对收发消息的过程和线程池这两个知识点详细展开一下。注意本篇文章并不是介绍Binder机制,而是针对它的两个小细节深入探讨一下,所以建议大家先详细的阅读《深入理解android内核设计思想》中有关Binder章节后对照阅读本篇文章。
352 0
|
3月前
|
缓存 安全 Java
Android深入Binder拦截问题分析
【7月更文挑战第1天】Android Binder 拦截可实现虚拟化、测试、SDK检测、逆向分析及ROM扩展。通过Java层aidl代理,利用IBinder接口规范来拦截通信。拦截步骤包括:替换Binder服务缓存对象,如ActivityManagerService;代理ServiceManager以控制服务获取。此操作需系统权限,可能涉及安全风险和版本差异,非必要时应谨慎。
|
Java API Android开发
Android中Binder在项目中的具体使用详解
Android中Binder在项目中的具体使用详解
169 0