AIDL的原理实现

2023-05-16

前言

Binder 驱动是基于 CS 模型设计的跨进程通信驱动, 想要使用 Binder 驱动进行通信, 需要三个步骤

  • 定义交互规范
  • 服务端实现
  • 客户端实现

一、 定义交互规范

public interface IService extends IInterface {
    /*
     跨进程提供服务的接口描述
    */
    String DESCRIPTOR = IService.class.getName();
    /*
      跨进程提供服务的接口中 getServiceName 这个方法 Transaction id.
     */
    int TRANSACTION_getServiceName = (IBinder.FIRST_CALL_TRANSACTION + 0);

    String getServiceName() throws RemoteException;
}

二、服务端的实现

1、接口 IService 在服务端的实现类

/**
 * 接口 IService 在服务端的实现类
 * {@link #mBinder } 这个对象是让 IService 拥有跨进程提供数据能力的 Binder 本地实现类
 */
public class ServiceImpl implements IService {

    private IBinder mBinder;

    public ServiceImpl(IBinder binder) {
        this.mBinder = binder;
    }

    @Override
    public String getServiceName() {
        return "This this IService support function.";
    }

    @Override
    public IBinder asBinder() {
        return mBinder;
    }

}

2、Service 端 Binder 本地实现类

/**
 * Service 端 Binder 本地实现类
 * 其向外提供的功能接口为 {@link IService}
 */
public class ServiceBinder extends Binder {

    /*
      持有其对应接口实现类的引用
     */
    private IService mImpl;

    public ServiceBinder() {
        mImpl = new ServiceBinder(this);
        // 调用了 attachInterface 之后, 父类 Binder 将会持有当前 IInterface 接口的描述
        // 在 onTransact 中 会自动处理 INTERFACE_TRANSACTION 类型的事务
        // 在 queryLocalInterface 中可以找到本地接口
        this.attachInterface(mImpl, mImpl.DESCRIPTOR);
    }

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            //          调用了 attachInterface 之后, 父类会处理该类型的 code.
           //            case INTERFACE_TRANSACTION: {
           //                reply.writeString(DESCRIPTOR);
           //                return true;
           //            }
            case IService.TRANSACTION_getServiceName: {
                data.enforceInterface(mImpl.DESCRIPTOR);
                reply.writeNoException();
                reply.writeString(mImpl.getServiceName());
                return true;
            }
            default:
                return super.onTransact(code, data, reply, flags);
        }
    }
}

三、客户端的实现

public class ServiceProxyImpl implements IService {

    private IBinder mBinderProxy;

    public ServiceProxyImpl(IBinder binder) {
        mBinderProxy = binder;
    }

    @Override
    public String getServiceName() throws RemoteException {
        String result = null;
        Parcel data = Parcel.obtain();
        Parcel replay = Parcel.obtain();
        try {
            // 1. 写入调用方法所对应接口的描述
            data.writeInterfaceToken(DESCRIPTOR);
            // 2. 向 Service 端发起 invocation 请求
            mBinderProxy.transact(IService.TRANSACTION_getServiceName, data, replay, 0);
            // 3. 读取 Service 端扔出来的异常信息
            replay.readException();
            // 4. 读取异常结果
            result = replay.readString();
        } finally {
            replay.recycle();
            data.recycle();
        }
        return result;
    }

    @Override
    public IBinder asBinder() {
        return mBinderProxy;
    }
}

四、具体实现

1、服务端

public class MyService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new ServiceBinder();
    }
}
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.mi.mytest.yobo" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

2、客户端

        Intent intent = new Intent();
        intent.setPackage("com.mi.mytest");
        intent.setAction("com.mi.mytest.yobo");
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.e("yobo","onServiceConnected");
                iService = new ServiceProxyImpl(service);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.e("yobo","onServiceDisconnected");
            }
        }, BIND_AUTO_CREATE);

3、注意

  • IService、ServiceBinder、ServiceImpl、ServiceProxyImpl需要在同一应用包名下
  • Android11以后对于启动别的应用的Activity和Service做了隐藏功能,需要在客户端添加如下代码:
    <queries>
        <intent>
            <action android:name="com.mi.mytest.yobo" />
        </intent>
    </queries>

五、Android 11上Google收缩了程序包可见性

其实是Android 11上Google收缩了程序包可见性,这就导致可能查询不到三方应用及其内部的ContentProvider、Service组件。Android开发者官网给出的解释如下:

“如果您的应用以 Android 11(API 级别 30)或更高版本为目标平台,在默认情况下,系统会自动让部分应用对您的应用可见,但会隐藏其他应用。通过让部分应用在默认情况下不可见,系统可以了解应向您的应用显示哪些其他应用,这样有助于鼓励最小权限原则,还可帮助 Google Play 等应用商店评估应用为用户提供的隐私权和安全性。”

1、降低版本兼容处理(不推荐)

首先想到的办法就是,降低targetSdkVersion版本,这样也行,运行在Android 11设备上没问题,不过迟早还是需要适配Android这个特性的。

    targetSdkVersion 29

2、增加QUERY_ALL_PACKAGES权限(不建议)

记得曾在Android 11适配的过程中用到新增的一个权限:android.permission.QUERY_ALL_PACKAGES。加上这个权限就能够查询所有的应用,解决前面无法启动三方应用Service的问题。而且QUERY_ALL_PACKAGES权限等级为normal,只要在AndroidManifest.xml中申请声明即可获得该权限。

    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />

不过,Google限制该权限的使用,如果开发者的应用需要上架Google Play,最好不要使用该权限否则会被检测警告甚至不让上架。

3、使用标签声明使用的三方组件(推荐)

可以使用范围更具体的的查询,使用标签声明要查询的,系统会查询所有能够处理该Intent的Service等组件。

    <queries>
        <intent>
            <action android:name="cn.quibbler.server.aidl" />
            <data android:path="quibbler" />
        </intent>
    </queries>

需要注意,开发者不要在中声明“宽泛的intent”。
对于ContentProvider,通过中的子标签查询指定的authorities。

    <queries>
        <provider android:authorities="sadas" />
    </queries>

还直接添加合作的三方应用包名,使对方包对自己可见。

    <queries>
        <package android:name="com.tencent.qq" />
    </queries>

开发者应当遵循最小使用原则,只添加应用所需的三方应用包,Google增加这样的设计也是为了隐私和安全考虑。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AIDL的原理实现 的相关文章

  • OSI 七层模型详解

    大家好 xff0c 我是蛋蛋 3T 43 技术学习视频资源 xff0c 500 43 技术电子书 xff0c 大量高效工具及网站 xff0c 私信回复 资源 即可免费获取 OSI xff08 Open System Interconnect
  • WebService的简单示例

    今天 xff0c 看到需求需要WebService进行通信 xff0c 所以我就先看看WebService是怎样的一个流程 xff0c 这里做个简单实例 首先我创建了两个工程 xff0c 一个为服务端 xff0c 另一个为客户端 part1
  • 今日头条2018校园招聘后端开发工程师 (第二批) 编程题 - 字母交换

    题目描述 xff1a 编码题 字符串S由小写字母构成 xff0c 长度为n 定义一种操作 xff0c 每次都可以挑选字符串中任意的两个相邻字母进行交换 询问在至多交换m次之后 xff0c 字符串中最多有多少个连续的位置上的字母相同 xff1
  • php 报错:A non-numeric value encountered

    意思是 39 遇到了非数值异常 39 xff0c 可能是你的代码里字符串拼接习惯性的将 39 39 写成了 39 43 39 所导致
  • linux系统变为只读,提示Read-only file system的解决办法

    mount o rw remount
  • 修改Debian登录窗口背景图片

    仅记录以便日后使用 xff1a 执行gresource export sh xff0c 将资源文件备份到 HOME shell theme目录将导出的 HOME shell theme theme中的所有文件 xff0c 保存到gnome
  • 【MySQL】Navicat修改数据库名称

    假设 xff1a 有一个数据库 xff0c 名称为A xff0c 需要修改为B 在Navicat中不可以按F2修改数据库的名称 xff0c 我们必须新建一个库 xff0c 命名为B 下面4种方式都可以实现目标 如果数据库中有远程表和权限设置
  • CityScapes数据集介绍

    CityScapes Cityperson数据集 xff0c 在16年CVPR上被提出 xff0c 是张姗姗一波人在CityScapes数据集上进行标注得到的行人检测数据集 做行人检测的应该都不陌生 在Replusion Loss和NMS
  • ARM学习(18) Jink Ozone调试总结

    笔者来聊聊Jink Ozone调试 1 Ozone加载选择elf或者bin Ozone调试的时候可以设置PC的位置 xff0c 主要有上面两种 从ELF读取PC位置 xff0c 调试时直接设置PC的初始位置从向量表中读取pc的初始值 xff
  • mac iCloud 关闭后 桌面文件不见了

    输入 user后回车 进入用户文件 打开iCloud Drive
  • 【模拟】AtCoder2160 Manhattan Compass

    分析 模拟实现题 把坐标轴转一下然后暴力求就行了 转了一下坐标轴 xff0c 问题就变成以p为中心 xff0c 与新的坐标轴平行的 xff0c 边长为2 d的正方形上的点能够与p相连 方便起见 xff0c 把答案分成两部分求 然后可以分别考
  • 处理爬虫是返回setCookie的一段js获取acw_sc__v2的方法

    处理爬虫是返回setCookie的一段js获取acw sc v2的方法 原文链接 setCookie JS反爬虫处理 处理代码 span class token keyword import span requests span class
  • C++ winpcap网络抓包代码实现,以及抓包内容解析。

    c 43 43 实现抓包代码 1 安装winpcap windows packet capture 是windows平台下一个免费 xff0c 公共的网络访问系统 开发winpcap这个项目的目的在于为win32应用程序提供访问网络底层的能
  • Python dataframe更换列名称

    方法1 使用pd rename函数 span class hljs operator a span span class hljs built in rename span columns 61 span class hljs string
  • 知识点2:Swift REPL

    关于REPL简介 REPL xff1a 英文缩写 xff08 Read Eval Print Loop xff09 即读取 执行 输出 循环的意思 Xcode 6 1 引入了另一种以交互式的方式体验Sw ift的方法 主要特点 xff1a
  • iOS 关于UIAlertController常见使用方法

    Step 1 警告框 1 代码 1 创建提示窗口 参数1 xff1b Title xff1a 标题 参数1 xff1b message xff1a 提示内容 参数1 xff1b Style 风格 UIAlertControllerStyle
  • 2023年最新版kali linux安装教程

    一 前期准备 前排提醒 xff0c 文末有绿色版安装包免费领取 xff01 二 VMware虚拟机配置 1 打开vmware xff0c 点击创建新的虚拟机 2 选择自定义 高级 选项 xff0c 点击下一步 3 继续下一步 4 选择 稍后
  • CentOS7.1下 安装vncserver和删除vnc占有的端口

    今天给两台新服务器装CentOs7 1系统 xff0c 然后装VNCServer的时候感觉网上的教程要么复杂多此一举 xff0c 要么不清楚 xff0c 关于 list端口的部分都没讲 所以这里整理一下 xff0c 按着下面的顺序来就可以了
  • mac使用虚拟机(VirtualBox+centos7)搭建kubernetes(K8S)集群

    文章目录 说明一 环境准备1 配置主机网络2 配置磁盘空间3 安装虚拟机配置网络4 设置Linux环境 三台均需要设置 二 安装docker kubeadm kubelet kubectl 三台均需要设置 1 安装docker环境2 kub
  • .NET6入门:1.Windows开发环境搭建

    作为 NET的最新版本 NET6长期支持版已经发布 xff0c NET6宣称是迄今为止最快的 NET 那当然不能落下时代的潮流 xff0c 就让我们跟着文章进入 NET6的世界吧 1 NET6SDK下载 Download NET Linux

随机推荐

  • 音视频编解码原理(一) 封装格式和编码方式简介

    一 封装格式 要了解音视频编解码原理 xff0c 首先需要知道什么是封装格式 xff1f 所谓封装格式 xff0c 就是将已经编码压缩好的视频轨和音频轨按照一定的格式封装到一个文件中 xff0c 一般情况下 xff0c 不同的封装格式对应不
  • VS调试方法总结(二)

    通过结构化异常定位崩溃程序 程序崩溃时 xff0c 生成文本文件 xff0c 记录崩溃得堆栈信息 直接上代码 已经编译通过 xff0c 拷贝直接可用 h include lt Windows h gt include lt stdarg h
  • QT(C++) + OpenCV + Python库打包发布可执行EXE

    QT xff08 C 43 43 xff09 43 OpenCV 43 Python库打包发布可执行EXE 背景 最近写了一个操作界面 xff0c 不仅用到了OpenCV的函数 xff0c 还调用了一个python脚本 xff0c 所以这里
  • Linux 内存管理 页回收和swap机制

    页高速缓存和页写回机制 页是物理内存或虚拟内存中一组连续的线性地址 xff0c Linux内核以页为单位处理内存 xff0c 页的大小通常是4KB 当一个进程请求一定量的页面时 xff0c 如果有可用的页面 xff0c 内核会直接把这些页面
  • docker 创建 network,出现异常问题及解决

    最近在使用 docker 创建 network 时 xff0c 出现错误 xff1a Error response from daemon could not find plugin bridge in v1 plugin registry
  • 工作进度所占总进度的比例

    如果实现的功能模块全部完成为 或者说 工作进度 xff1a 100 那么 xff1a 1 产品原型全部完成 包括文档的整理 xff1a 15 2 UI设计全部完成 xff1a 10 3 后台全部完成 xff1a 25 4 前台全部完成 xf
  • Docx4J替换内容时,内容换行失败问题解决

    WordprocessingMLPackage wordMLPackage 61 WordprocessingMLPackage load new java io File templatePath MainDocumentPart doc
  • C语言经典例题-用4×4矩阵显示从1到16的所有整数,并计算每行、每列和每条对角线上的和

    编写一个程序 xff0c 要求用户 按任意次序 xff09 输入从1到16的所有整数 xff0c 然后用4 4矩阵的形式将它们显示出来 再计算出每行 每列和每条对角线上的和 include lt stdio h gt int main in
  • java中Map.hashCode()函数说明

    在java中 xff0c Map hashCode 函数是在具有一定工作积累后 xff0c 为了更好的成长不可避免需要研究的内容 首先 xff0c 我们先看下原始代码 xff1a static final int hash Object k
  • 不支持的特性: getMetaData,问题解决

    最近使用springboot 43 mybatis 时遇到 xff1a 不支持的特性 getMetaData 的异常 使用 xff1a 64 Options useGeneratedKeys 61 false 解决的该问题 xff1b 官方
  • jsp四种范围

    page代表是与一个页面相关的对象和属性 request代表是与 Web 客户机发出一个请求相关的对象和属性 session代表是与用于某个 Web 客户机的一个用户体验相关的对象和属性 application代表是与整个 Web 应用程序
  • Kotlin-17-等号比较(== 、===)

    目录 1 Java中的 61 61 2 Java中的 equals 3 两者的区别 3 对于基本数据类型的 61 61 比较 4 Kotlin中的 61 61 与 61 61 61 1 Java中的 61 61 Java中的 61 61 直
  • Kotlin-30-继承多个父类

    目录 1 Java中的继承 2 Kotlin中的继承 1 Java中的继承 Java中的类只能继承一个父类 xff0c 是无法实现继承多个父类 xff0c 但是一个类可以实现多个接口 Java中的接口是无法给函数添加函数体的 abstrac
  • 算法-9-快速排序

    目录 1 描述 2 特点 3 代码实现 3 1 切分函数partition 图示 4 性能 5 快速排序优化 xff08 小数组插入排序 xff09 6 快排优化 xff08 三向切分 xff09 1 描述 快速排序也是基于递归实现的 和归
  • Kotlin进阶-6-重入锁+synchronized+volatile

    目录 1 介绍 2 线程的状态 3 创建线程 4 线程同步 4 1 可重入锁 4 2 不可重入锁的实现 4 3 可重入锁的实现 4 4 Java中的可重入锁 ReentrantLock 4 5 同步方法 synchronized 5 vol
  • Kotlin进阶-7-阻塞队列+线程池

    目录 1 阻塞队列 1 1 常见阻塞场景 2 Java中的阻塞队列 2 1 ArrayBlockingQueue 2 2 LinkedBlockingQueue 2 3 PriorityBlockingQueue 2 4 DelayQueu
  • Kotlin进阶-11-Activity启动后的视图加载分析

    1 介绍 Kotlin进阶 9 setContentView源析 43 Window Activity DecorView关系 Kotlin进阶 10 Activity的启动流程 前面两节分别介绍了Activity的启动流程 xff0c 还
  • Java多线程编程技术总结

    目录 1 退出线程的3种方式 xff1a 1 1 判断线程是否中断 xff1f 1 2 interrupt 1 3 stop 1 4 StackTraceElement getStackTrace 方法 2 suspend 和resume
  • 【Mysql】视图

    Mysql 视图 1 什么是视图 xff08 MySQL 5以及以上版本 xff09 2 视图的优点3 视图的规则与限制4 使用视图附录 1 什么是视图 xff08 MySQL 5以及以上版本 xff09 视图是虚拟的表 与包含数据的表不一
  • AIDL的原理实现

    前言 Binder 驱动是基于 CS 模型设计的跨进程通信驱动 想要使用 Binder 驱动进行通信 需要三个步骤 定义交互规范服务端实现客户端实现 一 定义交互规范 span class token keyword public span