在編寫Android應用程序時,我們一般將一些計算型的邏輯放在一個獨立的進程來處理,這樣主進程仍然可以流暢地響應界面事件,提高用戶體驗。Android系統為我們提供了一個Service類,我們可以實現一個以Service為基類的服務子類,在里面實現自己的計算型邏輯,然后在主進程通過startService函數來啟動這個服務。在本文中,將詳細分析主進程是如何通過startService函數來在新進程中啟動自定義服務的。
在主進程調用startService函數時,會通過Binder進程間通信機制來通知ActivitManagerService來創建新進程,並且啟動指定的服務。在Android系統中,Binder進程間通信機制使用非常廣泛,因此,希望讀者在繼續閱讀下面的內容之前,對Android系統和Binder進程間通信機制有一定的了解,具體可以參考前面Android進程間通信(IPC)機制Binder簡要介紹和學習計划一文。
關於startService的具體用法,可以參考前面Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計划一文中用到的實例,它是Activity類的一個成員函數:
- package shy.luo.ashmem;
- ......
- public class Client extends Activity implements OnClickListener {
- ......
- IMemoryService memoryService = null;
- ......
- @Override
- public void onCreate(Bundle savedInstanceState) {
- ......
- IMemoryService ms = getMemoryService();
- if(ms == null) {
- startService(new Intent("shy.luo.ashmem.server"));
- } else {
- Log.i(LOG_TAG, "Memory Service has started.");
- }
- ......
- Log.i(LOG_TAG, "Client Activity Created.");
- }
- ......
- }
這里的“shy.luo.ashmem.server”是在程序配置文件AndroidManifest.xml配置的Service的名字,用來告訴Android系統它所要啟動的服務的名字:
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="shy.luo.ashmem"
- android:sharedUserId="android.uid.system"
- android:versionCode="1"
- android:versionName="1.0">
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- ......
- <service
- android:enabled="true"
- android:name=".Server"
- android:process=".Server" >
- <intent-filter>
- <action android:name="shy.luo.ashmem.server"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </service>
- </application>
- </manifest>
這里,名字“shy.luo.ashmem.server”對應的服務類為shy.luo.ashmem.Server,下面語句:
- startService(new Intent("shy.luo.ashmem.server"));
就表示要在一個新的進程中啟動shy.luo.ashmem.Server這個服務類,它必須繼承於Android平台提供的Service類:
- package shy.luo.ashmem;
- ......
- public class Server extends Service {
- ......
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public void onCreate() {
- ......
- }
- ......
- }
下面,我們來看看Activity類中的startService成員函數是如何實現的。
先來看看Activity的類圖:
從圖中可以看出,Activity繼承了ContextWrapper類,而在ContextWrapper類中,實現了startService函數。在ContextWrapper類中,有一個成員變量mBase,它是一個ContextImpl實例,而ContextImpl類和ContextWrapper類一樣繼承於Context類,ContextWrapper類的startService函數最終過調用ContextImpl類的startService函數來實現。這種類設計方法在設計模式里面,就稱之為裝飾模式(Decorator),或者包裝模式(Wrapper)。
在ContextImpl類的startService類,最終又調用了ActivityManagerProxy類的startService來實現啟動服務的操作,看到這里的Proxy關鍵字,回憶一下前面Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析這篇文章,就會知道ActivityManagerProxy是一個Binder對象的遠程接口了,而這個Binder對象就是我們前面所說的ActivityManagerService了。
這個ActivityManagerService類實現在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中,它是Binder進程間通信機制中的Server角色,它是隨機啟動的。隨機啟動的Server是在frameworks/base/services/java/com/android/server/SystemServer.java文件里面進行啟動的,我們來看一下ActivityManagerService啟動相關的代碼:
- class ServerThread extends Thread {
- ......
- @Override
- public void run() {
- ......
- // Critical services...
- try {
- ......
- context = ActivityManagerService.main(factoryTest);
- ......
- ActivityManagerService.setSystemProcess();
- ......
- } catch (RuntimeException e) {
- Slog.e("System", "Failure starting core service", e);
- }
- ......
- }
- ......
- }
首先是調用ActivityManagerService.main函數來創建一個ActivityManagerService實例,然后通過調用ActivityManagerService.setSystemProcess函數把這個Binder實例添加Binder進程間通信機制的守護進程ServiceManager中去:
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
- static ActivityManagerService mSelf;
- ......
- public static void setSystemProcess() {
- try {
- ActivityManagerService m = mSelf;
- ServiceManager.addService("activity", m);
- ......
- } catch (PackageManager.NameNotFoundException e) {
- ......
- }
- }
- ......
- public static final Context main(int factoryTest) {
- ......
- ActivityManagerService m = thr.mService;
- mSelf = m;
- ......
- }
- }
這樣,ActivityManagerService就啟動起來了。
回到ActivityManagerProxy類的startService函數中,它定義在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:
- class ActivityManagerProxy implements IActivityManager
- {
- ......
- public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(caller != null ? caller.asBinder() : null);
- service.writeToParcel(data, 0);
- data.writeString(resolvedType);
- mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
- reply.readException();
- ComponentName res = ComponentName.readFromParcel(reply);
- data.recycle();
- reply.recycle();
- return res;
- }
- ......
- }
參數service是一個Intent實例,它里面指定了要啟動的服務的名稱,就是前面我們所說的“shy.luo.ashmem.server”了。
參數caller是一個IApplicationThread實例,它是一個在主進程創建的一個Binder對象。在Android應用程序中,每一個進程都用一個ActivityThread實例來表示,而在ActivityThread類中,有一個成員變量mAppThread,它是一個ApplicationThread實例,實現了IApplicationThread接口,它的作用是用來輔助ActivityThread類來執行一些操作,這個我們在后面會看到它是如何用來啟動服務的。
參數resolvedType是一個字符串,它表示service這個Intent的MIME類型,它是在解析Intent時用到的。在這個例子中,我們沒有指定這個Intent 的MIME類型,因此,這個參數為null。
ActivityManagerProxy類的startService函數把這三個參數寫入到data本地變量去,接着通過mRemote.transact函數進入到Binder驅動程序,然后Binder驅動程序喚醒正在等待Client請求的ActivityManagerService進程,最后進入到ActivityManagerService的startService函數中。
ActivityManagerService的startService函數的處理流程如下圖所示:
在這個序列圖中,一共有20個步驟,下面說明每一步。
Step 1. ActivityManagerService.startService
這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
- public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType) {
- // Refuse possible leaked file descriptors
- if (service != null && service.hasFileDescriptors() == true) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- synchronized(this) {
- final int callingPid = Binder.getCallingPid();
- final int callingUid = Binder.getCallingUid();
- final long origId = Binder.clearCallingIdentity();
- ComponentName res = startServiceLocked(caller, service,
- resolvedType, callingPid, callingUid);
- Binder.restoreCallingIdentity(origId);
- return res;
- }
- }
- ......
- }
這里的參數caller、service和resolvedType分別對應ActivityManagerProxy.startService傳進來的三個參數。
Step 2. ActivityManagerService.startServiceLocked
這個函數同樣定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
- ComponentName startServiceLocked(IApplicationThread caller,
- Intent service, String resolvedType,
- int callingPid, int callingUid) {
- synchronized(this) {
- ......
- ServiceLookupResult res =
- retrieveServiceLocked(service, resolvedType,
- callingPid, callingUid);
- ......
- ServiceRecord r = res.record;
- ......
- if (!bringUpServiceLocked(r, service.getFlags(), false)) {
- return new ComponentName("!", "Service process is bad");
- }
- return r.name;
- }
- }
- ......
- }
函數首先通過retrieveServiceLocked來解析service這個Intent,就是解析前面我們在AndroidManifest.xml定義的Service標簽的intent-filter相關內容,然后將解析結果放在res.record中,然后繼續調用bringUpServiceLocked進一步處理。
Step 3. ActivityManagerService.bringUpServiceLocked
這個函數同樣定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
- private final boolean bringUpServiceLocked(ServiceRecord r,
- int intentFlags, boolean whileRestarting) {
- ......
- final String appName = r.processName;
- ......
- // Not running -- get it started, and enqueue this service record
- // to be executed when the app comes up.
- if (startProcessLocked(appName, r.appInfo, true, intentFlags,
- "service", r.name, false) == null) {
- ......
- return false;
- }
- if (!mPendingServices.contains(r)) {
- mPendingServices.add(r);
- }
- return true;
- }
- ......
- }
這里的appName便是我們前面在AndroidManifest.xml文件定義service標簽時指定的android:process屬性值了,即“.Server”。
接着調用startProcessLocked函數來創建一個新的進程,以便加載自定義的Service類。最后將這個ServiceRecord保存在成員變量mPendingServices列表中,后面會用到。
Step 4. ActivityManagerService.startProcessLocked
這個函數同樣定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
- private final void startProcessLocked(ProcessRecord app,
- String hostingType, String hostingNameStr) {
- ......
- try {
- ......
- int pid = Process.start("android.app.ActivityThread",
- mSimpleProcessManagement ? app.processName : null, uid, uid,
- gids, debugFlags, null);
- ......
- if (pid == 0 || pid == MY_PID) {
- ......
- } else if (pid > 0) {
- app.pid = pid;
- app.removed = false;
- synchronized (mPidsSelfLocked) {
- this.mPidsSelfLocked.put(pid, app);
- ......
- }
- } else {
- ......
- }
- } catch (RuntimeException e) {
- ......
- }
- }
- ......
- }
這里調用Process.start函數創建了一個新的進程,指定新的進程執行android.app.ActivityThread類。最后將表示這個新進程的ProcessRecord保存在mPidSelfLocked列表中,后面會用到。
Step 5. Process.start
這個函數定義在frameworks/base/core/java/android/os/Process.java文件中,這個函數我們就不看了,有興趣的讀者可以自己研究一下。在這個場景中,它就是新建一個進程,然后導入android.app.ActivityThread這個類,然后執行它的main函數。
Step 6. ActivityThread.main
這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
- public final class ActivityThread {
- ......
- public static final void main(String[] args) {
- ......
- Looper.prepareMainLooper();
- ......
- ActivityThread thread = new ActivityThread();
- thread.attach(false);
- ......
- Looper.loop();
- ......
- thread.detach();
- ......
- }
- }
注意,執行到這里的時候,已經是在上一步創建的新進程里面了,即這里的進程是用來啟動服務的,原來的主進程已經完成了它的命令,返回了。
前面我們提到,在Android應用程序中,每一個進程對應一個ActivityThread實例,所以,這個函數會創建一個thread實例,然后調用ActivityThread.attach函數進一步處理。
Step 7. ActivityThread.attach
這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
- public final class ActivityThread {
- ......
- private final void attach(boolean system) {
- ......
- if (!system) {
- ......
- IActivityManager mgr = ActivityManagerNative.getDefault();
- try {
- mgr.attachApplication(mAppThread);
- } catch (RemoteException ex) {
- }
- } else {
- ......
- }
- ......
- }
- ......
- }
從Step 6中,這里傳進來的參數system為false。成員變量mAppThread是一個ApplicationThread實例,我們在前面已經描述過這個實例的作用,它是用來輔助ActivityThread來執行一些操作的。
調用ActivityManagerNative.getDefault函數得到ActivityManagerService的遠程接口,即ActivityManagerProxy,接着調用它的attachApplication函數。
Step 8. ActivityManagerProxy.attachApplication
這個函數定義在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:
- class ActivityManagerProxy implements IActivityManager
- {
- ......
- public void attachApplication(IApplicationThread app) throws RemoteException
- {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(app.asBinder());
- mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
- ......
- }
這個函數主要是將新進程里面的IApplicationThread實例通過Binder驅動程序傳遞給ActivityManagerService。
Step 9. ActivityManagerService.attachApplication
這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
- public final void attachApplication(IApplicationThread thread)
- {
- synchronized (this) {
- int callingPid = Binder.getCallingPid();
- final long origId = Binder.clearCallingIdentity();
- attachApplicationLocked(thread, callingPid);
- Binder.restoreCallingIdentity(origId);
- }
- }
- ......
- }
這里通過調用attachApplicationLocked函數進一步處理。
Step 10. ActivityManagerService.attachApplicationLocked
這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
- public final class ActivityManagerService extends ActivityManagerNative
- implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
- ......
- private final boolean attachApplicationLocked(IApplicationThread thread,
- int pid) {
- // Find the application record that is being attached... either via
- // the pid if we are running in multiple processes, or just pull the
- // next app record if we are emulating process with anonymous threads.
- ProcessRecord app;
- if (pid != MY_PID && pid >= 0) {
- synchronized (mPidsSelfLocked) {
- app = mPidsSelfLocked.get(pid);
- }
- } else if (mStartingProcesses.size() > 0) {
- app = mStartingProcesses.remove(0);
- app.setPid(pid);
- } else {
- app = null;
- }
- ......
- String processName = app.processName;
- ......
- app.thread = thread;
- ......
- boolean badApp = false;
- ......
- // Find any services that should be running in this process...
- if (!badApp && mPendingServices.size() > 0) {
- ServiceRecord sr = null;
- try {
- for (int i=0; i<mPendingServices.size(); i++) {
- sr = mPendingServices.get(i);
- if (app.info.uid != sr.appInfo.uid
- || !processName.equals(sr.processName)) {
- continue;
- }
- mPendingServices.remove(i);
- i--;
- realStartServiceLocked(sr, app);
- didSomething = true;
- }
- } catch (Exception e) {
- ......
- }
- }
- ......
- return true;
- }
- ......
- }
回憶一下在上面的Step 4中,以新進程的pid值作為key值保存了一個ProcessRecord在mPidsSelfLocked列表中,這里先把它取出來,存放在本地變量app中,並且將app.processName保存在本地變量processName中。
再回憶一下在上面的Step 3中,在成員變量mPendingServices中,保存了一個ServiceRecord,這里通過進程uid和進程名稱將它找出來,然后通過realStartServiceLocked函數來進一步處理。
Step 11. ActivityManagerService.realStartServiceLocked
這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
- class ActivityManagerProxy implements IActivityManager
- {
- ......
- private final void realStartServiceLocked(ServiceRecord r,
- ProcessRecord app) throws RemoteException {
- ......
- r.app = app;
- ......
- try {
- ......
- app.thread.scheduleCreateService(r, r.serviceInfo);
- ......
- } finally {
- ......
- }
- ......
- }
- ......
- }
這里的app.thread是一個ApplicationThread對象的遠程接口,它是在上面的Step 6創建ActivityThread對象時作為ActivityThread對象的成員變量同時創建的,然后在Step 9中傳過來的。然后調用這個遠程接口的scheduleCreateService函數回到原來的ActivityThread對象中執行啟動服務的操作。
Step 12. ApplicationThreadProxy.scheduleCreateService
這個函數定義在frameworks/base/core/java/android/app/ApplicationThreadNative.java文件中:
- class ApplicationThreadProxy implements IApplicationThread {
- ......
- public final void scheduleCreateService(IBinder token, ServiceInfo info)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- data.writeInterfaceToken(IApplicationThread.descriptor);
- data.writeStrongBinder(token);
- info.writeToParcel(data, 0);
- mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,
- IBinder.FLAG_ONEWAY);
- data.recycle();
- }
- ......
- }
這里通過Binder驅動程序回到新進程的ApplicationThread對象中去執行scheduleCreateService函數。
Step 13. ApplicationThread.scheduleCreateService
這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
- public final class ActivityThread {
- ......
- private final class ApplicationThread extends ApplicationThreadNative {
- ......
- public final void scheduleCreateService(IBinder token,
- ServiceInfo info) {
- CreateServiceData s = new CreateServiceData();
- s.token = token;
- s.info = info;
- queueOrSendMessage(H.CREATE_SERVICE, s);
- }
- ......
- }
- ......
- }
這里調用ActivityThread的queueOrSendMessage將一個CreateServiceData數據放到消息隊列中去,並且分開這個消息。注意,這里已經是在上面Step 4創建的新進程中執行了。
Step 14. ActivityThread.queueOrSendMessage
這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
- public final class ActivityThread {
- ......
- private final void queueOrSendMessage(int what, Object obj) {
- queueOrSendMessage(what, obj, 0, 0);
- }
- private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
- synchronized (this) {
- ......
- Message msg = Message.obtain();
- msg.what = what;
- msg.obj = obj;
- msg.arg1 = arg1;
- msg.arg2 = arg2;
- mH.sendMessage(msg);
- }
- }
- ......
- }
這里調用成員變量mH的sendMessage函數進行消息分發。這里的mH的類型為H,它繼承於Handler類。
Step 15. H.sendMessage
這個函數繼承於Handle類的sendMessage函數中,定義在frameworks/base/core/java/android/os/Handler.java文件中。這個函數我們就不看了,有興趣的讀者可以自己研究一下。消息分發以后,就進入到H.handleMessage函數進行處理了。
Step 16. H.handleMessage
這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
- public final class ActivityThread {
- ......
- private final class H extends Handler {
- ......
- public void handleMessage(Message msg) {
- ......
- switch (msg.what) {
- ......
- case CREATE_SERVICE:
- handleCreateService((CreateServiceData)msg.obj);
- break;
- ......
- }
- ......
- }
- ......
- }
- ......
- }
這里要處理的消息是CREATE_SERVICE,它調用ActivityThread類的handleCreateService成員函數進一步處理。
Step 17. ActivityThread.handleCreateService
這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:
- public final class ActivityThread {
- ......
- private final 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);
- 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());
- 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);
- }
- }
- }
- ......
- }
這里的data.info.name就是自定義的服務類shy.luo.ashmem.Server了。
Step 18. ClassLoader.loadClass
這一步實現在上面的ActivityThread.handleCreateService函數中:
- java.lang.ClassLoader cl = packageInfo.getClassLoader();
- service = (Service) cl.loadClass(data.info.name).newInstance();
Step 19. Obtain Service
這一步也是實現在上面的ActivityThread.handleCreateService函數中。上面通過ClassLoader.loadClass來導入自定義的服務類shy.luo.ashmem.Server並且創建它的一個實例后,就通過強制類型轉換得到一個Service類實例。前面我們說過,自己的服務類必須要繼承於Service類,這里就體現出來了為什么要這樣做了。
Step 20. Service.onCreate
這一步繼續實現在上面的ActivityThread.handleCreateService函數中:
- service.onCreate();
因為這里的service實際上是一個shy.luo.ashmem.Server類實例,因此,這里就是執行shy.luo.ashmem.Server類的onCreate函數了:
- public class Server extends Service {
- ......
- @Override
- public void onCreate() {
- ......
- }
- ......
- }
至此,這個自定義的服務就啟動起來了。
這樣,Android系統在新進程中啟動服務的過程就分析完成了,雖然很復雜,但是條理很清晰。它通過三次Binder進程間通信完成了服務的啟動過程,分別是:
一. Step 1至Step 7,從主進程調用到ActivityManagerService進程中,完成新進程的創建;
二. Step 8至Step 11,從新進程調用到ActivityManagerService進程中,獲取要在新進程啟動的服務的相關信息;
三. Step 12至Step 20,從ActivityManagerService進程又回到新進程中,最終將服務啟動起來。
學習完Android系統在新進程中啟動服務的過程后,希望讀者對Android系統的Service有一個深刻的理解。在編寫Android應用程序的時候,盡量把一些計算型的邏輯以Service在形式來實現,使得這些耗時的計算能在一個獨立的進程中進行,這樣就能保持主進程流暢地響應界面事件,提高用戶體驗。
--------------------------------------------------------------------
PS: 歡迎關注公眾號"Devin說",會不定期更新Java相關技術知識。
--------------------------------------------------------------------
轉自:http://blog.csdn.net/luoshengyang/article/details/6677029