service兩種啟動方式(電腦service怎麼開啟)

前言

這幾天分析了一下的啟動過程,於是乎,今天寫一下Service是如何啟動的; 給我的感覺是這些啟動過程並不複雜,千萬不要被一坨一坨的程式碼嚇住了,雖然彎彎繞繞不少,過載函式一個接著一個,就向走迷宮一樣,但只要抓住主線閱讀,很快就能找到出口; 強調一下閱讀系統原始碼,起碼要對程序間通訊要了解,對binder機制非常非常清楚,binder就是指南針,要不然你會暈頭轉向;強行閱讀,就容易睡著。

Service啟動先來一張圖感受一下

這張圖能夠說明一個大致的流程,但是服務的啟動肯定不是這麼簡單,但是我們先簡單的總結一下,逐漸深入。服務的啟動形式有兩種,startService()和 binderService(),我們看startService()這一種。startService是ContextWrapper裡面的方法。

ContextWrapper.java

  @Override    public ComponentName startService(Intent service) {        return mBase.startService(service);//mBase這裡指的是ContextImpl類    }

ContextImpl.java

   @Override     public ComponentName startService(Intent service) {         warnIfCallingFromSystemProcess();         return startServiceCommon(service, mUser);     }

  private ComponentName startServiceCommon(Intent service, UserHandle user) {         try {             //檢驗Intent             validateServiceIntent(service);              ......             ComponentName cn = ActivityManagerNative.getDefault().startService(                 mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(                             getContentResolver()), getOpPackageName(), user.getIdentifier());              ......             return cn;         } catch (RemoteException e) {             throw new RuntimeException("Failure from system", e);         }     }

校驗完Intent後,就呼叫
   ActivityManagerNative.getDefault(),獲取一個IActivityManager物件,將啟動Service這件事情交給了IActivityManager。我們看一下ActivityManagerNative的類定義

public abstract class ActivityManagerNative extends Binder implements IActivityManager

這種模式是不是非常熟悉啊? 繼承了Binder,實現了一個IActivityManager介面,這個跟我們生成了遠端服務通訊生成的AIDL的java檔案怎麼那麼像,現在告訴你,這就是為了遠端服務通訊做準備的,只是一般這種類我們都是自動生成的,ActivityManagerNative 是谷歌的人自己寫

一個完整的AID L有兩部分,一個是個跟服務端通訊的Stub,一個是跟客戶端通訊的Proxy; ActivityManagerNative就是Stub,閱讀原始碼發現在ActivityManagerNative 檔案中還有個ActivityManagerProxy,那麼跟客戶端通訊的Proxy也有了。先看IActivityManager怎麼獲取的

ActivityManagerNative.java

 static public IActivityManager getDefault() {         return gDefault.get();     }

  private static final SingletongDefault = new Singleton() {         protected IActivityManager create() {           //獲取名為"activity"的服務,服務都註冊到ServiceManager來統一管理             IBinder b = ServiceManager.getService("activity");             if (false) {                 Log.v("ActivityManager", "default service binder = "   b);             }             IActivityManager am = asInterface(b);             if (false) {                 Log.v("ActivityManager", "default service = "   am);             }             return am;         }     };

就是一個單例設計模式,獲取到服務物件IBinder,把這個IBinder轉換成IActivityManager返回了。現在由IActivityManager啟動服務。

 public ComponentName startService(IApplicationThread caller, Intent service,             String resolvedType, String callingPackage, int userId) 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);         data.writeString(callingPackage);         data.writeInt(userId);         mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);         reply.readException();         ComponentName res = ComponentName.readFromParcel(reply);         data.recycle();         reply.recycle();         return res;     }

上面說了ActivityManagerProxy作為binder通訊的客戶端,ActivityManagerNative 作為binder通訊的服務端; mRemote.transact()是binder通訊的客戶端發起方法,經過binder驅動,最後回到binder服務端ActivityManagerNative的onTransact()方法。

   @Override     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)             throws RemoteException {             .......         switch (code) {              case START_SERVICE_TRANSACTION: {                         data.enforceInterface(IActivityManager.descriptor);                         IBinder b = data.readStrongBinder();                         IApplicationThread app = ApplicationThreadNative.asInterface(b);                         Intent service = Intent.CREATOR.createFromParcel(data);                         String resolvedType = data.readString();                         String callingPackage = data.readString();                         int userId = data.readInt();                         ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);                         reply.writeNoException();                         ComponentName.writeToParcel(cn, reply);                         return true;                     }         }         .......     }

ActivityManagerNative的真正實現是ActivityManagerService,所以binder通訊的服務端的ActivityManagerService,
   ActivityManagerProxy.startService()最終呼叫
   ActivityManagerService.startService()。注意這就跨程序了,ActivityManagerService是一個服務端的程序。看ActivityManagerService中的startService方法。

ActivityManagerService.java

 public ComponentName startService(IApplicationThread caller, Intent service,             String resolvedType, String callingPackage, int userId)             throws TransactionTooLargeException {         ......         synchronized(this) {             .......             ComponentName res = mServices.startServiceLocked(caller, service,                     resolvedType, callingPid, callingUid, callingPackage, userId);             Binder.restoreCallingIdentity(origId);             return res;         }     }

ActivityManagerService沒有直接幹這個活,而是把這個任務交給了mService, mService 是一個 ActiveServices 物件。在早期的安卓版本中並沒有這個類,後來重構時抽出這個類專門用來管理Service.

ActiveServices.java

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,             int callingPid, int callingUid, String callingPackage, int userId)             throws TransactionTooLargeException {               ........               return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);     }

tartServiceInnerLocked呼叫了 bringUpServiceLocked(),bringUpServiceLocked()內部呼叫了realStartServiceLocked(),我們看realStartServiceLocked()方法。

private final void realStartServiceLocked(ServiceRecord r,             ProcessRecord app, boolean execInFg) throws RemoteException {        .......         try {             .......             app.thread.scheduleCreateService(r, r.serviceInfo,                     mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),                     app.repProcState);             r.postNotification();             created = true;         } catch (DeadObjectException e) {             ....         } finally {            ....         }         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));         }        // 進入onStartCommand()         sendServiceArgsLocked(r, execInFg, true);        ....     }

這裡的關鍵是

 app.thread.scheduleCreateService(r, r.serviceInfo,                     mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),

app 是要執行 Service 的程序對應的 ProcessRecord 物件,代表一個應用程序; 要區分一下,一般我們都是單方向通訊,客戶端將處理請求傳送給服務端,服務端處理後返回,如果要服務端向客戶端傳送一個“請求”呢?這裡的thread 是一個 ApplicationThreadProxy 物件,它是應用程序的 ApplicatonThread 物件在 AMS 端的代理,AMS 靠它來和應用程序進行通訊。所以AMS和應用程序可以雙向通訊了。

ApplicationThreadProxy.java

public final void scheduleCreateService(IBinder token, ServiceInfo info,         CompatibilityInfo compatInfo, int processState) throws RemoteException {     Parcel data = Parcel.obtain();     data.writeInterfaceToken(IApplicationThread.descriptor);     data.writeStrongBinder(token);     info.writeToParcel(data, 0);     compatInfo.writeToParcel(data, 0);     data.writeInt(processState);     try {         mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);     } catch (TransactionTooLargeException e) {         throw e;     }     data.recycle(); }

執行mRemote.transact後,就會回撥ApplicationThreadNative的onTransact,這是Binder的套路。

ApplicationThreadNative.java

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)         throws RemoteException {     switch (code) {     case SCHEDULE_CREATE_SERVICE_TRANSACTION: {         data.enforceInterface(IApplicationThread.descriptor);         IBinder token = data.readStrongBinder();         ServiceInfo info = ServiceInfo.CREATOR.createFromParcel(data);         CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);         int processState = data.readInt();         scheduleCreateService(token, info, compatInfo, processState);         return true;     }     ... }

內部呼叫scheduleCreateService,看上面的圖,可以知道,scheduleCreateService是屬於ApplicatonThread的。

ApplicatonThread.java

 public final void scheduleCreateService(IBinder token,                 ServiceInfo info, CompatibilityInfo compatInfo, int processState) {             updateProcessState(processState, false);             CreateServiceData s = new CreateServiceData();             s.token = token;             s.info = info;             s.compatInfo = compatInfo;             sendMessage(H.CREATE_SERVICE, s);         }

傳送一個訊息,這個訊息都是由H類處理的,H類就是系統Hander,專門處理系統請求的; 比如一些Activity的生命週期等全在這裡面。這個 H物件是在應用程序的主執行緒中建立的,所以最終的結果是把建立 Service 的訊息傳到了主執行緒,因此Service是執行在主執行緒中的。

H.java

private class H extends Handler {           .........             public void handleMessage(Message msg) {                          if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: "   codeToString(msg.what));             switch (msg.what) {                           case CREATE_SERVICE:                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");                     handleCreateService((CreateServiceData)msg.obj);                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);             }         }

ActivityThread.java

 private void handleCreateService(CreateServiceData data) {                .......         LoadedApk packageInfo = getPackageInfoNoCheck(                 data.info.applicationInfo, data.compatInfo);         Service service = null;         try {             // 反射載入Service             java.lang.ClassLoader cl = packageInfo.getClassLoader();             service = (Service) cl.loadClass(data.info.name).newInstance();         } catch (Exception e) {             .......         }         try {             if (localLOGV) Slog.v(TAG, "Creating service "   data.info.name);              //建立ContextImpl物件             ContextImpl context = ContextImpl.createAppContext(this, packageInfo);             context.setOuterContext(service);              //建立Application物件             Application app = packageInfo.makeApplication(false, mInstrumentation);             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, SERVICE_DONE_EXECUTING_ANON, 0, 0);             } catch (RemoteException e) {                 // nothing to do.             }         } catch (Exception e) {            .......         }     }

到此Service的onCreate就回撥了,那麼onStartCommand()何時回撥呢?在realStartServiceLocked中呼叫了sendServiceArgsLocked(r, execInFg, true),sendServiceArgsLocked與上面類似,最終也是傳送了一個(SERVICE_ARGS)訊息。

ApplicationThread.java

public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,             int flags ,Intent args) {             ServiceArgsData s = new ServiceArgsData();             s.token = token;             s.taskRemoved = taskRemoved;             s.startId = startId;             s.flags = flags;             s.args = args;             sendMessage(H.SERVICE_ARGS, s);         }

ActivityThread.java

private void handleServiceArgs(ServiceArgsData data) {         Service s = mServices.get(data.token);         if (s != null) {             try {                 if (data.args != null) {                     data.args.setExtrasClassLoader(s.getClassLoader());                     data.args.prepareToEnterProcess();                 }                 int res;                 if (!data.taskRemoved) {                 //onStartCommand回撥                     res = s.onStartCommand(data.args, data.flags, data.startId);                 } else {                     s.onTaskRemoved(data.args);                     res = Service.START_TASK_REMOVED_COMPLETE;                 }                 QueuedWork.waitToFinish();                 try {                     ActivityManagerNative.getDefault().serviceDoneExecuting(                             data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);                 } catch (RemoteException e) {                     // nothing to do.                 }                 ensureJitEnabled();             } catch (Exception e) {                ......             }         }     }

Service的onCreate的回撥和onStartCommand的回撥套路是完全一樣的,朋友們可以自己體會,onCreate的回撥先執行scheduleCreateService()方法,最終回撥Service.onCreate(); onStartCommand的回撥先執行scheduleServiceArgs()方法,最終回撥Service.onStartCommand()

總結一下:

IActivityManager介面中定義了AMS嚮應用程式(本例中即Service)提供的多種API,Activity通過ActivityManagerProxy就可以使用這些API,向AMS發出請求

所以是通過ActivityManagerProxy,呼叫ActivityManagerProxy的startService方法; 在內部呼叫transact,然後會呼叫ActivityManagerNative中的onTransact()方法,在該方法中,將會r完成AMS與Activity的連線並呼叫AMS的startService()方法,那麼AMS是如何Service所在的應用程式呢?比如scheduleCreateService

原來ApplicationThreadProxy 是應用程序的 ApplicatonThread 物件在 AMS 端的代理,AMS 靠它來和應用程序進行通訊。這就是Activity與AMS之間的雙向Binder連線;Activity用IActivityManager提供的APIActivityManagerService提出執行某個動作的請求(本例中是啟動RemoteService),ActivityManagerService通過IApplicationThread提供的API來控制Activity所在的應用程式

上面的分析省去了很多的內容,如果從程序角度看服務啟動過程。

  • Process A程序:是指呼叫startService命令所在的程序,也就是啟動服務的發起端程序
  • system_server程序:系統程序,是java framework框架的核心載體,裡面執行了大量的系統服務,比如這裡提供ApplicationThreadProxy,ActivityManagerService,這個兩個服務都執行在system_server程序的不同執行緒中
  • Zygote程序:是由init程序孵化而來的,用於建立Java層程序的母體,所有的Java層程序都是由Zygote程序孵化而來
  • Remote Service程序:遠端服務所在程序,是由Zygote程序孵化而來的用於執行Remote服務的程序。主執行緒主要負責Activity/Service等元件的生命週期以及UI相關操作都執行在這個執行緒; 另外,每個App程序中至少會有兩個binder執行緒 ApplicationThread和ActivityManagerProxy

啟動流程:

  • Process A程序採用Binder IPC向system_server程序發起startService請求;
  • system_server程序接收到請求後,向zygote程序傳送建立程序的請求;
  • zygote程序fork出新的子程序Remote Service程序;
  • Remote Service程序,通過Binder IPC向sytem_server程序發起attachApplication請求;
  • system_server程序在收到請求後,進行一系列準備工作後,再通過binder IPC向remote Service程序傳送scheduleCreateService請求;
  • Remote Service程序的binder執行緒在收到請求後,通過handler向主執行緒傳送CREATE_SERVICE訊息;
  • 主執行緒在收到Message後,通過發射機制建立目標Service,並回撥Service.onCreate()方法。 到此,服務便正式啟動完成。當建立的是本地服務或者服務所屬程序已建立時,則無需經過上述步驟2、3,直接建立服務即可

有需要文章中完整程式碼的同學 現在私信傳送 “底層原始碼” 即可免費獲取

現在私信傳送 “進階” 還可以獲取《更多 Android 原始碼解析 核心筆記 面試真題》

最後我想說:

學習沒有捷徑可言,我們要注意記學習,不僅要記,還要寫心得體會,文字筆記、畫圖、總結等,方式很多,但是一定要自己認真去做,不要太相信自己的記憶,只有反覆記憶,加深理解才行

同時,對於程式設計師而言,不單單是死記硬背,我們有更好的方式去學習,比如寫demo去驗證。複習知識點時,要及時跟你做過的專案結合起來,這樣在面試時就知道怎麼聊了,由專案講到知識點,由一個知識點串聯到另一個知識點。複習到一定階段,可以嘗試著去把這些東西串聯起來,由點及面,形成知識體系

對於程式設計師來說,要學習的知識內容、技術有太多太多,要想不被環境淘汰就只有不斷提升自己,從來都是我們去適應環境,而不是環境來適應我們

技術是無止境的,你需要對自己提交的每一行程式碼、使用的每一個工具負責,不斷挖掘其底層原理,才能使自己的技術昇華到更高的層面

Android 架構師之路還很漫長,與君共勉