AndroidService的綁定過程_第1頁
AndroidService的綁定過程_第2頁
AndroidService的綁定過程_第3頁
已閱讀5頁,還剩7頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、Android Service的綁定過程通常我們使用 Service都要和它通信,當(dāng)想要與 Service通信的時候,那么 Service要處于綁 定狀態(tài)的。然后客戶端可以拿到一個Binder與效勞端進行通信,這個過程是很自然的。那你真的了解過 Service的綁定過程嗎?為什么可以是 Binder和Service通信?同樣的先看一張圖大致了解一下,灰色背景框起來的是同一個類的方法,如下:Service的律宦過沖Design by xuyinhuan我們知道調(diào)用 Co ntext的bin dService方法即可綁定一個Service,而Con textlmpl是Con text的實現(xiàn)類。那接

2、下來就從源碼的角度分析Service的綁定過程。當(dāng)然是從 Contextlmpl的bindService方法開始,如下:Overridepublic boolea n bin dService(I ntent service, ServiceC onnection conn,int flags) warnl fCalli ngFromSystemProcess();return bin dServiceCom mon( service, conn, flags, mMai nThread.getHa ndler(), Process.myUserHa ndle();在 bindService

3、方法中又會轉(zhuǎn)到 bindServiceCommon 方法,將 Intent,ServiceConnection 對象 傳進。那就看看bindServiceCommon方法的實現(xiàn)。private boolea n bi ndServiceCom mon (I ntent service, ServiceC onn ecti on conn, int flags, Han dler han dler, UserHa ndle user) IServiceConnection sd;if (conn = null) throw new IllegalArgumentException("c

4、onnection is null");if (mPackageInfo != null) sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); else throw new RuntimeException("Not supported in system context");validateServiceIntent(service);try IBinder token = getActivityToken();if (token = null &

5、;& (flags&BIND_AUTO_CREATE) = 0 && mPackageInfo != null&& mPackageInfo.getApplicationInfo().targetSdkVersion< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) flags |= BIND_WAIVE_PRIORITY;service.prepareToLeaveProcess(this);int res = ActivityManagerNative.getDefault().bi

6、ndService(mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver(), sd, flags, getOpPackageName(), user.getIdentifier();if (res < 0) throw new SecurityException("Not allowed to bind to service " + service);return res != 0; catch (

7、RemoteException e) throw e.rethrowFromSystemServer();在上述代碼中,調(diào)用了 mPackageInfo ( LoadedApk 對象)的 getServiceDispatcher 方法。從 getServiceDispatcher 方法的名字可以看出是獲取一個“效勞分發(fā)者 。其實是根據(jù)這個“服 務(wù)分發(fā)者獲取到一個 Binder 對象的。那現(xiàn)在就看到 getServiceDispatcher 方法的實現(xiàn)。public final IServiceConnection getServiceDispatcher(ServiceConnection c

8、,Context context, Handler handler, int flags) synchronized (mServices) LoadedApk.ServiceDispatcher sd = null;ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);if (map != null) sd = map.get(c);if (sd = null) sd = new ServiceDispatcher(c, context, handler, fla

9、gs);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();從 getServiceDispatcher 方法的實現(xiàn)可以知道, ServiceConnection 和 ServiceDispatcher 構(gòu)成了 映射關(guān)系。當(dāng)存儲集合不為空的時

10、候,根據(jù)傳進的key,也就是ServiceConnection,來取出對應(yīng)的 ServiceDispatcher 對象。當(dāng)取出 ServiceDispatcher 對象后,最后一行代碼是關(guān)鍵,return sd.getIServiceConnection();調(diào)用了 ServiceDispatcher 對象的 getIServiceConnection 方法。這個方法肯定是獲取一個 IServiceConnection 的。IServiceConnection getIServiceConnection() return mIServiceConnection;那 么 mIServiceCon

11、nection 是 什 么 ? 現(xiàn) 在 就 可 以 來 看 下 ServiceDispatcher 類 了 。 ServiceDispatcher 是 LoadedApk 的內(nèi)部類,里面圭寸裝了 InnerConnection 和 ServiceConnection。 如下:static final class ServiceDispatcher private final ServiceDispatcher.InnerConnection mIServiceConnection;private final ServiceConnection mConnection;private final

12、 Context mContext;private final Handler mActivityThread;private final ServiceConnectionLeaked mLocation;private final int mFlags;private RuntimeException mUnbindLocation;private boolean mForgotten;private static class ConnectionInfo IBinder binder;IBinder.DeathRecipient deathMonitor;private static c

13、lass InnerConnection extends IServiceConnection.Stub final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;InnerConnection(LoadedApk.ServiceDispatcher sd) mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); public void connected(ComponentName name, IBinder service) t

14、hrows 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>();ServiceDispatc

15、her(ServiceConnection conn,Context context, Handler activityThread, int flags) mIServiceConnection = new InnerConnection(this); mConnection = conn; mContext = context;mActivityThread = activityThread; mLocation = new ServiceConnectionLeaked(null); mLocation.fillInStackTrace();mFlags = flags;/代碼省略先看到

16、 ServiceDispatcher 的構(gòu)造方法, 一個 ServiceDispatcher 關(guān)聯(lián)一個 InnerConnection 對象。 而 InnerConnection 呢?,它是一個 Binder ,有一個很重要的 connected 方法。至于為什么要 用 Binder ,因為與 Service 通信可能是跨進程的。好,到了這里先總結(jié)一下:調(diào)用 bindService 方法綁定效勞,會轉(zhuǎn)到 bindServiceCommon 方 法。在 bindServiceCommon 方法中,會調(diào)用 LoadedApk 的 getServiceDispatcher 方法,并將 Service

17、Connection 傳進, 根據(jù)這個 ServiceConnection 取出與其映射的 ServiceDispatcher 對 象,最后調(diào)用這個 ServiceDispatcher 對象的 getIServiceConnection 方法獲取與其關(guān)聯(lián)的 InnerConnection 對象并返回。簡單點理解就是用 ServiceConnection 換來了 InnerConnection ?,F(xiàn) 在 回 到 bindServiceCommon 方 法 , 可 以 看 到 綁 定 Service 的 過 程 會 轉(zhuǎn) 到 ActivityManagerNative.getDefault() 的

18、bindService 方 法 , 其 實 從 拋 出 的 異 常 類 型 RemoteException 也可以知道與 Service 通信可能是跨進程的,這個是很好理解的。而 ActivityManagerNative.getDefault() 是 ActivityManagerService , 那 么 繼 續(xù) 跟 進 ActivityManagerService 的 bindService 方法即可,如下:public int bindService(IApplicationThread caller, IBinder token, Intent service, String res

19、olvedType, IServiceConnection connection, int flags, String callingPackage, int userId) throws TransactionTooLargeException enforceNotIsolatedCaller("bindService");/ Refuse possible leaked file descriptorsif (service != null && service.hasFileDescriptors() = true) throw new Illegal

20、ArgumentException("File descriptors passed in Intent");if (callingPackage = null) throw new IllegalArgumentException("callingPackage cannot be null");synchronized(this) return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, callingPackage, use

21、rId);在上述代碼中,綁定 Service 的過程轉(zhuǎn)到 ActiveServices 的 bindServiceLocked 方法,那就跟 進 ActiveServices 的 bindServiceLocked 方法瞧瞧。如下:int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, final IServiceConnection connection, int flags, String callingPackage, final int us

22、erId) throws TransactionTooLargeException /代碼省略ConnectionRecord c = new ConnectionRecord(b, activity,connection, flags, clientLabel, clientIntent);IBinder binder = connection.asBinder();ArrayList<ConnectionRecord> clist = s.connections.get(binder);if (clist = null) clist = new ArrayList<Con

23、nectionRecord>();s.connections.put(binder, clist);clist.add(c);/代碼省略if (flags&Context.BIND_AUTO_CREATE) != 0) s.lastActivity = SystemClock.uptimeMillis();if (bringUpServiceLocked(s, service.getFlags(), callerFg, false, permissionsReviewRequired) != null) return 0;/代碼省略return 1;將 connection 對象

24、封裝在 ConnectionRecord 中,這里的 connection 就是上面提到的 InnerConnection 對象。這一步很重要的。然后調(diào)用了 bringUpServiceLocked 方法,那么就探探這個 bringUpServiceLocked 方法,private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired) throws Transactio

25、nTooLargeException /代碼省略if (app != null && app.thread != null) try app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);realStartServiceLocked(r, app, execInFg);return null; catch (TransactionTooLargeException e) throw e; catch (RemoteException e) Slog.w(TAG , &quo

26、t;Exception when starting service " + r.shortName, e);/ If a dead object exception was thrown - fall through to/ restart the application./代碼省略return null;可以看到調(diào)用了 realStartServiceLocked 方法,真正去啟動 Service 了。那么跟進 realStartServiceLocked 方法探探,如下:private final void realStartServiceLocked(ServiceRecord

27、 r,ProcessRecord app, boolean execInFg) throws RemoteException /代碼省略app.thread.scheduleCreateService(r, r.serviceInfo, mAm patibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState);r.postNotification(); created = true;/代碼省略requestServiceBindingsLocked(r, execInFg);updateServic

28、eClientActivitiesLocked(app, null, true);/ If the service is in the started state, and there are no/ pending arguments, then fake up one so its onStartCommand() will/ be called.if (r.startRequested && r.callStart && r.pendingStarts.size() = 0) r.pendingStarts.add(new ServiceRecord.St

29、artItem(r, false, r.makeNextStartId(), null, null);sendServiceArgsLocked(r, execInFg, true);/代碼省略這里會調(diào)用 app.thread的scheduleCreateService方法去創(chuàng)立一個 Service,然后會回調(diào) Service 的生命周期方法,然而綁定 Service 呢?在上述代碼中, 找到一個 requestServiceBindingsLocked 方法, 從名字看是請求綁定效勞的意 思,那么就是它沒錯了。private final void requestServiceBindings

30、Locked(ServiceRecord r, boolean execInFg)throws TransactionTooLargeException for (int i=r.bindings.size()-1; i>=0; i-) IntentBindRecord ibr = r.bindings.valueAt(i);if (!requestServiceBindingLocked(r, ibr, execInFg, false) break;咦,我再按住 Ctrl+ 鼠標(biāo)左鍵,點進去 requestServiceBindingLocked 方法。如下:private final

31、 boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,boolean execInFg, boolean rebind) throws TransactionTooLargeException if (r.app = null | r.app.thread = null) / If service is not currently running, can't yet bind.return false;if (!i.requested | rebind) && i.apps.s

32、ize() > 0) try bumpServiceExecutingLocked(r, execInFg, "bind"); r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); r.app.thread.scheduleBindService(r, ent.getIntent(), rebind,r.app.repProcState);if (!rebind) i.requested = true;i.hasBound = true;i.doRebind = false;/

33、代碼省略return true;r.app.thread 調(diào)用了 scheduleBindService 方法來綁定效勞, 而 r.app.thread 是 ApplicationThread , 現(xiàn)在關(guān)注到 ApplicationThread 即可, scheduleBindService 方法如下:public final void scheduleBindService(IBinder token, Intent intent,boolean rebind, int processState) updateProcessState(processState, false);BindSer

34、viceData s = new BindServiceData();s.token = token;ent = intent;s.rebind = rebind;if (DEBUG_SERVICE)Slog.v(TAG , "scheduleBindService token=" + token + " intent=" + intent + " uid="+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid();sendMessage(H.

35、BIND_SERVICE, s);封裝了待綁定的 Service 的信息,并發(fā)送了一個消息給主線程,public void handleMessage(Message msg) if (DEBUG_MESSAGES) Slog.v(TAG , ">>> handling: " + codeToString(msg.what);switch (msg.what) /代碼省略case BIND_SERVICE:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");

36、handleBindService(BindServiceData)ms );Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;/代碼省略調(diào)用了 handleBindService 方法,即將綁定完成啦。private void handleBindService(BindServiceData data) Service s = mServices.get(data.token);if (DEBUG_SERVICE)Slog.v(TAG , "handleBindService s=" + s + "

37、rebind=" + data.rebind);if (s != null) try ent.setExtrasClassLoader(s.getClassLoader(); ent.prepareToEnterProcess();try if (!data.rebind) IBinder binder = s.onBind(ent);ActivityManagerNative.getDefault().publishService(data.token, ent, binder); else s.onRebind(da

38、ent); ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); ensureJitEnabled(); catch (RemoteException ex) throw ex.rethrowFromSystemServer(); catch (Exception e) if (!mInstrumentation.onException(s, e) throw new RuntimeException( "Unable

39、to bind to service " + s + " with " + ent + ": " + e.toString(), e);根據(jù) token 獲取到 Service ,然后 Service 回調(diào) onBind 方法。結(jié)束了?可是 onBind 方法返回了一個 binder 是用來干嘛的?我們再看看 ActivityManagerNative.getDefault() 調(diào)用了 publishService 方法做了什么工作,此 時又回到了 ActivityManagerService 。public void publ

40、ishService(IBinder token, Intent intent, IBinder service) / Refuse possible leaked file descriptorsif (intent != null && intent.hasFileDescriptors() = true) throw new IllegalArgumentException("File descriptors passed in Intent");synchronized(this) if (!(token instanceof ServiceReco

41、rd) throw new IllegalArgumentException("Invalid service token"); mServices.publishServiceLocked(ServiceRecord)token, intent, service);又會交給 ActiveServices 處理,轉(zhuǎn)到了 publishServiceLocked 方法,那看到 ActiveServices 的 publishServiceLocked 方法,void publishServiceLocked(ServiceRecord r, Intent intent, IB

42、inder service) final long origId = Binder.clearCallingIdentity();try if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r+ " " + intent + ": " + service);if (r != null) Intent.FilterComparison filter= new Intent.FilterComparison(intent); IntentBindRecord b = r.bindi

43、ngs.get(filter);if (b != null && !b.received) b.binder = service; b.requested = true; b.received = true;for (int conni=r.connections.size()-1; conni>=0; conni-) ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni); for (int i=0; i<clist.size(); i+) ConnectionRecord c

44、= clist.get(i);if (!filter.equals(ent) if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Not publishing to: " + c);if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Bound intent: " + ent);if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Published intent: "

45、+ intent); continue;if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " +c);try c.conn.connected(, service); /代碼省略c.conn 是什么? 它是一個 InnerConnection 對象,對,就是那個那個 Binder ,上面也貼出了 代碼,在 ActiveServices 的 bindServiceLocked 方法中, InnerConnection 對象被封裝在 ConnectionRecord 中。那么現(xiàn)在它調(diào)用了 connected

46、 方法,就很好理解了。InnerConnection 的 connected 方法如下:public void connected(ComponentName name, IBinder service) throws RemoteException LoadedApk.ServiceDispatcher sd = mDispatcher.get();if (sd != null) sd.connected(name, service);會調(diào)用 ServiceDispatcher 的 connected 方法,如下public void connected(ComponentName name

47、, IBinder service) if (mActivityThread != null) mActivityThread.post(new RunConnection(name, service, 0); else doConnected(name, service);從而 ActivityThread 會投遞一個消息到主線程,此時就解決了跨進程通信。 那么你應(yīng)該猜到了 RunConnection 一定有在主線程回調(diào)的 onServiceConnected 方法,private final class RunConnection implements Runnable RunConnec

48、tion(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);final ComponentName mName; final IBinder mService;final int mCommand;咦,還不出現(xiàn)?繼續(xù)跟進 doConnected 方法,public void doConnected(Comp

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論