天天看點

Android的服務(Service)(三)Service用戶端的綁定與跨程序

http://blog.csdn.net/hehui1860/article/details/41743625

繼續上篇的分析,接下來是第三個問題”Service與其用戶端的綁定如何實作,即跨程序調用問題“

(一)、Service的生命周期

(二)、Service的自動重新開機問題

(三)、Service與其用戶端的綁定如何實作,即跨程序調用問題。

服務于用戶端的綁定通過binder來實作的,就是用戶端去bind服務。來看看ContextImpl的bindServiceCommon方法

[java]  view plain copy

  1. private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,  
  2.         UserHandle user) {  
  3.     IServiceConnection sd;  
  4.     if (mPackageInfo != null) {  
  5.         sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),  
  6.                 mMainThread.getHandler(), flags);  
  7.     }  
  8.     try {  
  9.         IBinder token = getActivityToken();  
  10.         if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null  
  11.                 && mPackageInfo.getApplicationInfo().targetSdkVersion  
  12.                 < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {  
  13.             flags |= BIND_WAIVE_PRIORITY;  
  14.         }  
  15.         service.prepareToLeaveProcess();  
  16.         int res = ActivityManagerNative.getDefault().bindService(  
  17.             mMainThread.getApplicationThread(), getActivityToken(),  
  18.             service, service.resolveTypeIfNeeded(getContentResolver()),  
  19.             sd, flags, user.getIdentifier());  
  20.         if (res < 0) {  
  21.             throw new SecurityException(  
  22.                     "Not allowed to bind to service " + service);  
  23.         }  
  24.         return res != 0;  
  25.     }  
  26. }  

然後會去LoadedApk.java裡面會建立用于跨程序連接配接的binder對象,就是一個ServiceDispatcher的InnerConnection。

[java]  view plain copy

Android的服務(Service)(三)Service用戶端的綁定與跨程式
Android的服務(Service)(三)Service用戶端的綁定與跨程式
  1. public final IServiceConnection getServiceDispatcher(ServiceConnection c,  
  2.         Context context, Handler handler, int flags) {  
  3.     synchronized (mServices) {  
  4.         LoadedApk.ServiceDispatcher sd = null;  
  5.         //這裡用一個map将所有的連接配接記錄都儲存起來了  
  6.         ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);  
  7.         if (map != null) {  
  8.             sd = map.get(c);  
  9.         }  
  10.         if (sd == null) {  
  11.             sd = new ServiceDispatcher(c, context, handler, flags);  
  12.             if (map == null) {  
  13.                 map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();  
  14.                 mServices.put(context, map);  
  15.             }  
  16.             map.put(c, sd);  
  17.         } else {  
  18.             sd.validate(context, handler);  
  19.         }  
  20.         return sd.getIServiceConnection();  
  21.     }  
  22. }  

[java]  view plain copy

Android的服務(Service)(三)Service用戶端的綁定與跨程式
Android的服務(Service)(三)Service用戶端的綁定與跨程式
  1.     static final class ServiceDispatcher {  
  2.         private final ServiceDispatcher.InnerConnection mIServiceConnection;  
  3.         private final ServiceConnection mConnection;  
  4.         private static class ConnectionInfo {  
  5.             IBinder binder;  
  6.             IBinder.DeathRecipient deathMonitor;  
  7.         }  
  8.         private static class InnerConnection extends IServiceConnection.Stub {  
  9.             final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;  
  10.             InnerConnection(LoadedApk.ServiceDispatcher sd) {  
  11.                 mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);  
  12.             }  
  13.             //這個方法就是在ActivityManagerService中執行綁定連結時的方法調用  
  14.             //這裡的service毫無疑問就是遠端對象執行onBind時傳回的那個咯  
  15.             //是以這裡才是服務端和用戶端傳遞一個binder對象的通道,因為這個過程涉及到兩個跨程序操作,是以這麼設計是必須也是合理的  
  16.             public void connected(ComponentName name, IBinder service) throws RemoteException {  
  17.                 LoadedApk.ServiceDispatcher sd = mDispatcher.get();  
  18.                 if (sd != null) {  
  19.                     sd.connected(name, service);  
  20.                 }  
  21.             }  
  22.         }  
  23.         private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections  
  24.             = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();  
  25.         ServiceConnection getServiceConnection() {  
  26.             return mConnection;  
  27.         }  
  28.         IServiceConnection getIServiceConnection() {  
  29.             return mIServiceConnection;  
  30.         }  
  31.         public void connected(ComponentName name, IBinder service) {  
  32.             if (mActivityThread != null) {  
  33.                 mActivityThread.post(new RunConnection(name, service, 0));  
  34.             } else {  
  35.                 doConnected(name, service);  
  36.             }  
  37.         }  
  38.         public void death(ComponentName name, IBinder service) {  
  39.             .......................  
  40.         }  
  41.         //實際執行connect  
  42.         public void doConnected(ComponentName name, IBinder service) {  
  43.             ServiceDispatcher.ConnectionInfo old;  
  44.             ServiceDispatcher.ConnectionInfo info;  
  45.             synchronized (this) {  
  46.                 if (mForgotten) {  
  47.                     // We unbound before receiving the connection; ignore  
  48.                     // any connection received.  
  49.                     return;  
  50.                 }  
  51.                 old = mActiveConnections.get(name);  
  52.                 if (old != null && old.binder == service) {  
  53.                     // Huh, already have this one.  Oh well!  
  54.                     return;  
  55.                 }  
  56.                 if (service != null) {  
  57.                     // A new service is being connected... set it all up.  
  58.                     mDied = false;  
  59.                     info = new ConnectionInfo();  
  60.                     info.binder = service;  
  61.                     info.deathMonitor = new DeathMonitor(name, service);  
  62.                     try {  
  63.                         service.linkToDeath(info.deathMonitor, 0);  
  64.                         mActiveConnections.put(name, info);  
  65.                     } catch (RemoteException e) {  
  66.                         // This service was dead before we got it...  just  
  67.                         // don't do anything with it.  
  68.                         mActiveConnections.remove(name);  
  69.                         return;  
  70.                     }  
  71.                 } else {  
  72.                     // The named service is being disconnected... clean up.  
  73.                     mActiveConnections.remove(name);  
  74.                 }  
  75.                 if (old != null) {  
  76.                     old.binder.unlinkToDeath(old.deathMonitor, 0);  
  77.                 }  
  78.             }  
  79.             // If there was an old service, it is not disconnected.  
  80.             if (old != null) {  
  81.                 mConnection.onServiceDisconnected(name);  
  82.             }  
  83.             // If there is a new service, it is now connected.  
  84.             // 眼熟了吧,這就是我們在綁定服務後擷取遠端對象代理的回調咯  
  85.             if (service != null) {  
  86.                 mConnection.onServiceConnected(name, service);  
  87.             }  
  88.         }  
  89.         public void doDeath(ComponentName name, IBinder service) {  
  90.             mConnection.onServiceDisconnected(name);  
  91.         }  
  92.         private final class RunConnection implements Runnable {  
  93.             RunConnection(ComponentName name, IBinder service, int command) {  
  94.                 mName = name;  
  95.                 mService = service;  
  96.                 mCommand = command;  
  97.             }  
  98.             public void run() {  
  99.                 if (mCommand == 0) {  
  100.                     doConnected(mName, mService);  
  101.                 } else if (mCommand == 1) {  
  102.                     doDeath(mName, mService);  
  103.                 }  
  104.             }  
  105.         }  
  106.         private final class DeathMonitor implements IBinder.DeathRecipient  
  107.         {  
  108.             DeathMonitor(ComponentName name, IBinder service) {  
  109.                 mName = name;  
  110.                 mService = service;  
  111.             }  
  112.             public void binderDied() {  
  113.                 death(mName, mService);  
  114.             }  
  115.             final ComponentName mName;  
  116.             final IBinder mService;  
  117.         }  
  118.  }  

後面就是bind操作了,前面講生命周期時已經有提到過的,這裡再把那個方法列一下:

[java]  view plain copy

Android的服務(Service)(三)Service用戶端的綁定與跨程式
Android的服務(Service)(三)Service用戶端的綁定與跨程式
  1. int bindServiceLocked(IApplicationThread caller, IBinder token,    
  2.         Intent service, String resolvedType,    
  3.         IServiceConnection connection, int flags, int userId) {    
  4.     ....................    
  5.     ServiceLookupResult res =    
  6.         retrieveServiceLocked(service, resolvedType,    
  7.                 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);    
  8.     ....................            
  9.     try {    
  10.         if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {    
  11.             if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "    
  12.                     + s);    
  13.         }    
  14.         ...................    
  15.         //bindings中添加一起綁定請求,後續requestServiceBindingsLocked()流程中處理綁定接口    
  16.         AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);    
  17.         ....................    
  18.         if ((flags&Context.BIND_AUTO_CREATE) != 0) {    
  19.             s.lastActivity = SystemClock.uptimeMillis();    
  20.             //如果攜帶的标志位中包含自動啟動,則進行建立服務的操作,代碼可以看前面,如果已經啟動了,其實是什麼操作也不幹的    
  21.             if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {    
  22.                 return 0;    
  23.             }    
  24.         }    
  25.         if (s.app != null) {    
  26.             // This could have made the service more important.    
  27.             mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client);    
  28.             mAm.updateOomAdjLocked(s.app);    
  29.         }    
  30.         if (s.app != null && b.intent.received) {    
  31.             // Service is already running, so we can immediately    
  32.             // publish the connection.    
  33.             // 如果服務已經啟動并且有綁定過了,直接傳回binder對象,這裡的conn就是前面提到的InnerConnection的代理,這裡看到了connected操作其實是由<pre name="code" class="java">                    // InnerConnection它來完成的  
  34.             try {    
  35.                 c.conn.connected(s.name, b.intent.binder);    
  36.             } catch (Exception e) {    
  37.                 Slog.w(TAG, "Failure sending service " + s.shortName    
  38.                         + " to connection " + c.conn.asBinder()    
  39.                         + " (in " + c.binding.client.processName + ")", e);    
  40.             }    
  41.             // If this is the first app connected back to this binding,    
  42.             // and the service had previously asked to be told when    
  43.             // rebound, then do so.    
  44.             // 從這裡可以看出,一般情況下,onBind隻會執行一次,除非請求doRebind    
  45.             // 這個标志位是舊的用戶端全部unbind之後自動設定上的    
  46.             if (b.intent.apps.size() == 1 && b.intent.doRebind) {    
  47.                 requestServiceBindingLocked(s, b.intent, callerFg, true);    
  48.             }    
  49.         } else if (!b.intent.requested) {    
  50.             //服務還沒有綁定者,則執行後續操作将調用到onBind操作    
  51.             requestServiceBindingLocked(s, b.intent, callerFg, false);    
  52.         }    
  53.         getServiceMap(s.userId).ensureNotStartingBackground(s);    
  54.     } finally {    
  55.         Binder.restoreCallingIdentity(origId);    
  56.     }    
  57.     return 1;    
  58. }    

大家有沒有在上面注意一個問題,InnerConnection中并沒有unConnected方法,那麼解綁的時候又是如何通過這個連接配接通道執行回調的呢?大家可以看看前面講的unBind流程中,裡面也是沒有任何地方會執行到這個操作的,它有的隻是服務端的unBind和可能執行onDestory。那麼什麼時候會執行到ServiceConnection.onServiceDisconnected,事實上隻有在遠端服務端那個binder死亡才會執行到的。這個就是通過為這個binder對象注冊一個IBinder.DeathRecipient,這是binder的死亡通知機制。這裡就不講了。

到這裡Android中的服務已經簡要的分析了一下,不可能面面俱到也不會全都正确,還請大家多多指教。