Android multi-process series

  • Several basic problems of Android multi-process communication
  • Binder for Android multiprocess
  • Android multiprocess manual Binder class
  • Android multiprocess Binder unbinding listener issues
  • Android Multiprocess Messenger
Through the previous articles, we have gained a certain understanding of Binder usage and workflow, but there are still several problems to be solved. One is that if the server process exits unexpectedly and Binder dies, the client will fail. There is also a permission verification problem, that is, the server needs to verify the identity of the client, not everyone can request the service of the server

Disposal of Binder accidental death

DeathRecipient listener for Binder
  • Register the death callback DeathRecipient with Binder in the onServiceConnected callback
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 {// Register the death callback ibinder.linktoDeath (mDeathRecipient,0); . } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { Log.e(TAG,"onServiceDisconnected-->binder died"); }};Copy the code
  • Appropriate processing in DeathRecipient, such as reconnecting to the server
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; //Bind service log.e (TAG,"mDeathRecipient-->bindService");
        Intent intent = new Intent(MainActivity.this, BookManagerService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE); }};Copy the code
  • To test this, we add terminating process code on the server side
@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) {/ / end of the current Process, testing Binder death callback android. The OS. The Process, killProcess (android. OS. Process. MyPid ());return; }... }}}Copy the code
  • The test results

From the above test, we can see that the client started the server process again by rebinding the service after the server process unexpectedly quit. In addition, we can handle the unexpected exit of the server process in the onServiceDisconnected method of ServiceConnection, which is the same and will not be tested. The difference between the two methods is that the onServiceDisconnected method is called back in the client’s UI thread, while the binderDied method is called back in the client’s Binder thread pool

Permission to verify

Verify with custom permissions in onBind
  • Start by customizing a permission
<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>
Copy the code
  • It is then checked in the onBind method of the Service
@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;
}
Copy the code

  • As can be seen from the above figure, the server verification fails because our application client does not declare the permission of the server verification, so we just need to add the corresponding permission declaration to our client
<uses-permission android:name="com.xxq2dream.permission.ACCESS_BOOK_SERVICE"/>

Copy the code

Verify permissions in the onTransact method
private Binder mBinder = new BookManagerImpl(){
    @Override
    public List<Book> getBookList() throws RemoteException {
        Log.e(TAG, "getBookList-->"+ System.currentTimeMillis());
        returnmBookList; }... @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]; } // Verify package nameif(! packageName.startsWith("com.xxq2dream")) {
            return false;
        }
        Log.e(TAG, "PERMISSION_GRANTED");
        returnsuper.onTransact(code, data, reply,flags); }};Copy the code
conclusion
  • A good use of Binder is push messaging and retention. For example, we can create a Service to run in a separate process and bind it to a Service in our application process. The Service of an independent process requests our server at regular intervals to check whether there are any new messages. If there are, it pulls the new messages and notifies the Service of the application process to perform operations such as pop-up notifications. After the application exits, our Service process remains alive, so it can always receive messages. Of course, our Service process would still be killed if the user cleaned up or ended the application with a single click.

Welcome to pay attention to my wechat public number, looking forward to learning, communicating and growing together with you!Copy the code