Android的服务(Service)(三)Service客户端的绑定与跨进程
生活随笔
收集整理的這篇文章主要介紹了
Android的服务(Service)(三)Service客户端的绑定与跨进程
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
繼續上篇的分析,接下來是第三個問題”Service與其客戶端的綁定如何實現,即跨進程調用問題“
(一)、Service的生命周期
(二)、Service的自動重啟問題
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 plaincopy 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 plaincopy ????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;?? ????????}?? ?}??
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;???? }????
(一)、Service的生命周期
(二)、Service的自動重啟問題
(三)、Service與其客戶端的綁定如何實現,即跨進程調用問題。
服務于客戶端的綁定通過binder來實現的,就是客戶端去bind服務。來看看ContextImpl的bindServiceCommon方法
[java]?view plaincopy
[java]?view plaincopy
后面就是bind操作了,前面講生命周期時已經有提到過的,這里再把那個方法列一下:
[java]?view plaincopy
大家有沒有在上面注意一個問題,InnerConnection中并沒有unConnected方法,那么解綁的時候又是如何通過這個連接通道執行回調的呢?大家可以看看前面講的unBind流程中,里面也是沒有任何地方會執行到這個操作的,它有的只是服務端的unBind和可能執行onDestory。那么什么時候會執行到ServiceConnection.onServiceDisconnected,事實上只有在遠程服務端那個binder死亡才會執行到的。這個就是通過為這個binder對象注冊一個IBinder.DeathRecipient,這是binder的死亡通知機制。這里就不講了。
到這里Android中的服務已經簡要的分析了一下,不可能面面俱到也不會全都正確,還請大家多多指教。
原文地址:http://blog.csdn.net/hehui1860/article/details/41743625
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Android的服务(Service)(三)Service客户端的绑定与跨进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android的服务(Service)(
- 下一篇: Binder学习指南