http://blog.csdn.net/hehui1860/article/details/41743625
繼續上篇的分析,接下來是第三個問題”Service與其用戶端的綁定如何實作,即跨程序調用問題“
(一)、Service的生命周期
(二)、Service的自動重新開機問題
(三)、Service與其用戶端的綁定如何實作,即跨程序調用問題。
服務于用戶端的綁定通過binder來實作的,就是用戶端去bind服務。來看看ContextImpl的bindServiceCommon方法
[java] view plain copy
- private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
- UserHandle user) {
- IServiceConnection sd;
- if (mPackageInfo != null) {
- sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
- mMainThread.getHandler(), flags);
- }
- try {
- IBinder token = getActivityToken();
- if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
- && mPackageInfo.getApplicationInfo().targetSdkVersion
- < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- flags |= BIND_WAIVE_PRIORITY;
- }
- service.prepareToLeaveProcess();
- int res = ActivityManagerNative.getDefault().bindService(
- mMainThread.getApplicationThread(), getActivityToken(),
- service, service.resolveTypeIfNeeded(getContentResolver()),
- sd, flags, user.getIdentifier());
- if (res < 0) {
- throw new SecurityException(
- "Not allowed to bind to service " + service);
- }
- return res != 0;
- }
- }
然後會去LoadedApk.java裡面會建立用于跨程序連接配接的binder對象,就是一個ServiceDispatcher的InnerConnection。
[java] view plain copy
- public final IServiceConnection getServiceDispatcher(ServiceConnection c,
- Context context, Handler handler, int flags) {
- synchronized (mServices) {
- LoadedApk.ServiceDispatcher sd = null;
- //這裡用一個map将所有的連接配接記錄都儲存起來了
- ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
- if (map != null) {
- sd = map.get(c);
- }
- if (sd == null) {
- sd = new ServiceDispatcher(c, context, handler, flags);
- if (map == null) {
- map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
- mServices.put(context, map);
- }
- map.put(c, sd);
- } else {
- sd.validate(context, handler);
- }
- return sd.getIServiceConnection();
- }
- }
[java] view plain copy
- static final class ServiceDispatcher {
- private final ServiceDispatcher.InnerConnection mIServiceConnection;
- private final ServiceConnection mConnection;
- private static class ConnectionInfo {
- IBinder binder;
- IBinder.DeathRecipient deathMonitor;
- }
- private static class InnerConnection extends IServiceConnection.Stub {
- final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
- InnerConnection(LoadedApk.ServiceDispatcher sd) {
- mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
- }
- //這個方法就是在ActivityManagerService中執行綁定連結時的方法調用
- //這裡的service毫無疑問就是遠端對象執行onBind時傳回的那個咯
- //是以這裡才是服務端和用戶端傳遞一個binder對象的通道,因為這個過程涉及到兩個跨程序操作,是以這麼設計是必須也是合理的
- public void connected(ComponentName name, IBinder service) throws RemoteException {
- LoadedApk.ServiceDispatcher sd = mDispatcher.get();
- if (sd != null) {
- sd.connected(name, service);
- }
- }
- }
- private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
- = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
- ServiceConnection getServiceConnection() {
- return mConnection;
- }
- IServiceConnection getIServiceConnection() {
- return mIServiceConnection;
- }
- public void connected(ComponentName name, IBinder service) {
- if (mActivityThread != null) {
- mActivityThread.post(new RunConnection(name, service, 0));
- } else {
- doConnected(name, service);
- }
- }
- public void death(ComponentName name, IBinder service) {
- .......................
- }
- //實際執行connect
- public void doConnected(ComponentName name, IBinder service) {
- ServiceDispatcher.ConnectionInfo old;
- ServiceDispatcher.ConnectionInfo info;
- synchronized (this) {
- if (mForgotten) {
- // We unbound before receiving the connection; ignore
- // any connection received.
- return;
- }
- old = mActiveConnections.get(name);
- if (old != null && old.binder == service) {
- // Huh, already have this one. Oh well!
- return;
- }
- if (service != null) {
- // A new service is being connected... set it all up.
- mDied = false;
- info = new ConnectionInfo();
- info.binder = service;
- info.deathMonitor = new DeathMonitor(name, service);
- try {
- service.linkToDeath(info.deathMonitor, 0);
- mActiveConnections.put(name, info);
- } catch (RemoteException e) {
- // This service was dead before we got it... just
- // don't do anything with it.
- mActiveConnections.remove(name);
- return;
- }
- } else {
- // The named service is being disconnected... clean up.
- mActiveConnections.remove(name);
- }
- if (old != null) {
- old.binder.unlinkToDeath(old.deathMonitor, 0);
- }
- }
- // If there was an old service, it is not disconnected.
- if (old != null) {
- mConnection.onServiceDisconnected(name);
- }
- // If there is a new service, it is now connected.
- // 眼熟了吧,這就是我們在綁定服務後擷取遠端對象代理的回調咯
- if (service != null) {
- mConnection.onServiceConnected(name, service);
- }
- }
- public void doDeath(ComponentName name, IBinder service) {
- mConnection.onServiceDisconnected(name);
- }
- private final class RunConnection implements Runnable {
- RunConnection(ComponentName name, IBinder service, int command) {
- mName = name;
- mService = service;
- mCommand = command;
- }
- public void run() {
- if (mCommand == 0) {
- doConnected(mName, mService);
- } else if (mCommand == 1) {
- doDeath(mName, mService);
- }
- }
- }
- private final class DeathMonitor implements IBinder.DeathRecipient
- {
- DeathMonitor(ComponentName name, IBinder service) {
- mName = name;
- mService = service;
- }
- public void binderDied() {
- death(mName, mService);
- }
- final ComponentName mName;
- final IBinder mService;
- }
- }
後面就是bind操作了,前面講生命周期時已經有提到過的,這裡再把那個方法列一下:
[java] view plain copy
- int bindServiceLocked(IApplicationThread caller, IBinder token,
- Intent service, String resolvedType,
- IServiceConnection connection, int flags, int userId) {
- ....................
- ServiceLookupResult res =
- retrieveServiceLocked(service, resolvedType,
- Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
- ....................
- try {
- if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
- if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
- + s);
- }
- ...................
- //bindings中添加一起綁定請求,後續requestServiceBindingsLocked()流程中處理綁定接口
- AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
- ....................
- if ((flags&Context.BIND_AUTO_CREATE) != 0) {
- s.lastActivity = SystemClock.uptimeMillis();
- //如果攜帶的标志位中包含自動啟動,則進行建立服務的操作,代碼可以看前面,如果已經啟動了,其實是什麼操作也不幹的
- if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
- return 0;
- }
- }
- if (s.app != null) {
- // This could have made the service more important.
- mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client);
- mAm.updateOomAdjLocked(s.app);
- }
- if (s.app != null && b.intent.received) {
- // Service is already running, so we can immediately
- // publish the connection.
- // 如果服務已經啟動并且有綁定過了,直接傳回binder對象,這裡的conn就是前面提到的InnerConnection的代理,這裡看到了connected操作其實是由<pre name="code" class="java"> // InnerConnection它來完成的
- try {
- c.conn.connected(s.name, b.intent.binder);
- } catch (Exception e) {
- Slog.w(TAG, "Failure sending service " + s.shortName
- + " to connection " + c.conn.asBinder()
- + " (in " + c.binding.client.processName + ")", e);
- }
- // If this is the first app connected back to this binding,
- // and the service had previously asked to be told when
- // rebound, then do so.
- // 從這裡可以看出,一般情況下,onBind隻會執行一次,除非請求doRebind
- // 這個标志位是舊的用戶端全部unbind之後自動設定上的
- if (b.intent.apps.size() == 1 && b.intent.doRebind) {
- requestServiceBindingLocked(s, b.intent, callerFg, true);
- }
- } else if (!b.intent.requested) {
- //服務還沒有綁定者,則執行後續操作将調用到onBind操作
- requestServiceBindingLocked(s, b.intent, callerFg, false);
- }
- getServiceMap(s.userId).ensureNotStartingBackground(s);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- return 1;
- }
大家有沒有在上面注意一個問題,InnerConnection中并沒有unConnected方法,那麼解綁的時候又是如何通過這個連接配接通道執行回調的呢?大家可以看看前面講的unBind流程中,裡面也是沒有任何地方會執行到這個操作的,它有的隻是服務端的unBind和可能執行onDestory。那麼什麼時候會執行到ServiceConnection.onServiceDisconnected,事實上隻有在遠端服務端那個binder死亡才會執行到的。這個就是通過為這個binder對象注冊一個IBinder.DeathRecipient,這是binder的死亡通知機制。這裡就不講了。
到這裡Android中的服務已經簡要的分析了一下,不可能面面俱到也不會全都正确,還請大家多多指教。