AIDL

作者: ttyttytty | 来源:发表于2021-07-08 17:20 被阅读0次

    IPC进程间通信Inter-Process Communication

    • Android 基于 Linux,而 Linux 出于安全考虑,不同进程间不能之间操作对方的数据,这叫做“进程隔离”。

    • IPC:Inter-Process Communication跨进程通信,是底层的标准通信协议。

    • RPC:远程跨进程通信 :通过网络,通信的进程运行在不同的计算机上

    • LPC:本地跨进程通信:通信的进程运行在同一台计算机上
      进程间通信技术包括消息传递、同步、共享内存和远程过程调用。

    • IDL:Interface Description Language (接口定义语言)。它通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信交流。比如,一个组件用 C++ 写成,另一个组件用 Java 写,仍然可以通信。

    • Java IDL&JNI:

      • 都可以实现不同语言的交互调用(其他方式:TCP连接或者其它IPC机制;JDBC;)
      • IDL不同进程,因此,本地代码的错误并不会引起Java虚拟机的崩溃;JNI相同进程
        • JNI使用场景:(1.Java API不支持与特定操作系统相关的特性;
          2.Java应用程序想要访问本地代码库,但是想减少进程间通信的开销;
          3.使用本地代码实现对性能要求非常高的功能)
    • AIDL:Android IDL,主要是Binder机制。Linux 上的其他进程通信方式(管道/消息队列/共享内存/信号量/Socket)

    Binder
    • 从代码角度来看,Binder 是一个类,实现了 IBinder 接口;Binder 实现了 IBinder 定义的操作,它是 Android IPC 的基础,平常接触到的各种 Manager(ActivityManager, ServiceManager 等),以及绑定 Service 时都在使用它进行跨进程操作。Binder.onTransact() 根据code具体实现绑定前后数据转换;attachInterface用户绑定binder&IInterfasce,IInterface 应该就是进程间通信定义的通用接口,我们通过定义接口,然后再服务端实现接口、客户端调用接口,就可以实现跨进程通信。

    • 从来源看,Binder 来自于 OpenBinder,是 Android IPC 机制中的一种,Binder 还可以理解成一个虚拟物理设备,设备驱动是dev/binder;

    • 从 Framework 层看,Binder 是 Service Manager 连接各种Manager(ActivityManager,PackageManager…) 和相应Service (ActivityManagerService, PackageManagerService…) 的桥梁;

    • 从客户端看,Binder 是客户端服务器通讯的媒介

    • 在 Linux 系统中,内存空间分为两部分:用户空间:运行着应用程序;内核空间:运行着系统内核和驱动。Binder起连接作用, Binder在跨进程传输后引用没有改变,这是非常关键的一点,这就使得 IBinder/Binder 对象在跨进程通信时可以作为唯一的标识。
      client和server不同进程也不是共享内存,所以数据在系统中以序列化的形式传输

    • BInder机制的组成:

      •     1. Client、Server和Service Manager实现在用户空间中,Binder驱动程序实现在内核空间中
        
            2. Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server
        
            3. Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和Service Manager通过open和ioctl文件操作函数与Binder驱动程序进行通信
        
            4. Client和Server之间的进程间通信通过Binder驱动程序间接实现
        
            5. Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力
        
    • 通信流程:

          1.ServiceManager 初始化
          当该应用程序启动时,ServiceManager 会和 Binder 驱动进行通信,告诉 Binder 驱动它是服务管理者
          Binder 驱动新建 ServiceManager 对应的 Binder 实体
          2.Server 向 ServiceManager 注册自己
          Server 向 Binder 驱动发起注册请求,Binder 为它创建 Binder 实体
          然后如果 ServiceManager 中没有这个 Server 时就添加 Server 名称与 Binder 引用到它的 Binder 引用表
          3.Client 获取远程服务
          Client 首先会向 Binder 驱动发起获取服务的请求,传递要获取的服务名称
          Binder 驱动将该请求转发给 ServiceManager 进程
          ServiceManager 查找到 Client 需要的 Server 对应的 Binder 实体的 Binder 引用信息,然后通过 Binder 驱动反馈给 Client
          Client 收到 Server 对应的 Binder 引用后,会创建一个 Server 对应的远程服务(即 Server 在当前进程的代理)
          4.Client 通过代理调用 Server
          Client 调用远程服务,远程服务收到 Client 请求之后,会和 Binder 驱动通信
          因为远程服务中有 Server 的 Binder 引用信息,因此驱动就能轻易的找到对应的 Server,进而将Client 的请求内容发送 Server
      
    • Binder性能与效率的优势:安全问题,我们可以采用C/S架构或者匿名的IPC通信机制,匿名的IPC通信机制无疑会影响进程间通信的方便性,比如匿名管道,就只能在亲属进程间通信。所以我们需要采用C/S的架构,在C/S架构下,Server端可以对Client端的请求做校验来保证安全性。
      解决并发问题,解决并发问题我们可以采用消息队列,或者通过锁来控制并发情况,或者采用C/S架构。
      在这三者的考虑下,我们发现只有采用C/S架构的共享内存才是最高效的。所以我们的Binder本质上就是C/S架构的共享内存的IPC机制。

    • 如何实现C/S的一对多?:在内核中,每个binder包括:多个binder引用结构体与client绑定,1个binder实体结构,与server绑定。binder引用与binder实体之间是可以互相索引到的,且是多对一关系。

    如何实现双向通信
    在血压进程里面,向ResearchData进程申请kit数据权限,受API限制,实际是由主进程实现。                                                              
    1.Client(血压)->Server(ResearchData):正常调用服务端接口,客户端初始化Callback.stub(),在回调.AIDL里面处理客户端自己的逻辑
    2."Server(ResearchData)"->主进程:实际代码是主进程中实现
    a)ResearchData定义回调AIDL和接口AIDL
    
        // IDataPermissionRequestCallback.aidl
        interface IDataPermissionRequestCallback {
            void onResult(in int resultCode );
        }
    
        // IWearDeviceManager.aidl
        interface IWearDeviceManager {
             //请求kit 授权
            void requestDataPermission(in List<DataPermission> permissionList, in IDataPermissionRequestCallback callback,in Cookie cookie);
         }
    
    b)血压进程实现回调AIDL并调用ResearchData的功能接口:
        provider.requestDataPermission(PERMISSION_LIST, new IDataPermissionRequestCallback.Stub() {
            @Override
            public void onResult(int resultCode) throws RemoteException {
                LogUtils.d(TAG, " requestDataPermission: " + resultCode);
            }
        });
        
    c)ResearchData:
        ResearchData实现对血压公开接口:
        public class authManagerImp extends IAuthManager.Stub implements AddHealthScopesCallback {
            private final RemoteCallbackList<IAddAuthScopesCallback> addAuthScopesCallbackList = new RemoteCallbackList<>();
            @Override
            public void requestDataPermission(List<com.huawei.study.data.permission.DataPermission> permissionList,
                IDataPermissionRequestCallback callback, Cookie cookie) throws RemoteException {
                addScopesInAUth(convertScope(permissionList));
            }
            
            public synchronized void addScopesInAUth(List<com.huawei.study.data.permission.DataPermission> scopes) {
                int number = addAuthScopesCallbackList.beginBroadcast();
                for (int i = 0; i < number; i++) {
                    try {
                        IAddAuthScopesCallback addAuthScopesCallback = addAuthScopesCallbackList.getBroadcastItem(i);
                        addAuthScopesCallback.addScopes(scopes);  // 最终调用主进程注册进来的Callback,执行实际scope申请代码
                    } catch (RemoteException ex) {
                        LogUtils.e(TAG, "failed to add health scope:" + scopes == null ? "" : scopes.toString());
                    }
                }
                addAuthScopesCallbackList.finishBroadcast();
            }
            @Override
            public void registerAddScopesCallback(IAddAuthScopesCallback callback) throws RemoteException {
                addAuthScopesCallbackList.register(callback);
            }
        }
        
        ResearchData实现接受主进程回调:
        // IAddAuthScopesCallback.aidl
        interface IAddAuthScopesCallback {
            void addScopes(in List<DataPermission> scopes);
        }
        
        主进程中ResearchServiceManager:
            private final IAddAuthScopesCallback.Stub addAuthScopesCallback = new IAddAuthScopesCallback.Stub() {
            @Override
            public void addScopes(List<DataPermission> scopes) throws RemoteException {
                HuaweiIdAuthManager.addAuthScopes(ActivityManager.getInstance().currentActivity(), FAIL_GET_SCOPE, PermissionUtil.convertScope(scopes));
            }
        };
         authManagerImp.registerAddScopeCallback(addAuthScopesCallback);
    
    

    相关文章

      网友评论

          本文标题:AIDL

          本文链接:https://www.haomeiwen.com/subject/keytpltx.html