Android笔记-service启动过程分析:bindService源码分析、startService和bindService区别
2018-01-30 20:04
656 查看
前言:
Service的启动流程将会分为一个系列来讲述。
本系列开始将分析Service的启动过程。
看这个系列文章之前你所需要知道的知识点:
1. 熟悉service的基本用法。
2. 了解bind机制,知道android的客户端和AMS间通信流程。
3. 最好学习过activity的启动流程。
本系列将涉及到以下一些分支:
startService源码分析
bindService源码分析、startService和bindService区别
第二次startService为什么没有调用onCreate
为什么bindService和startService同时调用后需要同时调用unBind和stop才能使服务停止。
前台Service原理
今天这一篇将讲述bindService源码分析:
service启动过程分析
bindService源码分析
bindServicestartService区别
ServiceDispatchInnerConnection
AMS中的bindService
ServiceConnection的onServiceConnected流程
总结
因为两者的AMS流程很相似,所以打算结合startService流程,分析两者的不同之处。
首先我们要思考一下startService和bindService用法上有什么不同:
1. 服务端:
2. 客户端
3、其他区别
区别大概就是以上几点。可以看出bindService和startService相比,多了一个bind机制,可以让Service和Activity之间相互通信。当然,主要目的是为了可以进行跨进程通信。
当然,客户端经过一系列调用最终会执行到ContextImpl的bindServiceCommon方法:
bindServiceCommon相比startServiceCommend多了一步sd参数的生成。sd参数是什么?怎么生成的呢?
先来看下获取sd的方法mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
:
ServiceDispatcher的getIServiceConnection方法
从上面两段代码我们看到sd原来是一个IServiceConnection。看上去是一个跨进程通信的玩意儿。
这里涉及到三个类(LoadedApk,ServiceDispatch,InnerConnection)、一个接口IServiceConnection:
LoadedApk,ServiceDispatch,InnerConnection关系如下:
LoadedApk: Local state maintained about a currently loaded .apk.:保持当前加载的.apk的本地状态。
ServiceDispatch:它是LoadedApk内部类,其构造函数:
InnerConnection:它是ServiceDispatch内部类,继承了IServiceConnection.Stub,可以跨进程通信,其源码:
InnerConnection持有了一个ServiceDispatcher,且该connected方法执行的是ServiceDispatcher的connected方法。再看ServiceDispatcher的connected方法:
可以看到connected方法会会执行RunConnection的run()方法或者doConnected方法,再看RunConnection类:
可以看到最终会执行doConnected方法,doConnected方法源码:
最终会执行ServiceConnection的onServiceConnected方法。
至于为什么这么麻烦的使用这么多类来生成一个sd,主要是因为涉及到跨进程通信,而ServiceConnection并不能进行跨进程通信,只能用ServiceDispatcher.InnerConnection来保存其信息,进行跨进程通信。
以上分析了ServiceConnection是如何被封装成ServiceDispatcher.InnerConnection的。
我们只要知道2点:
1. 由于ServiceConnection不能跨进程,所以使用了ServiceDispatcher.InnerConnection来保存ServiceConnection的信息,
2. ServiceDispatcher.InnerConnection执行connected方法会执行ServiceConnection的onServiceConnected方法。
记住以上两点,在后面的onServiceConnected我们流程中会用到,继续回头看,下面会进行跨进程通信。
bindService(ActivityManagerService)—bindServiceLocked(ActiveServices)—-bringUpServiceLocked(ActiveServices)—-realStartServiceLocked(ActiveServices)。
最终执行的realStartServiceLocked方法,其实在startService中最终也是realStartServiceLocked方法。很神奇,怎么都走了这个方法?为什么后面客户端的流程会不一样呢(startService执行了onStartCommend,bindService执行了onBind)?那么我们再来回顾一下realStartServiceLocked方法吧:
注意requestServiceBindingsLocked方法,它后续会调用bindService。
该方法用到了r.bindings。它是一个ArrayMap,保存了客户端的bind消息:
哈哈,前文中的卖得关子现在看到了,原来是用r.bindings来判断是否执行onBind方法的啊~。
具体保存方法在AMS一开始的方法bindServiceLocked中:
这里可以看到bindings里面保存了IntentBindRecord记录。IntentBindRecord保存的是intent。
requestServiceBindingsLocked通过循环取出该记录,执行requestServiceBindingLocked:
这里值得注意的是:
1. startService流程也会执行到requestServiceBindingsLocked方法,可是由于没有给bindings赋值,所以不会执行循环里的requestServiceBindingLocked方法。即不会执行onBind方法
2. bindService流程执行requestServiceBindingsLocked后,会继续执行sendServiceArgsLocked方法,通过startService流程解析,我们知道该方法后续会执行onStartCommend。执行onStartCommend的标识是pendingStarts这个记录。在前文中有提到记录如何赋值的。bindService流程并没有给其赋值。所以bindService并不会执行onStartCommend方法。
我们再看requestServiceBindingLocked方法又开始执行客户端ActivityThread中的方法:scheduleBindService:
这里相比startService不同的是:ActivityManagerNative.getDefault().publishService(data.token, data.intent, binder);方法。该方法其实又是AMS流程,最终调用客户端-client的onServiceConnected方法。
那么我们看下具体是怎么实现的吧。经过一系列调用,最终会执行ActiveServices的publishServiceLocked方法:
关键代码是c.conn.connected(r.name, service);这里的c是一个ConnectionRecord。是从ServiceRecord中的connections获取的。connections是在哪里赋值的呢?其实还是在一开始的bindServiceLocked方法里:
注意这里的connection参数,其实它就是文章一开始说的InnerConnection。
ConnectionRecord类保存了该connection。最终在publishServiceLocked里面循环取出并调用connection的connected方法。文章开头已经知道该方法最终会执行ServiceConnection的onServiceConnected方法。
至此bindService整个流程结束。
realStartServiceLocked中会依次执行requestServiceBindingsLocked、sendServiceArgsLocked方法
requestServiceBindingsLocked:通过循环IntentBindRecord记录来执行onBind方法
sendServiceArgsLocked:通过循环pendingStarts记录来执行onStartCommend方法
IntentBindRecord记录在bindServiceLocked中赋值
pendingStarts(StartItem)记录在startServiceLocked中赋值
bindService流程执行onBind后,会比startService流程多一步,调用onServiceConnected方法,该步骤也是一个AMS调用过程。用到了ServiceDispatch类。
Service的启动流程将会分为一个系列来讲述。
本系列开始将分析Service的启动过程。
看这个系列文章之前你所需要知道的知识点:
1. 熟悉service的基本用法。
2. 了解bind机制,知道android的客户端和AMS间通信流程。
3. 最好学习过activity的启动流程。
本系列将涉及到以下一些分支:
startService源码分析
bindService源码分析、startService和bindService区别
第二次startService为什么没有调用onCreate
为什么bindService和startService同时调用后需要同时调用unBind和stop才能使服务停止。
前台Service原理
今天这一篇将讲述bindService源码分析:
service启动过程分析
bindService源码分析
bindServicestartService区别
ServiceDispatchInnerConnection
AMS中的bindService
ServiceConnection的onServiceConnected流程
总结
service启动过程分析
bindService源码分析
bindService、startService区别
分析bindService,不打算像startService一样,分析整个AMS流程。因为两者的AMS流程很相似,所以打算结合startService流程,分析两者的不同之处。
首先我们要思考一下startService和bindService用法上有什么不同:
1. 服务端:
区别 | startService | bindService |
---|---|---|
生命周期 | 会调用onStartCommend | 会调用onBind |
返回值 | onStartCommend没有返回值 | onBind需要返回一个Bind类型的值 |
区别 | startService | bindService |
---|---|---|
启动 | 用startService来启动startService | 用bindService来启动bindService |
参数 | startService参数只需要一个Intent | bindService参数多需要ServiceConnection |
回调 | 没有回调 | 需要重写ServiceConnection的onServiceConnected方法 |
区别 | startService | bindService |
---|---|---|
直接UI更新(非广播或eventbus等其他机制) | 不可以 | 可以 |
跨进程 | 不可以 | 可以 |
ServiceDispatch、InnerConnection
我们先从客户端的bindService方法开始看,当然,客户端经过一系列调用最终会执行到ContextImpl的bindServiceCommon方法:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) { // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser. IServiceConnection sd;//sd具体实现类是ServiceDispatch if (conn == null) { throw new IllegalArgumentException("connection is null"); } if (mPackageInfo != null) { //新建一个ServiceDispatch.InnerConnection,第一个参数是:ServiceConnection 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 && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null && mPackageInfo.getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { flags |= BIND_WAIVE_PRIORITY; } //Prepare this {@link Intent} to leave an app process. 跨进程通信准备 service.prepareToLeaveProcess(this); //开始AMS通信,注意参数多了一个sd,该参数包含了ServiceConnection信息 int res = ActivityManager.getService().bindService( 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 (RemoteException e) { throw e.rethrowFromSystemServer(); } }
bindServiceCommon相比startServiceCommend多了一步sd参数的生成。sd参数是什么?怎么生成的呢?
先来看下获取sd的方法mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
:
public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) { synchronized (mServices) { LoadedApk.ServiceDispatcher sd = null; ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); if (map != null) { if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c); sd = map.get(c); } if (sd == null) { //用ServiceConnection生成一个LoadedApk.ServiceDispatcher sd = new ServiceDispatcher(c, context, handler, flags); if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c); if (map == null) { map = new ArrayMap<>(); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } return sd.getIServiceConnection();//获取InnerConnection } }
ServiceDispatcher的getIServiceConnection方法
private final ServiceDispatcher.InnerConnection mIServiceConnection; .. IServiceConnection getIServiceConnection() { return mIServiceConnection; }
从上面两段代码我们看到sd原来是一个IServiceConnection。看上去是一个跨进程通信的玩意儿。
这里涉及到三个类(LoadedApk,ServiceDispatch,InnerConnection)、一个接口IServiceConnection:
LoadedApk,ServiceDispatch,InnerConnection关系如下:
LoadedApk: Local state maintained about a currently loaded .apk.:保持当前加载的.apk的本地状态。
ServiceDispatch:它是LoadedApk内部类,其构造函数:
ServiceDispatcher(ServiceConnection conn, Context context, Handler activityThread, int flags) { mIServiceConnection = new InnerConnection(this);//用自己新建一个InnerConnection mConnection = conn;//保存了ServiceConnection mContext = context; mActivityThread = activityThread; mLocation = new ServiceConnectionLeaked(null); mLocation.fillInStackTrace(); mFlags = flags; }
InnerConnection:它是ServiceDispatch内部类,继承了IServiceConnection.Stub,可以跨进程通信,其源码:
private static class InnerConnection extends IServiceConnection.Stub {//继承IServiceConnection.Stub,可以跨进程 final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; InnerConnection(LoadedApk.ServiceDispatcher sd) { mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); } public void connected(ComponentName name, IBinder service, boolean dead) throws RemoteException { LoadedApk.ServiceDispatcher sd = mDispatcher.get(); if (sd != null) { sd.connected(name, service, dead); } } }
InnerConnection持有了一个ServiceDispatcher,且该connected方法执行的是ServiceDispatcher的connected方法。再看ServiceDispatcher的connected方法:
public void connected(ComponentName name, IBinder service, boolean dead) { if (mActivityThread != null) { mActivityThread.post(new RunConnection(name, service, 0, dead)); } else { doConnected(name, service, dead); } }
可以看到connected方法会会执行RunConnection的run()方法或者doConnected方法,再看RunConnection类:
private final class RunConnection implements Runnable { RunConnection(ComponentName name, IBinder service, int command, boolean dead) { mName = name; mService = service; mCommand = command; mDead = dead; } public void run() { if (mCommand == 0) { doConnected(mName, mService, mDead); } else if (mCommand == 1) { doDeath(mName, mService); } } final ComponentName mName; final IBinder mService; final int mCommand; final boolean mDead; }
可以看到最终会执行doConnected方法,doConnected方法源码:
public void doConnected(ComponentName name, IBinder service, boolean dead) { ServiceDispatcher.ConnectionInfo old; ServiceDispatcher.ConnectionInfo info; ...省略一些代码 // If there was an old service, it is now disconnected. if (old != null) { mConnection.onServiceDisconnected(name); } if (dead) { mConnection.onBindingDied(name); } // If there is a new service, it is now connected. if (service != null) { //执行ServiceConnection的onServiceConnected mConnection.onServiceConnected(name, service); } }
最终会执行ServiceConnection的onServiceConnected方法。
至于为什么这么麻烦的使用这么多类来生成一个sd,主要是因为涉及到跨进程通信,而ServiceConnection并不能进行跨进程通信,只能用ServiceDispatcher.InnerConnection来保存其信息,进行跨进程通信。
以上分析了ServiceConnection是如何被封装成ServiceDispatcher.InnerConnection的。
我们只要知道2点:
1. 由于ServiceConnection不能跨进程,所以使用了ServiceDispatcher.InnerConnection来保存ServiceConnection的信息,
2. ServiceDispatcher.InnerConnection执行connected方法会执行ServiceConnection的onServiceConnected方法。
记住以上两点,在后面的onServiceConnected我们流程中会用到,继续回头看,下面会进行跨进程通信。
AMS中的bindService
调用AMS的bindService,经过一系列调用最终同样会走到realStartServiceLocked。具体调用了哪些方法可以看时序图。总结如下:bindService(ActivityManagerService)—bindServiceLocked(ActiveServices)—-bringUpServiceLocked(ActiveServices)—-realStartServiceLocked(ActiveServices)。
最终执行的realStartServiceLocked方法,其实在startService中最终也是realStartServiceLocked方法。很神奇,怎么都走了这个方法?为什么后面客户端的流程会不一样呢(startService执行了onStartCommend,bindService执行了onBind)?那么我们再来回顾一下realStartServiceLocked方法吧:
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { if (app.thread == null) { throw new RemoteException(); } if (DEBUG_MU) Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid + ", ProcessRecord.uid = " + app.uid); r.app = app; r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); final boolean newService = app.services.add(r); bumpServiceExecutingLocked(r, execInFg, "create"); mAm.updateLruProcessLocked(app, false, null); mAm.updateOomAdjLocked(); boolean created = false; try { if (LOG_SERVICE_START_STOP) { String nameTerm; int lastPeriod = r.shortName.lastIndexOf('.'); nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName; EventLogTags.writeAmCreateService( r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid); } synchronized (r.stats.getBatteryStats()) { r.stats.startLaunchedLocked(); } mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_SERVICE); app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); //会调用onCreate方法 app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); r.postNotification(); created = true; } catch (DeadObjectException e) { Slog.w(TAG, "Application dead when creating service " + r); mAm.appDiedLocked(app); throw e; } finally { if (!created) { // Keep the executeNesting count accurate. final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying); // Cleanup. if (newService) { app.services.remove(r); r.app = null; } // Retry. if (!inDestroying) { scheduleServiceRestartLocked(r, false); } } } if (r.whitelistManager) { app.whitelistManager = true; } //后续onBind方法会调用 requestServiceBindingsLocked(r, execInFg); updateServiceClientActivitiesLocked(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.StartItem(r, false, r.makeNextStartId(), null, null)); } //后续onStartCommend方法会调用 sendServiceArgsLocked(r, execInFg, true); if (r.delayed) { if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r); getServiceMap(r.userId).mDelayedStartList.remove(r); r.delayed = false; } if (r.delayedStop) { // Oh and hey we've already been asked to stop! r.delayedStop = false; if (r.startRequested) { if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Applying delayed stop (from start): " + r); stopServiceLocked(r); } } }
注意requestServiceBindingsLocked方法,它后续会调用bindService。
private final void requestServiceBindingsLocked(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; } } }
该方法用到了r.bindings。它是一个ArrayMap,保存了客户端的bind消息:
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
哈哈,前文中的卖得关子现在看到了,原来是用r.bindings来判断是否执行onBind方法的啊~。
具体保存方法在AMS一开始的方法bindServiceLocked中:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, final IServiceConnection connection, int flags, String callingPackage, final int userId) throws TransactionTooLargeException { ... //该方法给bindings赋值 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); .... return 1; }
public AppBindRecord retrieveAppBindingLocked(Intent intent, ProcessRecord app) { Intent.FilterComparison filter = new Intent.FilterComparison(intent); IntentBindRecord i = bindings.get(filter); if (i == null) { i = new IntentBindRecord(this, filter); bindings.put(filter, i); } AppBindRecord a = i.apps.get(app); if (a != null) { return a; } a = new AppBindRecord(this, i, app); i.apps.put(app, a); return a; }
这里可以看到bindings里面保存了IntentBindRecord记录。IntentBindRecord保存的是intent。
requestServiceBindingsLocked通过循环取出该记录,执行requestServiceBindingLocked:
private final 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.size() > 0) { try { bumpServiceExecutingLocked(r, execInFg, "bind"); r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); //调用客户端的scheduleBindService方法 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState); if (!rebind) { i.requested = true; } i.hasBound = true; i.doRebind = false; } catch (TransactionTooLargeException e) { // Keep the executeNesting count accurate. if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e); final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying); throw e; } catch (RemoteException e) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r); // Keep the executeNesting count accurate. final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying); return false; } } return true; }
这里值得注意的是:
1. startService流程也会执行到requestServiceBindingsLocked方法,可是由于没有给bindings赋值,所以不会执行循环里的requestServiceBindingLocked方法。即不会执行onBind方法
2. bindService流程执行requestServiceBindingsLocked后,会继续执行sendServiceArgsLocked方法,通过startService流程解析,我们知道该方法后续会执行onStartCommend。执行onStartCommend的标识是pendingStarts这个记录。在前文中有提到记录如何赋值的。bindService流程并没有给其赋值。所以bindService并不会执行onStartCommend方法。
我们再看requestServiceBindingLocked方法又开始执行客户端ActivityThread中的方法:scheduleBindService:
public final void scheduleBindService(IBinder token, Intent intent, boolean rebind, int processState) { updateProcessState(processState, false); BindServiceData s = new BindServiceData(); s.token = token; s.intent = intent; s.rebind = rebind; if (DEBUG_SERVICE) Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid=" + Binder.getCallingUid() + " pid=" + Binder.getCallingPid()); sendMessage(H.BIND_SERVICE, s); }
ServiceConnection的onServiceConnected流程
后面的流程和startService在客户端流程一致,会调用到ActivityThread中的方法handleBindService:private void handleBindService(BindServiceData data) { Service s = mServices.get(data.token); if (DEBUG_SERVICE) Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind); if (s != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); data.intent.prepareToEnterProcess(); try { if (!data.rebind) { //执行客户端-server的onBind方法,并返回IBinder IBinder binder = s.onBind(data.intent); //注意:又一个AMS流程,用返回的IBinder调用客户端-client的onServiceConnected ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); 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 to bind to service " + s + " with " + data.intent + ": " + e.toString(), e); } } } }
这里相比startService不同的是:ActivityManagerNative.getDefault().publishService(data.token, data.intent, binder);方法。该方法其实又是AMS流程,最终调用客户端-client的onServiceConnected方法。
那么我们看下具体是怎么实现的吧。经过一系列调用,最终会执行ActiveServices的publishServiceLocked方法:
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder 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.bindings.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 = clist.get(i); if (!filter.equals(c.binding.intent.intent)) { if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Not publishing to: " + c); if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Bound intent: " + c.binding.intent.intent); if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Published intent: " + intent); continue; } if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c); try { //关键代码 c.conn.connected(r.name, service); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + r.name + " to connection " + c.conn.asBinder() + " (in " + c.binding.client.processName + ")", e); } } } } serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false); } } finally { Binder.restoreCallingIdentity(origId); } }
关键代码是c.conn.connected(r.name, service);这里的c是一个ConnectionRecord。是从ServiceRecord中的connections获取的。connections是在哪里赋值的呢?其实还是在一开始的bindServiceLocked方法里:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, final IServiceConnection connection, int flags, String callingPackage, final int userId) throws TransactionTooLargeException { ... //生成ConnectionRecord作为value ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); IBinder binder = connection.asBinder();//获取 InnerConnection,作为key ArrayList<ConnectionRecord> clist = s.connections.get(binder); if (clist == null) { clist = new ArrayList<ConnectionRecord>(); s.connections.put(binder, clist);//给connections赋值 } clist.add(c); .... return 1; }
注意这里的connection参数,其实它就是文章一开始说的InnerConnection。
ConnectionRecord类保存了该connection。最终在publishServiceLocked里面循环取出并调用connection的connected方法。文章开头已经知道该方法最终会执行ServiceConnection的onServiceConnected方法。
至此bindService整个流程结束。
总结:
startService和bindService在AMS中最后都会执行到realStartServiceLocked方法。realStartServiceLocked中会依次执行requestServiceBindingsLocked、sendServiceArgsLocked方法
requestServiceBindingsLocked:通过循环IntentBindRecord记录来执行onBind方法
sendServiceArgsLocked:通过循环pendingStarts记录来执行onStartCommend方法
IntentBindRecord记录在bindServiceLocked中赋值
pendingStarts(StartItem)记录在startServiceLocked中赋值
bindService流程执行onBind后,会比startService流程多一步,调用onServiceConnected方法,该步骤也是一个AMS调用过程。用到了ServiceDispatch类。
相关文章推荐
- Android笔记-service启动过程分析:startService源码分析
- Android源码解析之新进程中启动自定义服务过程(startService)的原理分析
- Android 8.0系统源码分析--startService启动过程源码分析
- Android 5.0源码分析---startService与bindService的区别
- Android系统在新进程中启动自定义服务过程(startService)的原理分析、Android应用程序绑定服务(bindService)的过程源代码分析
- 源码分析Android bindService与startService区别
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- Android 启动 Service(startservice和bindservice) 两种方式的区别
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- Android 中 startService()启动service的过程分析
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- Android服务启动之StartService源码分析
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- Android服务启动之StartService源码分析
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- Android 启动 Service(startservice和bindservice) 两种方式的区别
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
- android源码分析 Service的启动过程