前面已經介紹了如何建立一個應用服務,如何建立一個系統服務,這裡我把Android服務分為:應用服務(ActivityService),系統服務(SystemService),分類是否正確也不清楚,網上並沒有資料明確定義,之所以這樣分類,因為應用服務放在ActiveServices中管理,而系統服務放在ServiceManager中管理,兩者存在明顯的不同。由於Android設計時已經把中介層標準化了,我們實現一個服務時,只需要簡單實現服務端(Native)和調用端(Proxy)即可。本文將詳細描述ActiveService的啟動全過程,有關Binder的部分沒有詳細介紹,後續文章再介紹。
1、Activity服務啟動的幾個階段Activity服務啟動大致可以分為以下幾個階段:準備階段:做進程啟動前的準備工作。進程啟動階段:通過Zygote啟動進程。(當服務已經啟動時,此步驟略)Activity啟動階段:在新的進程裡,啟動Activity。本文重點說明第1階段和第3階段,進程啟動階段參見前一篇文章《Android 進階-進程啟動分析》。所以,Activity服務與應用的啟動過程大致相同。
2. 準備階段2.1 流程圖
2.2 關鍵流程說明上面的流程圖,和Activity應用啟動相似,最後都分為服務進程已經啟動和服務進程未啟動兩種情況,服務進程已經啟動的情況下,不需要進程啟動,直接到服務啟動步驟。從先前服務執行個體中,我們知道,當要調用一個服務時,需要先建立一個ServiceConnection,並在OnServiceConnected函數中,儲存服務的Binder介面,以便調用服務的各種介面。然後,再綁定服務,再調用服務。2.2.1 ContextImpl.bindServiceClient是調用Activity.bindService來綁定服務的,怎麼會到ContextImpl.bindService中?中略去了一些步驟,這裡結合代碼說明:Activity 繼承自 ContextThemeWrapper ,而ContextThemeWrapper繼承自 ContextWrapper,bindService就定義在ContextWraper中。frameworks/base/core/java/android/content/ContextWrapper.java
public class ContextWrapper extends Context { Context mBase; public ContextWrapper(Context base) { mBase = base; } ... public boolean bindService(Intent service, ServiceConnection conn, int flags) { return mBase.bindService(service, conn, flags); } ...}
再看ContextThemeWrapperframeworks/base/core/java/android/view/ContextThemeWrapper.java
public class ContextThemeWrapper extends ContextWrapper { ... public ContextThemeWrapper() { super(null); } ...}
而Activity沒有建構函式,這說明我們new一個Activity時,mBase是null,那怎麼bindService呢?一定有一個地方設定了mBase。在《Android進階-Activity應用啟動分析》一文中寫到ActivityThread.performLaunchActivity函數有介紹。現在繼續這個函數:frameworks/base/core/java/android/app/ActivityThread.java
public ActivityThread{ private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { ContextImpl appContext = new ContextImpl(); appContext.init(r.packageInfo, r.token, this); appContext.setOuterContext(activity); ... Context baseContext = appContext; ... return baseContext; } ... private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ... try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); ... if (activity != null) { //建立上下文 Context appContext = createBaseContextForActivity(r, activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); //串連上下文 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config); ... } r.paused = true; mActivities.put(r.token, r); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to start activity " + component + ": " + e.toString(), e); } } return activity; }}
frameworks/base/core/java/android/app/Activity.java
public Activity{... final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config) { // 串連mBase attachBaseContext(context); mFragments.attachActivity(this, mContainer, null); ... }}
frameworks/base/core/java/android/view/ContextThemeWrapper.java
public class ContextThemeWrapper{protected void attachBaseContext(Context newBase) {//串連mBase super.attachBaseContext(newBase); mBase = newBase; }}
從上面的原始碼可以看出,當載入Activity類後,便會調用createBaseContextForActivity來建立appContext,再用activity.attach來串連context。而appContext是用newContextImpl()來建立的,所以,Activity.mBase就是一個ContextImpl的類執行個體。因此,從ContextImpl.bindService開始。
2.2.2 ContextImpl.bindServiceCommonframeworks/base/core/java/android/app/ContextImpl.java
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, UserHandle user) { IServiceConnection sd; if (conn == null) { throw new IllegalArgumentException("connection is null"); } if (mPackageInfo != null) { // 建立一個IServiceConnection對象,服務綁定後,需要調用此對象的connected函數,觸發ServiceConnection.onServiceConnected事件 // 此對象是一個LoadedApk.ServiceDispatcher.InnerConnection對象,見後面的LoadedApk的代碼解釋 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), mMainThread.getHandler(), flags); } else { throw new RuntimeException("Not supported in system context"); } validateServiceIntent(service); try { ... // 通過ActivieyManagerProxy.bindService,經由Binder調用ActivityManagerService.bindService 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; } catch (RemoteException e) { return false; } }
frameworks/base/core/java/android/app/LoadedApk.java
public class LoadedApk{...static final class ServiceDispatcher {private final ServiceDispatcher.InnerConnection mIServiceConnection;...private static class InnerConnection extends IServiceConnection.Stub { ... } ... IServiceConnection getIServiceConnection() { // 返回一個InnerConnection串連 return mIServiceConnection; }}...public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) { synchronized (mServices) { LoadedApk.ServiceDispatcher sd = null; ArrayMap map = mServices.get(context); if (map != null) { sd = map.get(c); } if (sd == null) { // 建立ServiceDispatcher sd = new ServiceDispatcher(c, context, handler, flags); if (map == null) { map = new ArrayMap(); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } // 返回ServiceDispatcher.getIServiceConnection() return sd.getIServiceConnection(); } }...}
本函數做兩個事情:調用mPackageInfo.getServiceDispatcher建立IServiceConnection串連,返回的是ServiceDispatcher.InnerConnection對象,此對象作為bindService的參數,傳給後續實現者。此對象可以通過connected函數,來觸發ServiceConection.onServiceConnected,來通知調用方,服務已經綁定了,並傳入IBinder對象,可以調用方通過此對象來調用服務的各種操作;通過ActivityManagerProxy.bindService,來調用ActivityManagerService中的bindService方法。說明:ActivityManagerNavite.getDefault()返回的是一個ActivityManagerProxy對象,這在《Android進階- Activity應用啟動分析》一文中已經有介紹。具體的過程見,Binder通訊過程本文忽略。2.2.3 ActivityManagerService.bindServiceContextImpl通過ActivityManagerProxy,經由Binder驅動程式,將bindService的操作傳入到了ActivityManagerService.bindService中,圖中有較為清楚的表述,文字上不再細說。流程走到ActivityManagerService.bindService中後,又有兩個關鍵動作,即ActiveServices.realStartServiceLocked和ActiveServices.reuqestServiceBindLocket。2.2.4 ActiveServices.bringUpServiceLockedframeworks/base/services/java/com/android/server/am/ActiveServices.java
public class ActiveServices{...private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting) { ... ProcessRecord app; if (!isolated) { app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app); if (app != null && app.thread != null) { // 如果服務進程已經啟動 try { app.addPackage(r.appInfo.packageName, mAm.mProcessStats); realStartServiceLocked(r, app, execInFg); return null; } catch (RemoteException e) { Slog.w(TAG, "Exception when starting service " + r.shortName, e); } // If a dead object exception was thrown -- fall through to // restart the application. } } else { ... } // Not running -- get it started, and enqueue this service record // to be executed when the app comes up. if (app == null) { // 如果服務進程未啟動 if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, "service", r.name, false, isolated, false)) == null) { ... return msg; } if (isolated) { r.isolatedProc = app; } }... return null; }}
上面的函數流程很簡單,就是判斷如果服務進程已經啟動,則直接調用realStartServiceLocked啟動服務,否則調用ActivityManagerService.startProcessLocked啟動進程,進入進程啟動階段。3. 進程啟動階段略。詳見《Android 進階 - 進程啟動分析》一文。4. 服務啟動階段4.1 流程圖4.2 關鍵流程分析上面的圖看似比Activity啟動要複雜,實際上大的步驟差不過,只不過,服務啟動時,先要createService,再bindService,要發兩次訊息,而Activity啟動只需要發一次訊息。如果服務進程已經啟動的情況下,可直接從3.1:realStartServiceLocked一步往下看。請先參看《Android 進階 - Looper進程內通訊》和《Android 進階 -Activity應用啟動分析》,從bindServiceLocked到sendMessage,再到訊息進入到Looper.mainLooper.queue隊列中,如果看了前面兩篇文章,相信這一部分很容易看懂,這裡不再討論。流程主要發了兩個訊息H.CREATE_SERVICE和H.BIND_SERVICE,一個是建立服務的訊息,一個是綁定服務的訊息。這些訊息會在Looper.loop函數依次處理。4.2.1 handleCreateServiceH.CREATE_SERVICE的訊息,經由H.dispatchMessage,會進入ActivityThread.handleCreateService函數。frameworks/base/core/java/android/app/ActivityThread.java
public clas ActivityThread{...private void handleCreateService(CreateServiceData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance(); } catch (Exception e) { if (!mInstrumentation.onException(service, e)) { throw new RuntimeException( "Unable to instantiate service " + data.info.name + ": " + e.toString(), e); } } try { if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); ContextImpl context = new ContextImpl(); context.init(packageInfo, null, this); Application app = packageInfo.makeApplication(false, mInstrumentation); context.setOuterContext(service); // 串連服務上下文 service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); // 觸發服務的onCreate事件 service.onCreate(); mServices.put(data.token, service); try { ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, 0, 0, 0); } catch (RemoteException e) { // nothing to do. } } catch (Exception e) { if (!mInstrumentation.onException(service, e)) { throw new RuntimeException( "Unable to create service " + data.info.name + ": " + e.toString(), e); } } }}
4.2.2 handleBindServiceH.BIND_SERVICE的訊息,經由H.dispatchMessage,會進入ActivityThread.handleBindService函數。frameworks/base/core/java/android/app/ActivityThread.java
public class ActivityThread{... 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()); try { if (!data.rebind) { // 觸發服務的onBind事件 IBinder binder = s.onBind(data.intent); // 通過Binder,調用ActivityManagerService.publishService發布服務 ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder); } else { ... } ensureJitEnabled(); } catch (RemoteException ex) { } } catch (Exception e) { ... } } }}
4.2.3 publishService上節的源碼中說明,服務綁定完成之後,會通過ActivityManagerProxy代理,經由Binder,調用ActivityManagerService的publishService函數。frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
pulbic class ActivityManagerService{...public void publishService(IBinder token, Intent intent, IBinder service) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } synchronized(this) { if (!(token instanceof ServiceRecord)) { throw new IllegalArgumentException("Invalid service token"); } mServices.publishServiceLocked((ServiceRecord)token, intent, service); } } ...}
frameworks/base/services/java/com/android/server/am/ActiveServices.java
pulbic class ActiveService{...void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) { final long origId = Binder.clearCallingIdentity(); try { if (DEBUG_SERVICE) Slog.v(TAG, "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 clist = r.connections.valueAt(conni); for (int i=0; iframeworks/base/core/java/android/app/LoadedApk.javapublic class LoadApk{...static final class ServiceDispatcher {private static class InnerConnection extends IServiceConnection.Stub { final WeakReference mDispatcher; InnerConnection(LoadedApk.ServiceDispatcher sd) { mDispatcher = new WeakReference(sd); }// 通知已經串連 public void connected(ComponentName name, IBinder service) throws RemoteException { LoadedApk.ServiceDispatcher sd = mDispatcher.get(); if (sd != null) { // 進入下面的connected函數 sd.connected(name, service); } } } ... public void connected(ComponentName name, IBinder service) { if (mActivityThread != null) { mActivityThread.post(new RunConnection(name, service, 0)); } else { // 進入下面的doConnected函數 doConnected(name, service); } } ... public void doConnected(ComponentName name, IBinder service) { ServiceDispatcher.ConnectionInfo old; ServiceDispatcher.ConnectionInfo info; ... // If there was an old service, it is not disconnected. if (old != null) { // 假如是服務,觸發onServiceDisconnected事件 mConnection.onServiceDisconnected(name); } // If there is a new service, it is now connected. if (service != null) { // 假如是新服務,則觸發onServiceConnected。mConnection為在Activity.bindService是傳入的參數,也即是綁定服務前使用者建立的ServiceConnection類執行個體。 mConnection.onServiceConnected(name, service); } }}}
流程走到這裡,就算是完成了,進入了調用者建立的ServiceConnection.onServiceConnected函數中,此函數會傳回服務的IBinder介面,調用者可以儲存此介面調用服務的各類操作。