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

來源:互聯網
上載者:User

標籤:android   service   bind   binder   serviceconnection   

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

(一)、Service的生命週期

(二)、Service的自動重啟問題

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

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

    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。
    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();        }    }
    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操作了,前面講生命週期時已經有提到過的,這裡再把那個方法列一下:

        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中的服務已經簡要的分析了一下,不可能面面俱到也不會全都正確,還請大家多多指教。

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.