Android6.0之App的Service組件運(yùn)行機(jī)制之bindService

bindService的過程要比startService的過程復(fù)雜一些,因?yàn)閎ingService之后,發(fā)起者可以跨進(jìn)程調(diào)用service的某些方法。而startService啟動service之后诊县,發(fā)起者僅能去終止service,而不能調(diào)用service的方法措左。

既然發(fā)起者可以跨進(jìn)程調(diào)用service中的方法依痊,那么肯定要用到binder了。本文也會重點(diǎn)分析binder的傳遞過程怎披,至于binder的機(jī)制胸嘁,后面在單獨(dú)開篇介紹。使用bindService啟動的service的開發(fā)過程中一般都會借助aidl凉逛。這里不介紹aidl性宏,因?yàn)檫@不是本文的重點(diǎn)。

當(dāng)一個(gè)app進(jìn)程bindService()時(shí)状飞,它需要先準(zhǔn)備好一個(gè)實(shí)現(xiàn)了ServiceConnection接口的對象毫胜。ServiceConnection的定義如下:

public interface ServiceConnection {

    public void onServiceConnected(ComponentName name, IBinder service);

    public void onServiceDisconnected(ComponentName name);
}

bindService()見名知意即綁定服務(wù),建立一個(gè)邏輯連接诬辈。當(dāng)連接建立之后酵使,AMS會回調(diào)ServiceConnection接口對象的onServiceConnected()方法。把遠(yuǎn)端service的代理binder傳遞過來自晰,這樣就可以通過這個(gè)代理binder跨進(jìn)程調(diào)用service中的方法了凝化。

ServiceConnection接口的onServiceDisconnected()方法并不會在unbindService()操作斷開邏輯連接時(shí)執(zhí)行。而是在遠(yuǎn)端service進(jìn)程終止時(shí)酬荞,AMS才會回調(diào)onServiceDisconnected()搓劫。

另外要注意的是縱然service進(jìn)程的因?yàn)槟承┰虮唤K止瞧哟,之前的綁定在該service上的邏輯連接仍處于激活狀態(tài),當(dāng)service再次運(yùn)行的時(shí)候枪向,AMS會回調(diào)onServiceConnected勤揩。

bindService的過程,我們要關(guān)心的binder有兩個(gè)秘蛔,一個(gè)是遠(yuǎn)端service的binder陨亡,有了它客戶端進(jìn)程才能跨進(jìn)程調(diào)用service中的方法;另一個(gè)是binder是客戶端傳遞給AMS的深员,有了這個(gè)binder负蠕,AMS才會在邏輯連接建立之后,跨進(jìn)程調(diào)用客戶端中的ServiceConnection接口的對象中的onServiceConnected()和onServiceDisconnected()倦畅。

要明白bindservice的過程遮糖,就必須搞清楚這兩個(gè)binder的傳遞過程他。

另外bindservice在建立連接時(shí)叠赐,如果發(fā)現(xiàn)service還沒啟動欲账,會根據(jù)flag是否設(shè)置BIND_AUTO_CREATE,決定是否啟動這個(gè)service芭概。

同startService()一樣赛不,bindService()也是一個(gè)異步的過程,也就是說當(dāng)該方法返回時(shí)罢洲,邏輯連接很可能還沒有建立踢故,通俗的說就是該方法返回時(shí),onServiceConnected()方法很可能還沒執(zhí)行惹苗。

app的service和系統(tǒng)的service

系統(tǒng)中的servcice都是由ServiceManager負(fù)責(zé)管理的畴椰。系統(tǒng)中的service在啟動的時(shí)候,都會向ServiceManager注冊鸽粉。

App進(jìn)程要使用這些系統(tǒng)service時(shí),比如AMS抓艳,可以向ServiceManager通過service名字查詢触机。ServiceManager會返回這個(gè)service的一個(gè)代理binder。這樣便可以向service發(fā)起調(diào)用請求了玷或。

但是app是沒有權(quán)限向ServiceManager注冊service的儡首。所以只能另辟蹊徑。bindService要負(fù)責(zé)找到service的代理binder并傳遞到app進(jìn)程偏友。這期間涉及到binder實(shí)體的跨進(jìn)程傳輸蔬胯,也就是所謂的匿名binder。因?yàn)檫@些binder并沒有在ServiceManager中注冊位他。

bindService的過程

整個(gè)過程大體上是這樣的:

  1. 檢查要綁定的額service是否啟動氛濒,沒有的話产场,要先啟動service,然后執(zhí)行service的生命周期方法舞竿。

  2. 執(zhí)行綁定京景,先將遠(yuǎn)端service的binder傳遞到AMS中,然后AMS在將其傳遞到客戶端組件進(jìn)程中

ContextImpl.bindService():

public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, Process.myUserHandle());
    }

ContextImpl.bindServiceCommon():

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
        IServiceConnection sd;
      ................
        if (mPackageInfo != null) {
          //從LoadedApk中拿到一個(gè)binder實(shí)體
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        //  Android5.0之后不允許使用隱式調(diào)用
        // 這里對傳入的intetn進(jìn)行檢查骗奖,如果是android5.0以上确徙,
        //是隱式intent的話拋出異常
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            ....................
            service.prepareToLeaveProcess();
            // 向AMS發(fā)起跨進(jìn)程調(diào)用其bindService方法
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
          ..............................
            return res != 0;
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
    }

這里便引出了第一個(gè)binder:IServiceConnection sd。這是一個(gè)實(shí)體binder执桌,也就是說跨進(jìn)程傳輸?shù)紸MS進(jìn)程之后鄙皇,AMS進(jìn)程中最終得到的是一個(gè)代理binder。而且binder實(shí)體跨進(jìn)程傳輸過程中仰挣,會在binder驅(qū)動層中為其創(chuàng)建相應(yīng)的數(shù)據(jù)結(jié)構(gòu)伴逸,這樣binder便在binder驅(qū)動中扎根了。

那么這個(gè)binder實(shí)體最初是從哪里來的呢椎木?

客戶端組件中用來調(diào)度綁定操作的ServiceDispatcher對象

此處的mPackageInfo是用戶進(jìn)程里和apk對應(yīng)的LoadedApk對象违柏,前面所說的第一個(gè)binder實(shí)體由LoadedApk.getServiceDispatcher()獲得:

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
           Context context, Handler handler, int flags) {
       synchronized (mServices) {
           LoadedApk.ServiceDispatcher sd = null;
            // 先從LoadedApk.mService中查找,
            // 看看發(fā)起綁定操作的組件是否已經(jīng)存在一個(gè)用來處理傳入的
            //ServiceConnection接口對象的ServiceDispatcher
           ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
           if (map != null) {
              // 存在的話直接返回這個(gè)ServiceDispatcher
               sd = map.get(c);
           }
           if (sd == null) {
              // 不存在的話創(chuàng)建一個(gè)ServiceDispatcher
              // 這里要注意第三個(gè)參數(shù)handler香椎,是主線程的handler
              // 保存在了ServiceDispatcher.mActivityThread中
               sd = new ServiceDispatcher(c, context, handler, flags);
               if (map == null) {
                   map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                   mServices.put(context, map);
               }
                // 將創(chuàng)建的ServiceDispatcher緩存到LoadedApk.mService
               map.put(c, sd);
           } else {
               sd.validate(context, handler);
           }
           return sd.getIServiceConnection();
       }
   }

LoadedApk.ServiceDispatcher從它的名字中可以看出它類似于一個(gè)Dispatcher的作用漱竖,這個(gè)類的作用就是當(dāng)client bind某個(gè)service成功之后,負(fù)責(zé)向client分配service IBinder的畜伐;以及當(dāng)client unbind service時(shí)馍惹,負(fù)責(zé)通知client unbind service的狀態(tài)。

對于ServiceDispatcher的管理玛界,是以apk万矾,即package為載體的,也就是說對于某個(gè)package慎框,定義在其中的component如果請求去bind一個(gè)service良狈,那么LoadedApk將為這個(gè)component分配一個(gè)ServiceDispatcher。

component每請求bind一個(gè)service笨枯,都會為其指定一個(gè)ServiceConnection接口的對象薪丁,同一component組件內(nèi),LoadedApk將會為這個(gè)ServiceConnection接口的對象分配一個(gè)唯一的ServiceDispatcher馅精。但是不同component組件中严嗜,就算是使用同一個(gè)ServiceConnection接口的對象,LoadedApk中也會為這個(gè)對象分配兩個(gè)ServiceDispatcher對象洲敢。

也就是說漫玄,ServiceDispatcher是客戶端組件相關(guān)的一個(gè)概念。

每個(gè)app進(jìn)程中是可以加載多個(gè)apk包的压彭,記錄在ActivityThread.mPackages,整個(gè)關(guān)系如下所示:

android_app_service-6.png

packages中的組件component睦优,例如某個(gè)activity中使用bindService去綁定一個(gè)service時(shí)渗常,都需要提供一個(gè)實(shí)現(xiàn)ServiceConnection接口的對象,每一個(gè)這樣的對象都會與一個(gè)ServiceDispatcher對象綁定刨秆。

LoadedApk.mServices中存儲了本package中所有組件中所有的ServiceDispatcher凳谦。它是一個(gè)ArrayMap,key是context衡未,實(shí)際上就是組件尸执,因?yàn)榻M件繼承自Context。value又是一個(gè)ArrayMap缓醋,因?yàn)橐粋€(gè)組件中使可以綁定多個(gè)service的嘛如失。這個(gè)map的可以是實(shí)現(xiàn)了ServiceConnection接口的對象,value是與之綁定的ServiceDispatcher對象送粱。

現(xiàn)在可以看看這個(gè)ServiceDispatcher到底是個(gè)什么東東了:

static final class ServiceDispatcher {
    // 一個(gè)binder實(shí)體對象
    private final ServiceDispatcher.InnerConnection mIServiceConnection;
    // 邏輯連接建立時(shí)褪贵,執(zhí)行的回調(diào)接口對象
    private final ServiceConnection mConnection;
    // 所在的組件,即client
    private final Context mContext;
    // 進(jìn)程主線程即UI線程中的handler
    private final Handler mActivityThread;
    private final ServiceConnectionLeaked mLocation;
    // 綁定service時(shí)抗俄,傳入的flag脆丁,例如BIND_AUTO_CREATE
    private final int mFlags;

    private RuntimeException mUnbindLocation;
    private boolean mDied;
    private boolean mForgotten;
    // 因?yàn)橐粋€(gè)ServiceConnection可以被bindService方法多次調(diào)用,用來啟動不同的service动雹,
    // 那么ServiceDispatcher中自然要存儲這些連接信息了:
    // ConnectionInfo很簡單只有兩個(gè)屬性成員
    // IBinder binder;遠(yuǎn)端service的引用binder
    // IBinder.DeathRecipient deathMonitor; 遠(yuǎn)端binder的死亡通知方法
    private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
       = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
................
  }

ServiceDispatcher.InnerConnection是一個(gè)繼承自 IServiceConnection.Stub的binder實(shí)體類:

private static class InnerConnection extends IServiceConnection.Stub {
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
            }

            public void connected(ComponentName name, IBinder service) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
}

其中ServiceDispatcher.connected():

public void connected(ComponentName name, IBinder service) {
    // 這里的mActivityThread是主線程的handler
    // 也就是說槽卫,實(shí)際上ServiceConnection中的回調(diào)是在主線程中執(zhí)行的
      if (mActivityThread != null) {
          mActivityThread.post(new RunConnection(name, service, 0));
      } else {
          doConnected(name, service);
      }
}

ServiceDispatcher.InnerConnection是一個(gè)繼承自 IServiceConnection.Stub的binder實(shí)體類,從其名字上來看是一個(gè)內(nèi)部連接胰蝠,該怎么理解呢歼培?

因?yàn)閎indService()傳遞的ServiceConnection接口對象,并沒有跨進(jìn)程傳輸?shù)紸MS中茸塞,從bindServiceCommon()方法可以看出最終傳遞到AMS的是LoadedApk.getServiceDispatcher()返回的ServiceDispatcher.InnerConnection躲庄。AMS通過它跨進(jìn)程間接調(diào)用ServiceConnection中的方法。

因?yàn)橐粋€(gè)ServiceConnection可以在同一個(gè)客戶端組件內(nèi)被bindService方法多次調(diào)用钾虐,用來綁定不同的service噪窘,那么ServiceDispatcher中自然要存儲這些使用同一個(gè)serviceConnection綁定的service的連接信息了——ServiceDispatcher.mActiveConnections。

它是ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>類型對象效扫,


private static class ConnectionInfo {
  // 遠(yuǎn)端service的代理binder
  IBinder binder;
  // 遠(yuǎn)端service 死亡通知回調(diào)
  IBinder.DeathRecipient deathMonitor;
}

AMS中綁定service過程

ContextImpl.bindServiceCommon()方法中得到ServiceConnection對應(yīng)的ServiceDispatcher對象之后效览,便向AMS發(fā)起請求,跨進(jìn)程調(diào)用AMS.bindService():


public int bindService(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags, String callingPackage,
        int userId) throws TransactionTooLargeException {
    enforceNotIsolatedCaller("bindService");

    ..............
    synchronized(this) {
      // mServices是ActiveService
        return mServices.bindServiceLocked(caller, token, service,
                resolvedType, connection, flags, callingPackage, userId);
    }
}

AMS.bindService()對參數(shù)做了簡單檢查之后荡短,又調(diào)用ActiveService.bindServiceLocked()方法。

這里先對ActiveService.bindServiceLocked()方法的幾個(gè)重要參數(shù)做一些說明:

int bindServiceLocked(
         IApplicationThread caller, // 客戶端進(jìn)程ActivityThread.mAppThread的代理binder
         IBinder token,
         Intent service,// 客戶端綁定service時(shí)的intent
         String resolvedType,
         IServiceConnection connection, //客戶端進(jìn)程的中ServiceDispatcher.InnerConnection的代理binder
         int flags,
         String callingPackage, int userId) throws TransactionTooLargeException {

ActiveService.bindServiceLocked()與上一篇介紹的startService的ActiveService.startServiceLocked()方法中有很多相似的邏輯哆键。

比如同樣是要先查找要啟動的servicee在AMS中的代表ServiceRecord是否存在掘托,存在的話弟疆,意味著service已經(jīng)啟動泪勒;不存在的話吕嘀,要創(chuàng)建一個(gè)ServiceRecord對象障斋,這些操作還是由retrieveServiceLocked()方法負(fù)責(zé)的。然后通過bringUpServiceLocked()調(diào)用service的生命周期方法泪掀。只不過bindservice除了這兩個(gè)基本操作外听绳,還要執(zhí)行綁定操作,即將service的binder傳跨進(jìn)程傳輸?shù)絘pp客戶端組件中异赫。

綁定前的準(zhǔn)備工作

執(zhí)行綁定操作前椅挣,要先做一些準(zhǔn)備工作,比如在AMS中記錄客戶端和service的一些信息塔拳,下面的代碼就是做這些事情的:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
           String resolvedType, IServiceConnection connection, int flags,
           String callingPackage, int userId) throws TransactionTooLargeException {
  ...............
  // 得到service對應(yīng)的ServiceRecord
  ServiceLookupResult res =
      retrieveServiceLocked(service, resolvedType, callingPackage,
              Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
  ServiceRecord s = res.record;
  ....
  // 根據(jù)傳入的intent和發(fā)起者進(jìn)程鼠证,查找到一個(gè)合適的AppBindRecord對象,
  // 查找不到就創(chuàng)建一個(gè)靠抑,下面會介紹規(guī)則
  AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
  // 為本次連接創(chuàng)建ConnectionRecord對象
  ConnectionRecord c = new ConnectionRecord(b, activity,
          connection, flags, clientLabel, clientIntent);
  // 客戶端進(jìn)程的中ServiceDispatcher.InnerConnection的代理binder
  IBinder binder = connection.asBinder();
  // 將創(chuàng)建的邏輯連接對象ConnectionRecord量九,記錄在ServiceRecord中
  ArrayList<ConnectionRecord> clist = s.connections.get(binder);
  if (clist == null) {
      clist = new ArrayList<ConnectionRecord>();
      s.connections.put(binder, clist);
  }
  clist.add(c);
  // 同時(shí)記錄在AppBindRecord.connections中
  b.connections.add(c);
  // AppBindRecord.client是ProcessRecord,代表客戶端的進(jìn)程
  b.client.connections.add(c);
  .......
  // 除了ServiceRecord.connections記錄了該service連接信息外
  // ActiveService.mServiceConnections記錄了當(dāng)前系統(tǒng)中所有的連接信息
  // 所以也要將創(chuàng)建的連接對象,加入ActiveService.mServiceConnections
  clist = mServiceConnections.get(binder);
  if (clist == null) {
      clist = new ArrayList<ConnectionRecord>();
      mServiceConnections.put(binder, clist);
  }
  clist.add(c);
 ............

在前面關(guān)于service機(jī)制介紹的文章中提到過ServiceRecord中有一些數(shù)據(jù)成員是bindservice時(shí)用到的:

final class ServiceRecord extends Binder {
    ...............
    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
                = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();// IBinder -> ConnectionRecord of all bound clients
    // service所在的進(jìn)程
    ProcessRecord app;      // where this service is running or null.
}

AMS描述綁定service時(shí)的intent的IntentBindRecord類

app客戶端組件中發(fā)起綁定service操作時(shí)颂碧,一定要用到intent荠列,一般是顯示的intent(android 5.0 之后要求必須是顯示intent),而且只設(shè)置intetn.mComponent字段载城。

AMS中對綁定操作傳入的intent是用Intent.FilterComparison類來描述,也就是說當(dāng)客戶端綁定service時(shí)使用的intent指定的參數(shù)都一致的話肌似,AMS會將其看做是同一類intent。

AMS會為這類intent為其創(chuàng)建一個(gè)IntentBindRecord對象个曙。

final class IntentBindRecord {
    // 綁定的service在AMS中的代表
    final ServiceRecord service;
    /** The intent that is bound.*/
    final Intent.FilterComparison intent; //
    /** All apps that have bound to this Intent. */
    final ArrayMap<ProcessRecord, AppBindRecord> apps
            = new ArrayMap<ProcessRecord, AppBindRecord>();
    // service的binder代理binder
    IBinder binder;

其中IntentBindRecord.service 最終會保存綁定的service的ServiceRecord锈嫩;

IntentBindRecord.intent 就是前面所說的綁定service時(shí)設(shè)定的參數(shù)一致的intent在AMS中的表示Intent.FilterComparison對象;

IntentBindRecord.apps用來記錄所有使用該類intetn綁定同一個(gè)service的客戶端信息垦搬。key是客戶端進(jìn)程ProcessRecord呼寸,value是AppBindRecord。因?yàn)椴煌目蛻舳丝赡苁褂孟嗤膇ntent參數(shù)來綁定同一個(gè)service,所以IntentBindRecord要記錄下這些客戶端信息猴贰;

IntentBindRecord.binder最終保存service的代理binder对雪;

AMS通過ServiceRecord.retrieveAppBindingLocked()方法為判斷是否為傳入的intent創(chuàng)建一個(gè)IntentBindRecord:

public AppBindRecord retrieveAppBindingLocked(
           Intent intent,// 客戶端發(fā)起綁定操作時(shí)傳入的intent
           ProcessRecord app // 客戶端組件進(jìn)程) {
       // 為傳入的intent創(chuàng)建一個(gè)Intent.FilterComparison
       Intent.FilterComparison filter = new Intent.FilterComparison(intent);
       // 查找傳入的intent是否已經(jīng)有IntentBindRecord
       IntentBindRecord i = bindings.get(filter);
       if (i == null) {
          // 沒有的話創(chuàng)建
           i = new IntentBindRecord(this, filter);
           //并緩存到ServiceRecord.bings中
           bindings.put(filter, i);
       }
       // 查找客戶端的組件是否已經(jīng)綁定過該service
       AppBindRecord a = i.apps.get(app);
       // 綁定過的話,返回找到的AppBindRecord
       if (a != null) {
           return a;
       }
       // 沒有的話創(chuàng)建一個(gè)AppBindRecord對象
       a = new AppBindRecord(this, i, app);
       // 并緩存到IntentBindRecord.apps中
       i.apps.put(app, a);
       return a;
   }

retrieveAppBindingLocked()另一個(gè)主要作用是查找并創(chuàng)建AppBindRecord對象米绕。

AMS用于描述綁定service的客戶端整體信息的AppBindRecord類

對于一個(gè)Service來說瑟捣,有多少app客戶端進(jìn)程和它建立了綁定關(guān)系,就會有多少個(gè)AppBindRecord對象栅干。一個(gè)app客戶端進(jìn)程里可以有多個(gè)地方發(fā)起綁定動作迈套,所以AppBindRecord里需要用一個(gè)ArraySet<ConnectionRecord>記錄下每個(gè)綁定動作對應(yīng)的邏輯連接對象。

final class AppBindRecord {
    // 所在的service
    final ServiceRecord service;    // The running service.
    // 客戶端發(fā)起的bindservice時(shí)傳入的intent碱鳞,AMS會為其創(chuàng)建一個(gè)對應(yīng)的IntentBindRecord
    final IntentBindRecord intent;  // The intent we are bound to.
    // 客戶端進(jìn)程
    final ProcessRecord client;     // Who has started/bound the service.
    // 客戶端所在的app桑李,其他組件綁定該service的邏輯連接
    final ArraySet<ConnectionRecord> connections = new ArraySet<>();
                                    // All ConnectionRecord for this client.

AppBindRecord.service 用于描述客戶端綁定的service;

AppBindRecord.intent 用于描述客戶端綁定該service時(shí)使用的intent;

AppBindRecord.client 用于描述客戶端的進(jìn)程贵白;

AppBindRecord.connections 用于描述客戶端中所有組件綁定該service時(shí)創(chuàng)建的邏輯連接率拒;

AMS通過ServiceRecord.retrieveAppBindingLocked()來查找并創(chuàng)建一個(gè)合適的AppBindRecord對象。

描述綁定連接的ConnectionRecord類

AMS為每次綁定過程中創(chuàng)建的連接分配一個(gè)ConnectionRecord類型對象.

ConnectionRecord用來描述一個(gè)連接信息禁荒,即綁定信息猬膨,要對客戶端和service端進(jìn)行描述。

/**
* Description of a single binding to a service.
*/
final class ConnectionRecord {
   // 記錄客戶端綁定的信息
   final AppBindRecord binding;    // The application/service binding.
   // 這里是綁定服務(wù)的客戶端的一個(gè)binder呛伴,通過它可以調(diào)用客戶端的方法
   // ServiceConnection.onServiceConnected()
   final IServiceConnection conn;  // The client connection.
   final int flags;                // Binding options.

ConnectionRecord.binding代表這個(gè)連接所在的AppBindRecord.

ConnectionRecord.coon是一個(gè)binder代理對象勃痴,其實(shí)體binder是app進(jìn)程中ServiceDispatcher.mIServiceConnection。用來回調(diào)客戶端進(jìn)程中當(dāng)連接成功建立時(shí)的回調(diào)方法磷蜀。

客戶端組件在bindservice時(shí)召耘,都要創(chuàng)建一個(gè)實(shí)現(xiàn)ServiceConnection接口的對象,每個(gè)這樣的對象在客戶端組件所在的LoadedApk中都會分配一個(gè)ServiceDispatcher對象褐隆,這個(gè)對象用于處理所有使用該ServiceConnection接口的對象綁定service的客戶端組件的回調(diào)方法的執(zhí)行污它。

ConnectionRecord.flags 用于描述綁定該service時(shí),指定的flags庶弃,例如BIND_AUTO_CREATE.

AMS創(chuàng)建的ConnectionRecord對象會存儲在ServiceRecord.connections成員變量中.

ServiceRecord.connections是一個(gè)map衫贬,key是ServiceDispatcher.InnerConnection的代理binder,value是ArrayList<ConnectionRecord>類型的歇攻。

因?yàn)榭蛻舳诉M(jìn)程中一個(gè)Component中可能使用同一個(gè)ServiceConnection接口對象來多次綁定同一個(gè)service固惯,因?yàn)槊看谓壎ǘ紩?chuàng)建一個(gè)ConnectionRecord對象,那么這些ConnectionRecord需要使用ArrayList<ConnectionRecord>來保存缴守。

value中ConnectionRecord.IServiceConnection實(shí)際上一致與key是一致的葬毫。

AMS除了將這個(gè)"邏輯連接"ConnectionRecord對象,記錄在ServiceRecord.connections中外屡穗,還要向至少下面的幾處位置做記錄:

  1. 客戶端所在的進(jìn)程在AMS中的代表ProcessRecord.connections

  2. ActiveService.mServiceConnections,這里面記錄了AMS中所有app的service的連接

  3. AppBindRecord.connections中

之所以要在這么多地方做記錄贴捡,可能是為了在不同的場合下迅速查找到連接吧。

了解了以上內(nèi)容后村砂,就可以通過下圖簡明的描述客戶端進(jìn)程和AMS之間的關(guān)系:

android_app_service-7.png

執(zhí)行service生命周期方法

在做好前面的準(zhǔn)備工作之后烂斋,binderservice()就開始準(zhǔn)備與Service建立連接了。那么自然要先對service進(jìn)行一些操作础废,說白了就是執(zhí)行service的生命周期方法汛骂,這是由bringUpServiceLocked()方法來負(fù)責(zé)的。

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
           String resolvedType, IServiceConnection connection, int flags,
           String callingPackage, int userId) throws TransactionTooLargeException {
.................
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
    s.lastActivity = SystemClock.uptimeMillis();
    // 只有當(dāng)要綁定的service所在的進(jìn)程還啟動的時(shí)候评腺,該方法返回非null
    // 因?yàn)閱舆M(jìn)程需要一段時(shí)間帘瞭,所以就要先退出來
    // 這里暫時(shí)假設(shè)service所在的進(jìn)程已經(jīng)啟動
    if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
        return 0;
    }
}
....................

此時(shí)可以分為兩大情況:

  1. service進(jìn)程還沒啟動

  2. service進(jìn)程已經(jīng)啟動,此時(shí)有可分為兩種情況:service還沒啟動和service已經(jīng)運(yùn)行蒿讥。
    bringUpServiceLocked()方法依據(jù)ServiceRecord.app區(qū)分以上兩大情況:

1.ServiceRecord.app不為null图张,而且ServiceRecord.app.thread也不為null锋拖,預(yù)示著service已經(jīng)運(yùn)行了,但是這時(shí)候并不會向startService()啟動service那樣跨進(jìn)程調(diào)用service.onStartCommand()生命周期方法祸轮,因?yàn)閎indService啟動service時(shí)沒有將信息記錄到ServiceRecord.pendingStarts。

2.ServiceRecord.app為null侥钳,說明ServiceRecord還沒有和service所在的進(jìn)程關(guān)聯(lián)适袜。

此時(shí)在依據(jù)ServiceRecord.processName,也就是service要求運(yùn)行在的進(jìn)程的名字,在AMS中查找是否有這樣的進(jìn)程存在舷夺,如果有的話苦酱,只需要啟動service,也就是在找到的進(jìn)程中創(chuàng)建service對象给猾,并執(zhí)行service.onCreate()生命周期方法疫萤。

以上兩種情況的詳細(xì)過程,參考前一篇文章敢伸。

如果沒有在AMS中找到名字為ServiceRecord.processName的進(jìn)程扯饶,那么就要先創(chuàng)建進(jìn)程了,這里不考慮這種情況池颈。

綁定service

綁定實(shí)際上就是想辦法拿到service的binder尾序,并將其傳遞到客戶端組件進(jìn)程,另外還要對前面準(zhǔn)備工作期間創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)設(shè)置相關(guān)的字段躯砰。

這部分代碼如下:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
           String resolvedType, IServiceConnection connection, int flags,
           String callingPackage, int userId) throws TransactionTooLargeException {
.................
// b.intent.received為true每币,表明已經(jīng)拿到了service的binder
f (s.app != null && b.intent.received) {
        // Service is already running, so we can immediately
        // publish the connection.
        try {
            // 這里就可以直接遠(yuǎn)程調(diào)用客戶端組件中onServiceConnected()方法將service的binder傳遞過去了
            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.
        if (b.intent.apps.size() == 1 && b.intent.doRebind) {
            requestServiceBindingLocked(s, b.intent, callerFg, true);
        }
    } else if (!b.intent.requested) {
        // 之前沒綁定過,那么就調(diào)用下面的額方法進(jìn)行綁定
        requestServiceBindingLocked(s, b.intent, callerFg, false);
    }

    getServiceMap(s.userId).ensureNotStartingBackground(s);

} finally {
    Binder.restoreCallingIdentity(origId);
}

這里分兩種情況:

  1. 客戶端組件之前已經(jīng)綁定過該service琢歇,現(xiàn)在這個(gè)組件又要再次綁定兰怠,也就是客戶端同一組件重復(fù)綁定

  2. 客戶端組件首次綁定該service

這兩種情況的區(qū)分是依據(jù)AppBindRecord.intent,即AMS為bindservice()傳入的intent分配的IntentBindRecord對象來決定的李茫。

final class IntentBindRecord {
  /** Binder published from service. */
  IBinder binder;
  /** Set when we have initiated a request for this binder. */
  boolean requested;
  /** Set when we have received the requested binder. */
  boolean received;
  /** Set when we still need to tell the service all clients are unbound. */
  boolean hasBound;
}

IntentBindRecord.received為true揭保,表明IntentBindRecord.binder已經(jīng)指向遠(yuǎn)端service的binder;

IntentBindRecord.requested為false涌矢,表明IntentBindRecord.binder還沒有指向遠(yuǎn)端service的binder掖举;

這里分析第二種情況,時(shí)序圖如下:

android_app_service-9.png

requestServiceBindingLocked()方法中跨進(jìn)程調(diào)用service所在的進(jìn)程中方法,最終會導(dǎo)致service.onBind()執(zhí)行娜庇,該方法返回service的實(shí)體binder塔次。

這里有一點(diǎn)要貼別注意,那只要service被某個(gè)客戶端組件綁定過了名秀,就不會再執(zhí)行service.onBind()方法了励负,原因就在requestServiceBindingLocked()方法中:

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {

        ..............
        // 傳入的rebind為false還是true,取決于AMS調(diào)用service.onUnbind()返回值
        // 如果希望客戶端下一次綁定到服務(wù)時(shí)接收 onRebind() 調(diào)用(而不是接收 onBind() 調(diào)用)匕得,onUnbind()返回true
        // service首次被綁定時(shí)继榆,rebind肯定為false
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                // 跨進(jìn)程調(diào)用service所在進(jìn)程的scheduleBindService()方法巾表,執(zhí)行綁定操作,這是一個(gè)異步方法略吨,會立即返回
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    // 只要service被綁定過了集币,IntentBindRecord.requested就會被設(shè)置為true
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (TransactionTooLargeException e) {
              .................
            } catch (RemoteException e) {
              .................
            }
        }
        return true;
    }

通過以上代碼可知,只要service被綁定過一次翠忠,那么IntentBindRecord.requested救回被設(shè)置為true鞠苟,其他客戶端組件再次綁定的時(shí)候,由于if條件為假秽之,所以不會再次跨進(jìn)程調(diào)用service進(jìn)程中的scheduleBindService()方法当娱,也就不會調(diào)用service.onBind()方法了。

因?yàn)閎indservice時(shí)傳入的intent一般都是顯示intent考榨,不會設(shè)置其他參數(shù)跨细,所以只要客戶端綁定的是同一個(gè)service,那么在AMS中只會有一個(gè)IntentBindRecord對象河质。

除非該servcie綁定過之后冀惭,所有綁定它的客戶端組件都執(zhí)行了unbindService(),那么最終會導(dǎo)致service.onUnbind()方法執(zhí)行愤诱,如果該方法返回了true云头,那么下次再有客戶端組件綁定該service時(shí),rebind會被設(shè)置為true淫半,這導(dǎo)致不會調(diào)用service.onBind()溃槐,而是調(diào)用service.rebind()方法。如下代碼所示:

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 {
                    // 傳入flase時(shí)執(zhí)行onBind()
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManagerNative.getDefault().publishService(
                                data.token, data.intent, binder);
                    } else {
                      // 傳入true時(shí)執(zhí)行onRebind()
                        s.onRebind(data.intent);
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

這里考慮首次綁定時(shí)的情況科吭,所以rebind肯定為false昏滴,那么service調(diào)用過onBind()之后,又通過AMS的代理对人,跨進(jìn)程調(diào)用AMS的publishService()將service的binder傳遞到AMS中谣殊,然后在傳遞到客戶端。

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
.......
IntentBindRecord b = r.bindings.get(filter);
// 初次綁定
if (b != null && !b.received) {
      // 保存service的代理binder
      b.binder = service;
      // 設(shè)置下面的兩個(gè)標(biāo)志為true
      b.requested = true;
      b.received = true;
      // 一般情況下牺弄,首次綁定時(shí)姻几,connections.size為1
      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 {
                   // 將service的binder傳遞到客戶端
                   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);
               }
           }
       }
   }
...........

那么當(dāng)首次綁定之后,又有其他客戶端組件來綁定這個(gè)service势告,那么在bindServiceLocked()方法中蛇捌,會直接跨進(jìn)程調(diào)用客戶端的connected():

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, IServiceConnection connection, int flags,
        String callingPackage, int userId) throws TransactionTooLargeException {
        ................
        if (s.app != null && b.intent.received) {
              // Service is already running, so we can immediately
              // publish the connection.
              try {
                  // 直接跨進(jìn)程調(diào)用客戶端的connected()
                  // 不在需要跨進(jìn)程調(diào)用service.onBind()
                  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);
              }
        ..........................

}

在看客戶端進(jìn)程的connected()

public void connected(ComponentName name, IBinder service) throws RemoteException {
    // 先得到處理ServiceConnection的ServiceDispatcher
    LoadedApk.ServiceDispatcher sd = mDispatcher.get();
    if (sd != null) {
        sd.connected(name, service);
    }
}
public void connected(ComponentName name, IBinder service) {
   // mActivityThread是在創(chuàng)建 ServiceDispatcher對象時(shí),傳入的組件所在進(jìn)程的主線程的handler
   // 也就是說RunConnection是在組件所在的主線程中執(zhí)行的
   if (mActivityThread != null) {
       mActivityThread.post(new RunConnection(name, service, 0));
   } else {
       doConnected(name, service);
   }
}

RunConnection.run()中會調(diào)用LoadedApk.doConnected()方法:

public void run() {
    if (mCommand == 0) {
        doConnected(mName, mService);
    } else if (mCommand == 1) {
        doDeath(mName, mService);
    }
}

LoadedApk.doConnected():


public void doConnected(ComponentName name, IBinder service) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;

    synchronized (this) {
        .....................
        ServiceDispatcher.ConnectionInfo old;
        //很有意思咱台,也就是說同一組件中對同一個(gè)service重復(fù)綁定络拌,onServiceConnected()只會執(zhí)行一次
        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 {
                // 設(shè)置死亡回調(diào)
                service.linkToDeath(info.deathMonitor, 0);
                // 將info保存在LoadedApk.mActiveConnections
                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) {
      // 執(zhí)行回調(diào)
        mConnection.onServiceConnected(name, service);
    }
}

doConnected()比較有意思的是下面的代碼:

ServiceDispatcher.ConnectionInfo old;
old = mActiveConnections.get(name);
      if (old != null && old.binder == service) {
          // Huh, already have this one.  Oh well!
          return;
}

mActiveConnections來自ServiceDispatcher:

private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
            = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();

ServiceDispatcher.mActiveConnections用來記錄該LoadedApk中的組件所綁定的service的連接信息。key是service的組件名回溺,value是ServiceDispatcher.ConnectionInfo春贸。

ConnectionInfo中記錄了service的代理binder以及死亡通知回調(diào)混萝。


private static class ConnectionInfo {
  // 遠(yuǎn)端service的代理binder
  IBinder binder;
  // 遠(yuǎn)端service 死亡通知回調(diào)
  IBinder.DeathRecipient deathMonitor;
}

connected(ComponentName name, IBinder service)方法的第一個(gè)參數(shù)是service的組件名,第二個(gè)參數(shù)是service的代理binder萍恕。

connected()方法中首先以name為key在mActiveConnections查找逸嘀,如果索引到的ConnectionInfo的binder與傳入的binder一致的話,說明是同一組件內(nèi)使用同一個(gè)ServiceConnection接口對象對同一個(gè)service重復(fù)綁定允粤,此時(shí)不會執(zhí)行onServiceConnected()方法厘熟。

unbindeService

現(xiàn)在在看一下unbindeService()的過程,直接看AMS.unbindServiceLocked()维哈,整個(gè)過程大體上就是找到相關(guān)的連接對象ConnectionRecord,將其從相關(guān)的map中移除,然后根據(jù)情況決定是否調(diào)用serive.onUnbind生命周期方法

boolean unbindServiceLocked(IServiceConnection connection) {
       // 得到ServiceDispatcher.InnerConnection的binder
       IBinder binder = connection.asBinder();
       if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
       // 前面說了ActiveService.mServiceConnections,這里面記錄了AMS中所有app的service的連接
       // 自然也包括同一組件內(nèi)使用同一個(gè)ServiceConnection綁定同一個(gè)service的情況
       ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
       // 說明沒有使用該ServiceConnection接口對象綁定過service
       // 所以無需unbind
       if (clist == null) {
           Slog.w(TAG, "Unbind failed: could not find connection for "
                 + connection.asBinder());
           return false;
       }

       final long origId = Binder.clearCallingIdentity();
       try {
           // 依次取出同一組件內(nèi)使用該ServiceConnection接口對象綁定的service的連接信息對象ConnectionRecord
           // 這里要注意的是登澜,這相當(dāng)于在發(fā)起unbindService()操作的組件中阔挠,對所有使用該ServiceConnection接口對象綁定的sercvice
           // 發(fā)起unbindService操作
           while (clist.size() > 0) {
               ConnectionRecord r = clist.get(0);
               removeConnectionLocked(r, null, null);
               if (clist.size() > 0 && clist.get(0) == r) {
                   // In case it didn't get removed above, do it now.
                   Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
                   clist.remove(0);
               }
               if (r.binding.service.app != null) {
                   // This could have made the service less important.
                   if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
                       r.binding.service.app.treatLikeActivity = true;
                       mAm.updateLruProcessLocked(r.binding.service.app,
                               r.binding.service.app.hasClientActivities
                               || r.binding.service.app.treatLikeActivity, null);
                   }
                   mAm.updateOomAdjLocked(r.binding.service.app);
               }
           }
       } finally {
           Binder.restoreCallingIdentity(origId);
       }

       return true;
   }

再看removeConnectionLocked():

    void removeConnectionLocked(
        ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
        IBinder binder = c.conn.asBinder();
        AppBindRecord b = c.binding;
        ServiceRecord s = b.service;
        // 從ServiceRecord中取出所有綁定該service的連接
        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
        if (clist != null) {
            // 將使用要unbindService()的ServiceConnection創(chuàng)建的連接
            // 從ServiceRecord.connections中移除
            clist.remove(c);
            if (clist.size() == 0) {
                s.connections.remove(binder);
            }
        }
        // 將使用要unbindService()的ServiceConnection創(chuàng)建的連接
        // 從AppBindRecord.connections中移除
        b.connections.remove(c);
        if (c.activity != null && c.activity != skipAct) {
            if (c.activity.connections != null) {
                c.activity.connections.remove(c);
            }
        }
        if (b.client != skipApp) {
            b.client.connections.remove(c);
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.updateHasAboveClientLocked();
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
        }
        clist = mServiceConnections.get(binder);
        if (clist != null) {
            // 將使用要unbindService()的ServiceConnection創(chuàng)建的連接
            // 從ActiveService.mServiceConnections中移除
            clist.remove(c);
            if (clist.size() == 0) {
                mServiceConnections.remove(binder);
            }
        }

        mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);

        // 如果AppBindRecord.connections.size為0
        // 表示某客戶端已經(jīng)沒有組件與該service綁定了
        // 那么將客戶端從IntentBindRecord.apps中移除
        if (b.connections.size() == 0) {
            b.intent.apps.remove(b.client);
        }

        if (!c.serviceDead) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
                    + ": shouldUnbind=" + b.intent.hasBound);
            // 如果IntentBindRecord.apps.size為0,表示沒有客戶端與該service綁定了
            // 那么開始回調(diào)service進(jìn)程的scheduleUnbindService()脑蠕,執(zhí)行service.unbind()
            if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                    && b.intent.hasBound) {
                try {
                    bumpServiceExecutingLocked(s, false, "unbind");
                    if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
                            && s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) {
                        // If this service's process is not already in the cached list,
                        // then update it in the LRU list here because this may be causing
                        // it to go down there and we want it to start out near the top.
                        mAm.updateLruProcessLocked(s.app, false, null);
                    }
                    mAm.updateOomAdjLocked(s.app);
                    b.intent.hasBound = false;
                    // Assume the client doesn't want to know about a rebind;
                    // we will deal with that later if it asks for one.
                    b.intent.doRebind = false;
                    s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
                } catch (Exception e) {
                    Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
                    serviceProcessGoneLocked(s);
                }
            }

            if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
                boolean hasAutoCreate = s.hasAutoCreateConnections();
                if (!hasAutoCreate) {
                    if (s.tracker != null) {
                        s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
                                SystemClock.uptimeMillis());
                    }
                }
                // 根據(jù)情況決定是否調(diào)用service.onDestroy()方法
                bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
            }
        }
    }

scheduleUnbindService()會導(dǎo)致下面的方法在service的主線程中執(zhí)行:

private void handleUnbindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                // 執(zhí)行service.onUnbind()生命周期方法
                boolean doRebind = s.onUnbind(data.intent);
                try {
                    if (doRebind) {
                        // 如果onUnbind()的返回值設(shè)置為true的話购撼,
                        // 調(diào)用AMS.unbindFinished()
                        ActivityManagerNative.getDefault().unbindFinished(
                                data.token, data.intent, doRebind);
                    } else {
                        ActivityManagerNative.getDefault().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                } catch (RemoteException ex) {
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to unbind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

unbindeService()代碼就說道這里,接下來總結(jié)下:

  1. ServiceConnection.onServiceDisconnected()并不會在unbindeService()過程中調(diào)用谴仙,它只會在service進(jìn)程被終止時(shí)回調(diào)通知綁定的客戶端迂求;

  2. 只有在綁定這個(gè)service的所有客戶端中的組件都執(zhí)行了unbindeService()時(shí),service才會被銷毀晃跺,執(zhí)行servcice.onDestroy(),這也就要求暗示我們當(dāng)完成于服務(wù)的交互后揩局,最好unbindeService,這樣有利于系統(tǒng)及時(shí)回收service資源;

  3. 當(dāng)目標(biāo)service所在的進(jìn)程被殺掉時(shí)(即除了正诚苹ⅲ回收service)凌盯,系統(tǒng)并不會銷毀之前的與該service綁定的組件創(chuàng)建的連接,一旦service后續(xù)再次運(yùn)行烹玉,系統(tǒng)會再次回調(diào)onServiceConnected()驰怎;

  4. 如果service是通過startService()啟動的,那么service將一直運(yùn)行到其通過 stopSelf() 自行停止二打,或其他組件調(diào)用 stopService() 為止县忌,無論其是否綁定到任何客戶端;

  5. unbindeService()操作也是異步操作的继效;

  6. 一般情況下症杏,只要service被客戶端綁定過了,當(dāng)其再被綁定時(shí)莲趣,不會在調(diào)用service.onBind()方法了鸳慈,也就是說通常service.onBind()只會執(zhí)行一次;

  7. 同一個(gè)組件內(nèi)使用同一個(gè)ServiceConnection接口對象喧伞,重復(fù)綁定一個(gè)service時(shí)走芋,會在AMS中為起創(chuàng)建連接绩郎,但是不會導(dǎo)致ServiceConnection.onServiceConnected()方法執(zhí)行

  8. 同一個(gè)組件內(nèi)執(zhí)行unbindeService(ServiceConnection sc)時(shí),相當(dāng)于對所有使用sc綁定的service執(zhí)行一次unbindeService操作翁逞;

這里比較有趣的是肋杖,假設(shè)同一組件內(nèi)使用sc重復(fù)綁定的一個(gè)servcie N次,那么這一次unbindeService(),當(dāng)對于該該組件綁定該service來說執(zhí)行了N次unbindeService操作挖函。

生命周期的總結(jié):

單獨(dú)使用bindService()状植,unbindService()會經(jīng)歷:->onCreate()->onBind()->Service running->onUnbind() -> onDestroy();

單獨(dú)使用startService()怨喘,stopService()會經(jīng)歷:->onCreate()->onStartCommand()->Service running-> onDestroy()津畸;

先調(diào)用startService(),再調(diào)用bindService()方法:

a. 如果結(jié)束只調(diào)用unbindService()必怜,那么只會執(zhí)行到onUnbind()肉拓,將不會執(zhí)行onDestroy():->onCreate()->onStartCommand()->onBind()->Service running-> onUnbind();

b. 如果在unbindService后,在調(diào)用stopService()梳庆,那么:->onCreate()->onStartCommand()->onBind()->Service running-> onUnbind()->onDestroy();

service的生命周期方法都運(yùn)行在主線程中暖途,所以如果要在生命周期中執(zhí)行耗時(shí)操作,請額外開啟線程膏执。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末驻售,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子更米,更是在濱河造成了極大的恐慌欺栗,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壳快,死亡現(xiàn)場離奇詭異纸巷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)眶痰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門瘤旨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人竖伯,你說我怎么就攤上這事存哲。” “怎么了七婴?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵祟偷,是天一觀的道長。 經(jīng)常有香客問我打厘,道長修肠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任户盯,我火速辦了婚禮嵌施,結(jié)果婚禮上饲化,老公的妹妹穿的比我還像新娘。我一直安慰自己吗伤,他們只是感情好吃靠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著足淆,像睡著了一般巢块。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巧号,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天族奢,我揣著相機(jī)與錄音,去河邊找鬼丹鸿。 笑死歹鱼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卜高。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼南片,長吁一口氣:“原來是場噩夢啊……” “哼掺涛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起疼进,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤薪缆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后伞广,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拣帽,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年嚼锄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了减拭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡区丑,死狀恐怖拧粪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沧侥,我是刑警寧澤可霎,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站宴杀,受9級特大地震影響癣朗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旺罢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一旷余、第九天 我趴在偏房一處隱蔽的房頂上張望绢记。 院中可真熱鬧,春花似錦荣暮、人聲如沸庭惜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽护赊。三九已至,卻和暖如春砾跃,著一層夾襖步出監(jiān)牢的瞬間骏啰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工抽高, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留判耕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓翘骂,卻偏偏與公主長得像壁熄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子碳竟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容