天天看點

【Service的工作過程】bindService的啟動過程目錄ContextImpl到AMS的調用過程AMS到ActivityThread請求PublishService過程釋出服務到ServiceConnection 回調過程The end

Service 的綁定過程将分為兩個部分,分别是ContextImpl到AMS的調用過程和Service的綁定過程。

目錄

【Service的工作過程】bindService的啟動過程目錄ContextImpl到AMS的調用過程AMS到ActivityThread請求PublishService過程釋出服務到ServiceConnection 回調過程The end

ContextImpl到AMS的調用過程

這點流程與startService方式流程一緻,也是調用ContextImpl的bindService最終請求AMS的bindService。

這裡就介紹下ContextImpl到AMS調用間的一個重要方法

ContextImpl#bindServiceCommon

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
  IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
        //1、mPackageInfo 為LoadedApk類型,
        //這裡通過LoadedApk 對象的getServiceDispatcher方法對ServiceConnection
        // 進行封裝成IServiceConnection 對象即sd
        //IServiceConnection類可以看到IPC的痕迹
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
...

// 2、最終調用AMS的bindService
  int res = ActivityManager.getService().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());

}
           

AMS到ActivityThread請求PublishService過程

時序圖

【Service的工作過程】bindService的啟動過程目錄ContextImpl到AMS的調用過程AMS到ActivityThread請求PublishService過程釋出服務到ServiceConnection 回調過程The end

AMS的bindService方法會調用ActiveServices類型的對象mServices的bindServiceLocked方法具體如下:

ActiveServices#bindServiceLocked

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {

...
 ServiceRecord s = res.record;
...
//1、通過ServiceRecord的retrieveAppBindingLocked方法獲得AppBindRecord 對象
  AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
   ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent);

            IBinder binder = connection.asBinder();
  ...
  /*
  2、啟動Service
 調用bringUpServiceLocked方法,在bringUpServiceLocked方法中又調用
realStartServiceLocked 方法,最終由ActivityThread 
調用Service的onCreate 方法啟動Service,
這也說明了bindService方法内部會啟動Service.
*/
   if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }
            ...
   /*
3、s.app!=null表示Service 已經運作。
  其中s 是ServiceRecord類型對象,app是ProcessRecord類型對象。

b.intent.received表示目前應用程式程序已經接收到綁定Service時傳回的Binder,
這樣應用程式程序就可以通過Binder 來擷取要綁定的Service的通路接口

*/
   if (s.app != null && b.intent.received) {
                try {
/*
4、c.conn 是IServiceConnection類型,具體實作為ServiceDispatcher.InnerConnection
   ServiceDispatcher是LoadedApk的内部類
   InnerConnection的connected方法内部會調用H的post方法向主線程發送消息,
   并且解決目前應用程式程序和Service跨程序通信的問題

*/
                    c.conn.connected(s.name, b.intent.binder, false);
                } catch (Exception e) {
                    Slog.w(TAG, "Failure sending service " + s.shortName
                            + " to connection " + c.conn.asBinder()
                            + " (in " + c.binding.client.processName + ")", e);
                }
  /*

5、如果目前應用程式程序是第一個與Service進行綁定的,
并且Service已經調用過onUnBind方法,則需要走if的requestServiceBindingLocked。

如果應用程式程序的Client端沒有發送過綁定Service的請求,
則會調用if的requestServiceBindingLocked。

if 與else的requestServiceBindingLocked差別隻是最後傳遞的rebind boolean參數不同
rebind 為true代表重新綁定,為false代表不是重新綁定。

*/
                if (b.intent.apps.size() == 1 && b.intent.doRebind) {
                    requestServiceBindingLocked(s, b.intent, callerFg, true);
                }
            } else if (!b.intent.requested) {
                requestServiceBindingLocked(s, b.intent, callerFg, false);
            }

            getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);

        } finally {
            Binder.restoreCallingIdentity(origId);
        }

        return 1;
}
           

ServiceRecord:描述一個Service資訊。

ProcessRecord:描述一個程序的資訊。

ConnectionRecord:描述應用程式程序和Service建立的一次通信

AppBindRecord:維護Service與應用程式程序之間的關聯。其内部存儲了誰綁定的Service (ProcessRecord)、被綁定的Service (AppBindRecord)、綁定Service的Intent (IntentBindRecord)和所有綁定通信記錄的資訊(ArraySet<ConnectionRecord>)

ActiveServices#requestServiceBindingLocked

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
...
//bindServiceLocked的if語句調用可知:i.requested=true,rebind=true
 if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.repProcState);
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            }
            ...
            return true;

}
           

i是IntentBindRecord 類型的對象,AMS 會為每個綁定Service的Intent配置設定一個IntentBindRecord類型對象

i.apps.size() > 0到底是啥意思呢?表示所有用目前Intent綁定Service的應用程式程序個數大于0。

final class IntentBindRecord {
     // 記錄被綁定的service
    final ServiceRecord service;
    //記錄綁定service的Intent
    final Intent.FilterComparison intent; 
    //記錄所有用目前Intent綁定service的應用程序
    final ArrayMap<ProcessRecord, AppBindRecord> apps
            = new ArrayMap<ProcessRecord, AppBindRecord>();
            ...

}
           

r.app.thread的類型為IApplicationThread,它的實作是ActivityThread的内部類ApplicationThread,scheduleBindService方法:

ActivityThread#scheduleBindService

public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            // 将Service的資訊封裝成BindServiceData對象
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;

            if (DEBUG_SERVICE)
                Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                        + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
            //将BindServiceData傳入到sendMessage方法中。sendMessage向H發送消息
            sendMessage(H.BIND_SERVICE, s);
        }

           

H 類在接收到BIND_SERVICE類型消息時,會在handleMessage方法中會調用handleBindService方法

ActivityThread#handleBindService

private void handleBindService(BindServiceData data) {
     //1、擷取要綁定的service
        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 {
                /*
                  2、data為BindServiceData對象。第一次綁定時rebind為false
                     會執行service的onBind方法。
                 */
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }
           

可知:如果目前應用程式程序第一個與Service進行綁定,并且Service已經調用過onUnBind方法,則會調用Service的onRebind方法。

這裡服務的綁定就完成了,接下來就是釋出服務,以及ServiceConnection 回調過程。

釋出服務到ServiceConnection 回調過程

時序圖

【Service的工作過程】bindService的啟動過程目錄ContextImpl到AMS的調用過程AMS到ActivityThread請求PublishService過程釋出服務到ServiceConnection 回調過程The end

AMS的publishService

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");
            }
            // 内部調用ActiveServices類的publishServiceLocked
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }
           

ActiveServices的publishServiceLocked

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
...
 for (int conni=r.connections.size()-1; conni>=0; conni--) {
                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                        for (int i=0; i<clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);
                            if (!filter.equals(c.binding.intent.intent)) {
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Not publishing to: " + c);
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Published intent: " + intent);
                                continue;
                            }
                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                            try {
                            /*
c.conn:IServiceConnection類型

是ServiceConnection在本地的代理,用于解決目前應用程式程序和Service跨程序通信的問題

ServiceDispatcher.InnerConnection是具體的實作類

ServiceDispatcher是LoadedApk的内部

*/
                                c.conn.connected(r.name, service, false);
                            }
...
}
           

LoadApk 内部類ServiceDispatcher類的内部類InnerConnection的connected方法

static final class ServiceDispatcher {

...
  //ServiceDispatcher 内部類
  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, boolean dead)
                    throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                //1、sd為ServiceDispatcher 類對象
                    sd.connected(name, service, dead);
                }
            }
        }
  //ServiceDispatcher 方法
  public void connected(ComponentName name, IBinder service, boolean dead) {
            if (mActivityThread != null) {
            /*
           2、 mActivityThread 為Handle類型,這裡調用handle的post方法。
            
            mActivityThread在這裡實際指向H類,是以,通過調用H的post方法将
            RunConnection對象的内容運作在主線程中

           */
            
                mActivityThread.post(new RunConnection(name, service, 0, dead));
            } else {
                doConnected(name, service, dead);
            }
        }
   //ServiceDispatcher 内部類
   private final class RunConnection implements Runnable {
            RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
                mName = name;
                mService = service;
                mCommand = command;
                mDead = dead;
            }

            public void run() {
                if (mCommand == 0) {
                //3、 run方法最終調用的是doConnected方法
                    doConnected(mName, mService, mDead);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }

            final ComponentName mName;
            final IBinder mService;
            final int mCommand;
            final boolean mDead;
        }

  public void doConnected(ComponentName name, IBinder service, boolean dead) {
    ...
 /*
調用了ServiceConnection 類型的對象mConnection 的onServiceConnected方法,
這樣在用戶端實作了ServiceConnection接口類的onServiceConnected方法就會被執行。
至此,Service 的綁定過程就分析完成。
  */
            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
                      
}
...

}

           

The end

參考:

安卓進階解密:微信讀書版

繼續閱讀