Android 多进程开发 - AIDL 回调、RemoteCallbackList、AIDL 安全校验
一、AIDL 的回调1、基本介绍AIDL 的回调指服务端主动通知客户端例如位置变化这需要跨进程回调2、演示1CallbackIPlayerCallback.aidl这里是位于src/main/java/com/my/common包下packagecom.my.common;interfaceIPlayerCallback{voidonSongChanged(StringsongName);voidonPlayStateChanged(booleanisPlaying);}2AIDLIMyAidlInterface.aidl这里是位于src/main/java/com/my/common包下packagecom.my.common;importcom.my.common.IPlayerCallback;interfaceIMyAidlInterface{voidplay();voidpause();voidregisterCallback(IPlayerCallbackcallback);voidunregisterCallback();}3ServerprivateIPlayerCallbackcallback;privateStringsongName;privatebooleanisPlayingfalse;privatefinalIMyAidlInterface.StubbindernewIMyAidlInterface.Stub(){Overridepublicvoidplay()throwsRemoteException{if(isPlaying)return;isPlayingtrue;if(callbacknull)return;callback.onPlayStateChanged(isPlaying);if(songNamenull){songNameServer Song;callback.onSongChanged(songName);}}Overridepublicvoidpause()throwsRemoteException{if(!isPlaying)return;isPlayingfalse;if(callbacknull)return;callback.onPlayStateChanged(isPlaying);}OverridepublicvoidregisterCallback(IPlayerCallbackcallback)throwsRemoteException{ServerService.this.callbackcallback;}OverridepublicvoidunregisterCallback()throwsRemoteException{ServerService.this.callbacknull;}};4Clienttry{myAidlInterface.play();Log.i(TAG,play method success);}catch(RemoteExceptione){e.printStackTrace();Log.e(TAG,play method error: e.getMessage());}try{myAidlInterface.pause();Log.i(TAG,pause method success);}catch(RemoteExceptione){e.printStackTrace();Log.e(TAG,pause method error: e.getMessage());}try{myAidlInterface.registerCallback(newIPlayerCallback.Stub(){OverridepublicvoidonSongChanged(StringsongName)throwsRemoteException{Log.i(TAG,now thread: Thread.currentThread().getName());Log.i(TAG,onSongChanged: songName);}OverridepublicvoidonPlayStateChanged(booleanisPlaying)throwsRemoteException{Log.i(TAG,now thread: Thread.currentThread().getName());Log.i(TAG,onPlayStateChanged: isPlaying);}});Log.i(TAG,registerCallback method success);}catch(RemoteExceptione){e.printStackTrace();Log.e(TAG,registerCallback method error: e.getMessage());}try{myAidlInterface.unregisterCallback();Log.i(TAG,unregisterCallback method success);}catch(RemoteExceptione){e.printStackTrace();Log.e(TAG,unregisterCallback method error: e.getMessage());}5Test先调用 registerCallback 方法输出结果如下registerCallback method success再调用 play 方法输出结果如下now thread: main onPlayStateChanged: true now thread: main onSongChanged: Server Song play method success再调用 pause 方法输出结果如下now thread: main onPlayStateChanged: false pause method success最后调用 unregisterCallback 方法输出结果如下unregisterCallback method success二、RemoteCallbackList1、基本介绍RemoteCallbackList 是 Android 专门为跨进程通信设计的一个工具类它用于安全、自动地管理回调beginBroadcast 是 RemoteCallbackList 中用于安全遍历列表的一个方法它配合 finishBroadcast 方法一起使用beginBroadcast 方法会固定当前要遍历的快照记录当前所有存活回调的数量在调用finishBroadcast 方法之前列表不会变化2、演示1CallbackIPlayerCallback.aidl这里是位于src/main/java/com/my/common包下packagecom.my.common;interfaceIPlayerCallback{voidonSongChanged(StringsongName);voidonPlayStateChanged(booleanisPlaying);}2AIDLIMyAidlInterface.aidl这里是位于src/main/java/com/my/common包下packagecom.my.common;importcom.my.common.IPlayerCallback;interfaceIMyAidlInterface{voidplay();voidpause();voidregisterCallback(IPlayerCallbackcallback);voidunregisterCallback(IPlayerCallbackcallback);}3ServerprivateRemoteCallbackListIPlayerCallbackcallbackListnewRemoteCallbackList();privateStringsongName;privatebooleanisPlayingfalse;privatefinalIMyAidlInterface.StubbindernewIMyAidlInterface.Stub(){Overridepublicvoidplay()throwsRemoteException{if(isPlaying)return;isPlayingtrue;booleanisSongNameChangedfalse;if(songNamenull){songNameServer Song;isSongNameChangedtrue;}intncallbackList.beginBroadcast();for(inti0;in;i){IPlayerCallbackcallbackcallbackList.getBroadcastItem(i);callback.onPlayStateChanged(isPlaying);if(isSongNameChanged)callback.onSongChanged(songName);}callbackList.finishBroadcast();}Overridepublicvoidpause()throwsRemoteException{if(!isPlaying)return;isPlayingfalse;intncallbackList.beginBroadcast();for(inti0;in;i){IPlayerCallbackcallbackcallbackList.getBroadcastItem(i);callback.onPlayStateChanged(isPlaying);}callbackList.finishBroadcast();}OverridepublicvoidregisterCallback(IPlayerCallbackcallback)throwsRemoteException{callbackList.register(callback);}OverridepublicvoidunregisterCallback(IPlayerCallbackcallback)throwsRemoteException{callbackList.unregister(callback);}};4Clienttry{myAidlInterface.play();Log.i(TAG,play method success);}catch(RemoteExceptione){e.printStackTrace();Log.e(TAG,play method error: e.getMessage());}try{myAidlInterface.pause();Log.i(TAG,pause method success);}catch(RemoteExceptione){e.printStackTrace();Log.e(TAG,pause method error: e.getMessage());}try{myAidlInterface.registerCallback(newIPlayerCallback.Stub(){OverridepublicvoidonSongChanged(StringsongName)throwsRemoteException{Log.i(TAG,now thread: Thread.currentThread().getName());Log.i(TAG,onSongChanged: songName);}OverridepublicvoidonPlayStateChanged(booleanisPlaying)throwsRemoteException{Log.i(TAG,now thread: Thread.currentThread().getName());Log.i(TAG,onPlayStateChanged: isPlaying);}});Log.i(TAG,registerCallback method success);}catch(RemoteExceptione){e.printStackTrace();Log.e(TAG,registerCallback method error: e.getMessage());}try{myAidlInterface.unregisterCallback();Log.i(TAG,unregisterCallback method success);}catch(RemoteExceptione){e.printStackTrace();Log.e(TAG,unregisterCallback method error: e.getMessage());}5Test先调用 registerCallback 方法输出结果如下registerCallback method success再调用 play 方法输出结果如下now thread: main onPlayStateChanged: true now thread: main onSongChanged: Server Song play method success再调用 pause 方法输出结果如下now thread: main onPlayStateChanged: false pause method success最后调用 unregisterCallback 方法输出结果如下unregisterCallback method success三、AIDL 安全校验需求引入默认情况下任何知道 AIDL 接口的应用都能绑定服务并调用方法这可能导致数据泄露和恶意调用1、权限校验1ServerAndroidManifest.xml定义权限permissionandroid:namecom.my.ACCESS_TEST_SERVICEandroid:protectionLevelnormal/在 Binder 方法中校验权限intresultcheckCallingPermission(com.my.ACCESS_TEST_SERVICE);Log.i(TAG,权限检查结果: result);if(resultPackageManager.PERMISSION_DENIED){Log.i(TAG,权限拒绝);thrownewSecurityException(权限拒绝);}Log.i(TAG,权限通过);// 执行其他业务逻辑2ClientAndroidManifest.xml声明权限uses-permissionandroid:namecom.my.ACCESS_TEST_SERVICE/2、UID / PID 校验Server在 Binder 方法中校验 UID / PIDintcallingUidBinder.getCallingUid();if(callingUid!1000callingUid!1001){thrownewSecurityException(无权调用);}// 执行其他业务逻辑3、包名白名单校验Server在 Binder 方法中校验包名白名单privatestaticfinalListStringALLOWED_PACKAGESArrays.asList(com.my.server,com.my.client);privatebooleanallowedPackagesCheck(){intcallingUidBinder.getCallingUid();String[]packagesgetPackageManager().getPackagesForUid(callingUid);if(packages!null){for(Stringpkg:packages){Log.i(TAG,package: pkg);if(ALLOWED_PACKAGES.contains(pkg)){returntrue;}}}returnfalse;}if(!allowedPackagesCheck()){Log.i(TAG,调用者未被授权);thrownewSecurityException(调用者未被授权);}Log.i(TAG,调用者已被授权);// 执行其他业务逻辑四、protectionLevel补充学习protectionLevel 是 Android 权限系统中定义权限风险等级的属性normal普通级别安装时自动授予无需用户确认dangerous危险级别运行时需用户明确授权signature签名级别只有相同签名的应用才能获得权限安装时自动授予signatureOrSystem签名或系统级别只有相同签名的应用才能获得权限或者位于 Android 系统映像的专用文件夹中的应用才能获得权限在 API 级别 23 中已废弃是signature|privileged的旧同义词建议使用 signature 代替参考文档 1https://developer.android.google.cn/guide/topics/manifest/permission-element?hlzh-cn参考文档 2https://developer.android.google.cn/reference/android/R.attr#protectionLevel

相关新闻

在 Android Studio 中,新建 AIDL 文件按钮是灰色

在 Android Studio 中,新建 AIDL 文件按钮是灰色

在 Android Studio 中,新建 AIDL 文件按钮是灰色并出现如下提示信息 AIDL File (Requires setting the buildFeatures.aidl to true in the Gradle build files)问题原因 这个提示信息表示未在 Gradle 中开启 AIDL 支持 处理策略 在模块级 build.gradle 文件中&…

2026/5/17 6:43:45 阅读更多 →
移动硬盘被system占用无法弹出

移动硬盘被system占用无法弹出

以管理员身份打开cmd,依次执行下方命令再弹出即可。1.打开系统自带的磁盘工具diskpart2.列出所有磁盘,看容量找到移动硬盘编号(如 Disk 2)list disk3.替换为你的移动硬盘编号select disk 24.强制脱机offline disk5.重新联机online…

2026/5/17 6:43:44 阅读更多 →
东南亚海外仓人员管理痛点:本土员工难管?这套海外仓WMS帮你规范化

东南亚海外仓人员管理痛点:本土员工难管?这套海外仓WMS帮你规范化

做东南亚三方海外仓,人员管理是一大难题。东南亚本土员工流动性大、责任心不强、专业能力不足,加上仓库运营环节多、流程杂,人员管理混乱,导致工作效率低、出错率高,人工成本居高不下,严重影响仓库的正常运…

2026/7/3 5:48:43 阅读更多 →

最新新闻

猫抓浏览器插件:你的终极网页资源嗅探与下载解决方案

猫抓浏览器插件:你的终极网页资源嗅探与下载解决方案

猫抓浏览器插件:你的终极网页资源嗅探与下载解决方案 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 在数字内容无处不在的今天&#x…

2026/7/3 19:00:51 阅读更多 →
从数据分布角度理解:为什么不同任务要用不同的损失函数?

从数据分布角度理解:为什么不同任务要用不同的损失函数?

从数据分布角度理解:为什么不同任务要用不同的损失函数? 一、先说清楚:损失函数到底是什么? 在机器学习里,我们可以先把模型想象成一个“会猜答案的机器”。 给它一个输入,比如一张图片、一段文字、一个学生的学习时长,它会输出一个预测结果。 比如: 输入:学习时间…

2026/7/3 18:58:50 阅读更多 →
三重降压转换方案在嵌入式系统中的应用与优化

三重降压转换方案在嵌入式系统中的应用与优化

1. 为什么需要三重降压转换方案在嵌入式系统和工业控制领域,多电压轨供电已经成为标配需求。以典型的ARM Cortex-M4应用为例,核心处理器需要1.2V供电,外设接口需要3.3V,而模拟电路部分则可能需要1.8V。传统方案采用多个独立DC-DC转…

2026/7/3 18:58:50 阅读更多 →
ppt模板_0139_黑蝙蝠侠

ppt模板_0139_黑蝙蝠侠

PPT模板分享

2026/7/3 18:56:50 阅读更多 →
LLM安全护栏工程实战2026:多层防御体系下的Prompt注入、越狱与内容审核

LLM安全护栏工程实战2026:多层防御体系下的Prompt注入、越狱与内容审核

引言 2026年,当AI Agent被部署到金融交易、医疗诊断、法律咨询等关键领域时,安全问题从"锦上添花"变成了"生死攸关"。AAAI 2026上,LLM安全相关的论文数量同比增长了300%。Prompt注入已被OWASP列为LLM应用十大安全风险之首…

2026/7/3 18:56:50 阅读更多 →
为什么遇到分式可以“颠倒”过来算?

为什么遇到分式可以“颠倒”过来算?

为什么可以“颠倒”过来算? 这种“颠倒”操作看起来有些不可思议,但它背后有非常严密的数学逻辑支撑。 简单来说:“颠倒”其实是在利用极限的倒数性质。只要极限不为 0,我们就可以把整个算式翻转过来算,最后再把结果翻…

2026/7/3 18:52:49 阅读更多 →

日新闻

Nginx防御TLS重协商攻击实战:从原理到配置与监控

Nginx防御TLS重协商攻击实战:从原理到配置与监控

1. 项目概述:为什么TLS重协商攻击至今仍需警惕十多年前的CVE-2011-1473,一个关于TLS/SSL协议重协商机制的漏洞,现在提起来还有必要吗?很多运维和开发朋友可能会觉得,这都老掉牙了,现代服务器和客户端不都默…

2026/7/3 0:03:59 阅读更多 →
华为防火墙双通道远程管理实战:Web与SSH配置详解

华为防火墙双通道远程管理实战:Web与SSH配置详解

1. 项目概述:为什么需要双通道远程管理防火墙?在任何一个稍具规模的企业网络里,防火墙都是那个默默守护在边界的关键角色。作为网络工程师,我们不可能每次都跑到机房,插上console线去配置它。远程管理能力,…

2026/7/3 0:03:59 阅读更多 →
AD74413R与PIC18F65K40的高精度工业数据采集方案

AD74413R与PIC18F65K40的高精度工业数据采集方案

1. 项目概述:AD74413R与PIC18F65K40的协同工作在工业自动化和精密测量领域,同时实现高精度模数转换(ADC)和数模转换(DAC)功能是许多复杂系统的核心需求。AD74413R作为一款四通道可配置模拟输入/输出器件,与PIC18F65K40微控制器的组合&#xf…

2026/7/3 0:05:59 阅读更多 →

周新闻

月新闻