Android多进程系列

  • Android 多进程通信之几个基本问题
  • Android多进程之Binder的使用
  • Android多进程之手动编写Binder类
  • Android多进程之Binder解绑监听的问题
  • Android 多进程之Messenger的使用
通过前几篇文章,我们对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);    }};
  • 为了测试,我们在服务端添加结束进程的代码
@Overridepublic 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中通过自定义权限来验证
  • 首先要自定义一个权限
            
  • 然后在Service中的onBind方法中校验
@Nullable@Overridepublic 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;}
权限校验被拒绝
  • 从上图中我们可以看到,由于我们的应用客户端没有声明服务端校验的权限,所以服务端校验不通过,我们只需要在我们的客户端添加相应的权限声明即可
权限校验通过
在onTransact方法中进行权限校验
private Binder mBinder = new BookManagerImpl(){    @Override    public List 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进程仍然会被干掉。

欢迎关注我的微信公众号,期待与你一起学习,一起交流,一起成长!


AntDream

更多相关文章

  1. ContentProvider使用与query流程分析
  2. Android访问WCF服务
  3. Android(安卓)manifest属性
  4. AndroidManifest.xml的Service元素 android:process设置
  5. MainFest.xml android
  6. android核心知识点学习资料
  7. android核心知识点学习资料
  8. Android夸进程通信机制二:Parcel 与 Parcelable
  9. Android启动过程深入解析

随机推荐

  1. Android(安卓)4.0 中的Camera
  2. Android(安卓)5种方式存储数据:
  3. android时序图 以及UML中时序图、流程图
  4. Android(安卓)Studio 低版本Gradle升级到
  5. Android点击监听事件
  6. android将线程绑定在指定CPU
  7. Flutter 的 TensorFlow Lite 插件 - tfli
  8. 你知道 Android(安卓)的 MessageQueue.Id
  9. Android开发错误Unable to execute dex:
  10. Android(安卓)Studio 无法引用org.apache