Android多进程之Binder的意外死亡及权限校验
Android多进程系列
通过前几篇文章,我们对Binder的使用和工作流程有了一定的了解,但是还有几个问题休要我们去解决。一个是如果服务端进程意外退出,Binder死亡,那客户端就会请求失败;还有一个就是权限校验问题,就是服务端需要校验一下客户端的身份权限,不能谁都能请求服务端的服务
Binder意外死亡的处理
给Binder设置DeathRecipient监听
- 在绑定Service服务后的onServiceConnected回调中给Binder注册死亡回调DeathRecipient
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e(TAG, "ServiceConnection-->"+ System.currentTimeMillis());
IBookManager bookManager = BookManagerImpl.asInterface(iBinder);
mRemoteBookManager = bookManager;
try {
//注册死亡回调
iBinder.linkToDeath(mDeathRecipient,0);
...
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e(TAG, "onServiceDisconnected-->binder died");
}
};
- 在DeathRecipient中相应的处理,比如重新连接服务端
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Log.e(TAG, "mDeathRecipient-->binderDied-->");
if (mRemoteBookManager == null) {
return;
}
mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
mRemoteBookManager = null;
//Binder死亡,重新绑定服务
Log.e(TAG, "mDeathRecipient-->bindService");
Intent intent = new Intent(MainActivity.this, BookManagerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
};
- 为了测试,我们在服务端添加结束进程的代码
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate-->"+ System.currentTimeMillis());
new Thread(new ServiceWorker()).start();
}
private class ServiceWorker implements Runnable {
@Override
public void run() {
while (!mIsServiceDestoryed.get()) {
try {
Thread.sleep(5000);
}catch (InterruptedException e) {
e.printStackTrace();
}
int bookId = mBookList.size() + 1;
if (bookId == 8) {
//结束当前进程,测试Binder死亡回调
android.os.Process.killProcess(android.os.Process.myPid());
return;
}
...
}
}
}
- 测试效果
从上面的测试我们可以看到客户端在服务端进程意外退出后,通过重新绑定服务又把服务端进程启动了。此外,我们还可以在ServiceConnection的onServiceDisconnected方法中处理服务端进程意外退出的情况,方法是一样的,就不测试了。2种方法的区别就在于onServiceDisconnected方法在客户端的UI线程中被回调,而binderDied方法在客户端的Binder线程池中被回调
权限验证
在onBind中通过自定义权限来验证
- 首先要自定义一个权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxq2dream.android_ipc">
<permission
android:name="com.xxq2dream.permission.ACCESS_BOOK_SERVICE"
android:protectionLevel="normal"/>
</manifest>
- 然后在Service中的onBind方法中校验
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind-->"+ System.currentTimeMillis());
int check = checkCallingOrSelfPermission("com.xxq2dream.permission.ACCESS_BOOK_SERVICE");
if (check == PackageManager.PERMISSION_DENIED) {
Log.e(TAG, "PERMISSION_DENIED");
return null;
}
Log.e(TAG, "PERMISSION_GRANTED");
return mBinder;
}
- 从上图中我们可以看到,由于我们的应用客户端没有声明服务端校验的权限,所以服务端校验不通过,我们只需要在我们的客户端添加相应的权限声明即可
<uses-permission android:name="com.xxq2dream.permission.ACCESS_BOOK_SERVICE"/>
在onTransact方法中进行权限校验
private Binder mBinder = new BookManagerImpl(){
@Override
public List<Book> getBookList() throws RemoteException {
Log.e(TAG, "getBookList-->"+ System.currentTimeMillis());
return mBookList;
}
...
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
int check = checkCallingOrSelfPermission("com.xxq2dream.permission.ACCESS_BOOK_SERVICE");
if (check == PackageManager.PERMISSION_DENIED) {
Log.e(TAG, "PERMISSION_DENIED");
return false;
}
String packageName = null;
//获取客户端包名
String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
if (packages != null && packages.length > 0) {
packageName = packages[0];
}
//校验包名
if (!packageName.startsWith("com.xxq2dream")) {
return false;
}
Log.e(TAG, "PERMISSION_GRANTED");
return super.onTransact(code, data, reply,flags);
}
};
结语
- Binder的一个很好的应用就是推送消息和保活。比如我们可以创建一个Service运行在一个独立的进程中,然后和我们的应用进程中的一个Service绑定。独立进程的Service每隔一定的时间向我们的服务端请求查看是否有新的消息,有的话就拉取新的消息,然后通知给应用进程的Service,执行弹出通知之类的操作。应用程序退出后,我们的Service进程还是存活的,这样就可以一直接收消息。当然,如果用户一键清理或是直接结束应用的话,我们的Service进程仍然会被干掉。
欢迎关注我的微信公众号,期待与你一起学习,一起交流,一起成长!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
Android组件化开发实践(三):组件开发规范
不以规矩,不成方圆。特别是多人协作开发时,如果没有统一的开发规范,势必会造成各种混乱。在实际开发中,常常会碰到的问题有: 引入的某个第三方库版本冲突; 不同组件里同名资源文件被覆盖; APP壳工程打包时AndroidManifest.xml合并发生错误; 往往单独的组件工程运行良好,但是集成到壳工程时就是不行,所以我们必须要严格遵守规范,尽可能减少这种问题的出现。以下是我在实际开发中采用的一些步骤规范: 1. 新建组件工程 我的每个组件都是一个单独的小工程,而不是像其他的方案那样,只有一个主工程,每个组件只是工程里的一个module,这种方式实质上还是单一工程模式。这样在代码权限管控,组件职责划分上就很明确了,每个工程是一个组件,每个组件有一个owner(也就是负责人)。 打开Android Studio(目前只采用该IDE来开发,其他IDE不考虑),点击"File -> New -> New Project...",全新创建一个新的工程,工程名字以及包名根据实际业务来定。 2. 新建module 在刚创建好的工程中,点击"File -> New -> New ...
-
下一篇
font-face 详解
版权声明:本文首发 http://asing1elife.com ,转载请注明出处。 https://blog.csdn.net/asing1elife/article/details/82862181 @font-face 是 CSS3 的一个模块,其主要作用是可将自定义字体嵌入到网页中,让网页字体的运用不只是限定在 Web 安全字体中 更多精彩 更多技术博客,请移步 asing1elife’s blog 语法 webFontName: 引入的自定义字体名称,将会为指定的元素添加 font-family: webFontName source: 字体路径 format: 字体格式,用于帮助浏览器识别,truetype opentype truetype-aat embedded-opentype svg … weight: 字体是否粗体 style: 字体样式 @font-face { font-family: <webFontName>; src: <source> [<format>][,<source> [<format&g...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS7,8上快速安装Gitea,搭建Git服务器