天天看點

Android應用程式綁定服務(bindService)的過程源代碼分析

        Android應用程式元件Service與Activity一樣,既可以在新的程序中啟動,也可以在應用程式程序内部啟動;前面我們已經分析了在新的程序中啟動Service的過程,本文将要介紹在應用程式内部綁定Service的過程,這是一種在應用程式程序内部啟動Service的方法。

《Android系統源代碼情景分析》一書正在進擊的程式員網(http://0xcc0xcd.com)中連載,點選進入!

        在前面一篇文章Android程序間通信(IPC)機制Binder簡要介紹和學習計劃中,我們就曾經提到,在Android系統中,每一個應用程式都是由一些Activity和Service組成的,一般Service運作在獨立的程序中,而Activity有可能運作在同一個程序中,也有可能運作在不同的程序中;在接下來的文章中,Android系統在新程序中啟動自定義服務過程(startService)的原理分析一文介紹了在新的程序中啟動Service的過程,Android應用程式啟動過程源代碼分析一文介紹了在新的程序中啟動Activity的過程,而Android應用程式内部啟動Activity過程(startActivity)的源代碼分析一文則介紹了在應用程式程序内部啟動Activity的過程;本文接過最後一棒,繼續介紹在應用程式程序内部啟動Service的過程,這種過程又可以稱在應用程式程序内部綁定服務(bindService)的過程,這樣,讀者應該就可以對Android應用程式啟動Activity和Service有一個充分的認識了。

        這裡仍然是按照老規矩,通過具體的例子來分析Android應用程式綁定Service的過程,而所使用的例子便是前面我們在介紹Android系統廣播機制的一篇文章Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃中所開發的應用程式Broadcast了。

        我們先簡單回顧一下這個應用程式執行個體綁定Service的過程。在這個應用程式的MainActivity的onCreate函數中,會調用bindService來綁定一個計數器服務CounterService,這裡綁定的意思其實就是在MainActivity内部獲得CounterService的接口,是以,這個過程的第一步就是要把CounterService啟動起來。當CounterService的onCreate函數被調用起來了,就說明CounterService已經啟動起來了,接下來系統還要調用CounterService的onBind函數,跟CounterService要一個Binder對象,這個Binder對象是在CounterService内部自定義的CounterBinder類的一個執行個體,它繼承于Binder類,裡面實作一個getService函數,用來傳回外部的CounterService接口。系統得到這個Binder對象之後,就會調用MainActivity在bindService函數裡面傳過來的ServiceConnection執行個體的onServiceConnected函數,并把這個Binder對象以參數的形式傳到onServiceConnected函數裡面,于是,MainActivity就可以調用這個Binder對象的getService函數來獲得CounterService的接口了。

        這個過程比較複雜,但總體來說,思路還是比較清晰的,整個調用過程為MainActivity.bindService->CounterService.onCreate->CounterService.onBind->MainActivity.ServiceConnection.onServiceConnection->CounterService.CounterBinder.getService。下面,我們就先用一個序列圖來總體描述這個服務綁定的過程,然後就具體分析每一個步驟。

Android應用程式綁定服務(bindService)的過程源代碼分析

點選檢視大圖

        Step 1. ContextWrapper.bindService

        這個函數定義在frameworks/base/core/java/android/content/ContextWrapper.java檔案中:

public class ContextWrapper extends Context {
	Context mBase;
	......

	@Override
	public boolean bindService(Intent service, ServiceConnection conn,
			int flags) {
		return mBase.bindService(service, conn, flags);
	}

	......
}
           

        這裡的mBase是一個ContextImpl執行個體變量,于是就調用ContextImpl的bindService函數來進一步處理。

        Step 2. ContextImpl.bindService

        這個函數定義在frameworks/base/core/java/android/app/ContextImpl.java檔案中:

class ContextImpl extends Context {
	......

	@Override
	public boolean bindService(Intent service, ServiceConnection conn,
			int flags) {
		IServiceConnection sd;
		if (mPackageInfo != null) {
			sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
				mMainThread.getHandler(), flags);
		} else {
			......
		}
		try {
			int res = ActivityManagerNative.getDefault().bindService(
				mMainThread.getApplicationThread(), getActivityToken(),
				service, service.resolveTypeIfNeeded(getContentResolver()),
				sd, flags);
			......
			return res != 0;
		} catch (RemoteException e) {
			return false;
		}
	}

	......

}
           

        這裡的mMainThread是一個ActivityThread執行個體,通過它的getHandler函數可以獲得一個Handler對象,有了這個Handler對象後,就可以把消息分發到ActivityThread所在的線程消息隊列中去了,後面我們将會看到這個用法,現在我們暫時不關注,隻要知道這裡從ActivityThread處獲得了一個Handler并且儲存在下面要介紹的ServiceDispatcher中去就可以了。

        我們先看一下ActivityThread.getHandler的實作,然後再回到這裡的bindService函數來。

        Step 3. ActivityThread.getHandler

        這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:

public final class ActivityThread {
	......

	final H mH = new H();

	......

	private final class H extends Handler {
		......

		public void handleMessage(Message msg) {
			......
		}

		......
	}

	......

	final Handler getHandler() {
		return mH;
	}

	......
}
           

        這裡傳回的Handler是在ActivityThread類内部從Handler類繼承下來的一個H類執行個體變量。

        回到Step 2中的ContextImpl.bindService函數中,獲得了這個Handler對象後,就調用mPackageInfo.getServiceDispatcher函數來獲得一個IServiceConnection接口,這裡的mPackageInfo的類型是LoadedApk,我們來看看它的getServiceDispatcher函數的實作,然後再回到ContextImpl.bindService函數來。

        Step 4. LoadedApk.getServiceDispatcher

        這個函數定義在frameworks/base/core/java/android/app/LoadedApk.java檔案中:

final class LoadedApk {
	......

	public final IServiceConnection getServiceDispatcher(ServiceConnection c,
			Context context, Handler handler, int flags) {
		synchronized (mServices) {
			LoadedApk.ServiceDispatcher sd = null;
			HashMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
			if (map != null) {
				sd = map.get(c);
			}
			if (sd == null) {
				sd = new ServiceDispatcher(c, context, handler, flags);
				if (map == null) {
					map = new HashMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
					mServices.put(context, map);
				}
				map.put(c, sd);
			} else {
				sd.validate(context, handler);
			}
			return sd.getIServiceConnection();
		}
	}

	......

	static final class ServiceDispatcher {
		private final ServiceDispatcher.InnerConnection mIServiceConnection;
		private final ServiceConnection mConnection;
		private final Handler mActivityThread;
		......

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

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

			......
		}

		......

		ServiceDispatcher(ServiceConnection conn,
				Context context, Handler activityThread, int flags) {
			mIServiceConnection = new InnerConnection(this);
			mConnection = conn;
			mActivityThread = activityThread;
			......
		}

		......

		IServiceConnection getIServiceConnection() {
			return mIServiceConnection;
		}

		......
	}

	......
}
           

         在getServiceDispatcher函數中,傳進來的參數context是一個MainActivity執行個體,先以它為Key值在mServices中檢視一下,是不是已經存在相應的ServiceDispatcher執行個體,如果有了,就不用建立了,直接取出來。在我們這個情景中,需要建立一個新的ServiceDispatcher。在建立新的ServiceDispatcher執行個體的過程中,将上面傳下來ServiceConnection參數c和Hanlder參數儲存在了ServiceDispatcher執行個體的内部,并且建立了一個InnerConnection對象,這是一個Binder對象,一會是要傳遞給ActivityManagerService的,ActivityManagerServic後續就是要通過這個Binder對象和ServiceConnection通信的。

        函數getServiceDispatcher最後就是傳回了一個InnerConnection對象給ContextImpl.bindService函數。回到ContextImpl.bindService函數中,它接着就要調用ActivityManagerService的遠端接口來進一步處理了。

       Step 5. ActivityManagerService.bindService

       這個函數定義在frameworks/base/core/java/android/app/ActivityManagerNative.java檔案中:

class ActivityManagerProxy implements IActivityManager
{
	......

	public int bindService(IApplicationThread caller, IBinder token,
			Intent service, String resolvedType, IServiceConnection connection,
			int flags) throws RemoteException {
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		data.writeInterfaceToken(IActivityManager.descriptor);
		data.writeStrongBinder(caller != null ? caller.asBinder() : null);
		data.writeStrongBinder(token);
		service.writeToParcel(data, 0);
		data.writeString(resolvedType);
		data.writeStrongBinder(connection.asBinder());
		data.writeInt(flags);
		mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
		reply.readException();
		int res = reply.readInt();
		data.recycle();
		reply.recycle();
		return res;
	}

	......
}
           

         這個函數通過Binder驅動程式就進入到ActivityManagerService的bindService函數去了。

         Step 6. ActivityManagerService.bindService

         這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java檔案中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	public int bindService(IApplicationThread caller, IBinder token,
			Intent service, String resolvedType,
			IServiceConnection connection, int flags) {
		......

		synchronized(this) {
			......
			final ProcessRecord callerApp = getRecordForAppLocked(caller);
			......

			ActivityRecord activity = null;
			if (token != null) {
				int aindex = mMainStack.indexOfTokenLocked(token);
				......
				activity = (ActivityRecord)mMainStack.mHistory.get(aindex);
			}
			
			......

			ServiceLookupResult res =
				retrieveServiceLocked(service, resolvedType,
				Binder.getCallingPid(), Binder.getCallingUid());
			
			......

			ServiceRecord s = res.record;

			final long origId = Binder.clearCallingIdentity();

			......

			AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
			ConnectionRecord c = new ConnectionRecord(b, activity,
				connection, flags, clientLabel, clientIntent);

			IBinder binder = connection.asBinder();
			ArrayList<ConnectionRecord> clist = s.connections.get(binder);

			if (clist == null) {
				clist = new ArrayList<ConnectionRecord>();
				s.connections.put(binder, clist);
			}
			clist.add(c);
			b.connections.add(c);
			if (activity != null) {
				if (activity.connections == null) {
					activity.connections = new HashSet<ConnectionRecord>();
				}
				activity.connections.add(c);
			}
			b.client.connections.add(c);
			clist = mServiceConnections.get(binder);
			if (clist == null) {
				clist = new ArrayList<ConnectionRecord>();
				mServiceConnections.put(binder, clist);
			}
		
			clist.add(c);

			if ((flags&Context.BIND_AUTO_CREATE) != 0) {
				......
				if (!bringUpServiceLocked(s, service.getFlags(), false)) {
					return 0;
				}
			}

			......
		}

		return 1;
	}			

	......
}
           

         函數首先根據傳進來的參數token是MainActivity在ActivityManagerService裡面的一個令牌,通過這個令牌就可以将這個代表MainActivity的ActivityRecord取回來了。

        接着通過retrieveServiceLocked函數,得到一個ServiceRecord,這個ServiceReocrd描述的是一個Service對象,這裡就是CounterService了,這是根據傳進來的參數service的内容獲得的。回憶一下在MainActivity.onCreate函數綁定服務的語句:

Intent bindIntent = new Intent(MainActivity.this, CounterService.class);
bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
           

        這裡的參數service,就是上面的bindIntent了,它裡面設定了CounterService類的資訊(CounterService.class),是以,這裡可以通過它來把CounterService的資訊取出來,并且儲存在ServiceRecord對象s中。

        接下來,就是把傳進來的參數connection封裝成一個ConnectionRecord對象。注意,這裡的參數connection是一個Binder對象,它的類型是LoadedApk.ServiceDispatcher.InnerConnection,是在Step 4中建立的,後續ActivityManagerService就是要通過它來告訴MainActivity,CounterService已經啟動起來了,是以,這裡要把這個ConnectionRecord變量c儲存下來,它保在在好幾個地方,都是為了後面要用時友善地取回來的,這裡就不仔細去研究了,隻要知道ActivityManagerService要使用它時就可以友善地把它取出來就可以了,具體後面我們再分析。

        最後,傳進來的參數flags的位Context.BIND_AUTO_CREATE為1(參見上面MainActivity.onCreate函數調用bindService函數時設定的參數),是以,這裡會調用bringUpServiceLocked函數進一步處理。

        Step 7. 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;
		ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);

		if (app != null && app.thread != null) {
			try {
				realStartServiceLocked(r, app);
				return true;
			} catch (RemoteException e) {
				......
			}
		}

		// 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) {
				......
		}

		......
	}

	......
}
           

        回憶在Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃中一文中,我們沒有在程式的AndroidManifest.xml配置檔案中設定CounterService的process屬性值,是以,它預設就為application标簽的process屬性值,而application标簽的process屬性值也沒有設定,于是,它們就預設為應用程式的包名了,即這裡的appName的值為"shy.luo.broadcast"。接下來根據appName和應用程式的uid值獲得一個ProcessRecord記錄,由于之前在啟動MainActivity的時候,已經根據這個appName和uid值建立了一個ProcessReocrd對象(具體可以參考Android應用程式啟動過程源代碼分析一文),是以,這裡取回來的app和app.thread均不為null,于是,就執行realStartServiceLocked函數來執行下一步操作了。

        如果這裡得到的ProcessRecord變量app為null,又是什麼情況呢?在這種情況下,就會執行後面的startProcessLocked函數來建立一個新的程序,然後在這個新的程序中啟動這個Service了,具體可以參考前面一篇文章Android系統在新程序中啟動自定義服務過程(startService)的原理分析。

        Step 8. ActivityManagerService.realStartServiceLocked

        這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java檔案中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	private final void realStartServiceLocked(ServiceRecord r,
			ProcessRecord app) throws RemoteException {
		......
		r.app = app;
		......

		app.services.add(r);
		......

		try {
			......
			app.thread.scheduleCreateService(r, r.serviceInfo);
			......
		} finally {
			......
		}

		requestServiceBindingsLocked(r);

		......
	}

	......
}
           

        這個函數執行了兩個操作,一個是操作是調用app.thread.scheduleCreateService函數來在應用程式程序内部啟動CounterService,這個操作會導緻CounterService的onCreate函數被調用;另一個操作是調用requestServiceBindingsLocked函數來向CounterService要一個Binder對象,這個操作會導緻CounterService的onBind函數被調用。

        這裡,我們先沿着app.thread.scheduleCreateService這個路徑分析下去,然後再回過頭來分析requestServiceBindingsLocked的調用過程。這裡的app.thread是一個Binder對象的遠端接口,類型為ApplicationThreadProxy。每一個Android應用程式程序裡面都有一個ActivtyThread對象和一個ApplicationThread對象,其中是ApplicationThread對象是ActivityThread對象的一個成員變量,是ActivityThread與ActivityManagerService之間用來執行程序間通信的,具體可以參考Android應用程式啟動過程源代碼分析一文。

        Step 9. 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 10. 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函數把一個H.CREATE_SERVICE類型的消息放到ActivityThread的消息隊列中去。

         Step 11. ActivityThread.queueOrSendMessage

         這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:

public final class ActivityThread {
	......

	// if the thread hasn't started yet, we don't have the handler, so just
	// save the messages until we're ready.
	private final void queueOrSendMessage(int what, Object obj) {
		queueOrSendMessage(what, obj, 0, 0);
	}

	private final void queueOrSendMessage(int what, Object obj, int arg1) {
		queueOrSendMessage(what, obj, arg1, 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是一個在ActivityThread内部定義的一個類,繼承于Hanlder類,用于處理消息的。

        Step 12. H.sendMessage

        由于H類繼承于Handler類,是以,這裡實際執行的Handler.sendMessage函數,這個函數定義在frameworks/base/core/java/android/os/Handler.java檔案,這裡我們就不看了,有興趣的讀者可以自己研究一下,調用了這個函數之後,這個消息就真正地進入到ActivityThread的消息隊列去了,最終這個消息由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;
			......
			}
		}
	}

	......
}
           

        這個消息最終由ActivityThread的handleCreateService函數來處理。

        Step 13. ActivityThread.handleCreateService

        這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:

public final class ActivityThread {
	......

	private final void handleCreateService(CreateServiceData data) {
		......

		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) {
			......
		}

		try {
			......

			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);
			......
		} catch (Exception e) {
			......
		}
	}

	......
}
           

         這個函數的工作就是把CounterService類加載到記憶體中來,然後調用它的onCreate函數。

         Step 14. CounterService.onCreate

         這個函數定義在Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃中一文中所介紹的應用程式Broadcast的工程目錄下的src/shy/luo/broadcast/CounterService.java檔案中:

public class CounterService extends Service implements ICounterService {
	......

	@Override  
	public void onCreate() {  
		super.onCreate();  

		Log.i(LOG_TAG, "Counter Service Created.");  
	} 

	......
}
           

        這樣,CounterService就啟動起來了。

        至此,應用程式綁定服務過程中的第一步MainActivity.bindService->CounterService.onCreate就完成了。

        這一步完成之後,我們還要回到Step  8中去,執行下一個操作,即調用ActivityManagerService.requestServiceBindingsLocked函數,這個調用是用來執行CounterService的onBind函數的。

        Step 15. ActivityManagerService.requestServiceBindingsLocked

        這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java檔案中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	private final void requestServiceBindingsLocked(ServiceRecord r) {
		Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
		while (bindings.hasNext()) {
			IntentBindRecord i = bindings.next();
			if (!requestServiceBindingLocked(r, i, false)) {
				break;
			}
		}
	}

	private final boolean requestServiceBindingLocked(ServiceRecord r,
			IntentBindRecord i, boolean rebind) {
		......
		if ((!i.requested || rebind) && i.apps.size() > 0) {
		  try {
			  ......
			  r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
			  ......
		  } catch (RemoteException e) {
			  ......
		  }
		}
		return true;
	}

	......
}
           

        這裡的參數r就是我們在前面的Step 6中建立的ServiceRecord了,它代表剛才已經啟動了的CounterService。函數requestServiceBindingsLocked調用了requestServiceBindingLocked函數來處理綁定服務的操作,而函數requestServiceBindingLocked又調用了app.thread.scheduleBindService函數執行操作,前面我們已經介紹過app.thread,它是一個Binder對象的遠端接口,類型是ApplicationThreadProxy。

        Step 16. ApplicationThreadProxy.scheduleBindService

        這個函數定義在frameworks/base/core/java/android/app/ApplicationThreadNative.java檔案中:

class ApplicationThreadProxy implements IApplicationThread {
	......
	
	public final void scheduleBindService(IBinder token, Intent intent, boolean rebind)
			throws RemoteException {
		Parcel data = Parcel.obtain();
		data.writeInterfaceToken(IApplicationThread.descriptor);
		data.writeStrongBinder(token);
		intent.writeToParcel(data, 0);
		data.writeInt(rebind ? 1 : 0);
		mRemote.transact(SCHEDULE_BIND_SERVICE_TRANSACTION, data, null,
			IBinder.FLAG_ONEWAY);
		data.recycle();
	}

	......
}
           

         這裡通過Binder驅動程式就進入到ApplicationThread的scheduleBindService函數去了。

         Step 17. ApplicationThread.scheduleBindService

         這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:

public final class ActivityThread {
	......

	public final void scheduleBindService(IBinder token, Intent intent,
			boolean rebind) {
		BindServiceData s = new BindServiceData();
		s.token = token;
		s.intent = intent;
		s.rebind = rebind;

		queueOrSendMessage(H.BIND_SERVICE, s);
	}

	......
}
           

        這裡像上面的Step 11一樣,調用ActivityThread.queueOrSendMessage函數來發送消息。

        Step 18. ActivityThread.queueOrSendMessage

        參考上面的Step 11,不過這裡的消息類型是H.BIND_SERVICE。

        Step 19. H.sendMessage

        參考上面的Step 12,不過這裡最終在H.handleMessage函數中,要處理的消息類型是H.BIND_SERVICE:

public final class ActivityThread {
	......

	private final class H extends Handler {
		......

		public void handleMessage(Message msg) {
			......
			switch (msg.what) {
			......
			case BIND_SERVICE:
				handleBindService((BindServiceData)msg.obj);
				break;
			......
			}
		}
	}

	......
}
           

         這裡調用ActivityThread.handleBindService函數來進一步處理。

         Step 20. ActivityThread.handleBindService

         這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java檔案中:

public final class ActivityThread {
	......

	private final void handleBindService(BindServiceData data) {
		Service s = mServices.get(data.token);
		if (s != null) {
			try {
				data.intent.setExtrasClassLoader(s.getClassLoader());
				try {
					if (!data.rebind) {
						IBinder binder = s.onBind(data.intent);
						ActivityManagerNative.getDefault().publishService(
							data.token, data.intent, binder);
					} else {
						......
					}
					......
				} catch (RemoteException ex) {
				}
			} catch (Exception e) {
				......
			}
		}
	}

	......
}
           

        在前面的Step 13執行ActivityThread.handleCreateService函數中,已經将這個CounterService執行個體儲存在mServices中,是以,這裡首先通過data.token值将它取回來,儲存在本地變量s中,接着執行了兩個操作,一個操作是調用s.onBind,即CounterService.onBind獲得一個Binder對象,另一個操作就是把這個Binder對象傳遞給ActivityManagerService。

        我們先看CounterService.onBind操作,然後再回到ActivityThread.handleBindService函數中來。

        Step 21. CounterService.onBind

        這個函數定義在Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃中一文中所介紹的應用程式Broadcast的工程目錄下的src/shy/luo/broadcast/CounterService.java檔案中:

public class CounterService extends Service implements ICounterService {
	......

	private final IBinder binder = new CounterBinder();  

	public class CounterBinder extends Binder {  
		public CounterService getService() {  
			return CounterService.this;  
		}  
	}  

	@Override  
	public IBinder onBind(Intent intent) {  
		return binder;  
	}  

	......
}
           

        這裡的onBind函數傳回一個是CounterBinder類型的Binder對象,它裡面實作一個成員函數getService,用于傳回CounterService接口。

        至此,應用程式綁定服務過程中的第二步CounterService.onBind就完成了。

        回到ActivityThread.handleBindService函數中,獲得了這個CounterBinder對象後,就調用ActivityManagerProxy.publishService來通知MainActivity,CounterService已經連接配接好了。

        Step 22. ActivityManagerProxy.publishService

        這個函數定義在frameworks/base/core/java/android/app/ActivityManagerNative.java檔案中:

class ActivityManagerProxy implements IActivityManager
{
	......

	public void publishService(IBinder token,
	Intent intent, IBinder service) throws RemoteException {
		Parcel data = Parcel.obtain();
		Parcel reply = Parcel.obtain();
		data.writeInterfaceToken(IActivityManager.descriptor);
		data.writeStrongBinder(token);
		intent.writeToParcel(data, 0);
		data.writeStrongBinder(service);
		mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
		reply.readException();
		data.recycle();
		reply.recycle();
	}

	......
}
           

         這裡通過Binder驅動程式就進入到ActivityManagerService的publishService函數中去了。

         Step 23. ActivityManagerService.publishService

         這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java檔案中:

public final class ActivityManagerService extends ActivityManagerNative
		implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
	......

	public void publishService(IBinder token, Intent intent, IBinder service) {
		......
		synchronized(this) {
			......
			ServiceRecord r = (ServiceRecord)token;
			......

			......
			if (r != null) {
				Intent.FilterComparison filter
					= new Intent.FilterComparison(intent);
				IntentBindRecord b = r.bindings.get(filter);
				if (b != null && !b.received) {
					b.binder = service;
					b.requested = true;
					b.received = true;
					if (r.connections.size() > 0) {
						Iterator<ArrayList<ConnectionRecord>> it
							= r.connections.values().iterator();
						while (it.hasNext()) {
							ArrayList<ConnectionRecord> clist = it.next();
							for (int i=0; i<clist.size(); i++) {
								ConnectionRecord c = clist.get(i);
								......
								try {
									c.conn.connected(r.name, service);
								} catch (Exception e) {
									......
								}
							}
						}
					}
				}

				......
			}
		}
	}

	......
}
           

        這裡傳進來的參數token是一個ServiceRecord對象,它是在上面的Step 6中建立的,代表CounterService這個Service。在Step 6中,我們曾經把一個ConnectionRecord放在ServiceRecord.connections清單中:

ServiceRecord s = res.record;

    ......

    ConnectionRecord c = new ConnectionRecord(b, activity,
		connection, flags, clientLabel, clientIntent);

    IBinder binder = connection.asBinder();
    ArrayList<ConnectionRecord> clist = s.connections.get(binder);

    if (clist == null) {
	clist = new ArrayList<ConnectionRecord>();
	s.connections.put(binder, clist);
    }
           

        是以,這裡可以從r.connections中将這個ConnectionRecord取出來:

Iterator<ArrayList<ConnectionRecord>> it
	= r.connections.values().iterator();
    while (it.hasNext()) {
	ArrayList<ConnectionRecord> clist = it.next();
	for (int i=0; i<clist.size(); i++) {
	        ConnectionRecord c = clist.get(i);
		......
		try {
			c.conn.connected(r.name, service);
		} catch (Exception e) {
			......
		}
	}
    }
           

        每一個ConnectionRecord裡面都有一個成員變量conn,它的類型是IServiceConnection,是一個Binder對象的遠端接口,這個Binder對象又是什麼呢?這就是我們在Step 

4中建立的LoadedApk.ServiceDispatcher.InnerConnection對象了。是以,這裡執行c.conn.connected函數後就會進入到LoadedApk.ServiceDispatcher.InnerConnection.connected函數中去了。

        Step 24. InnerConnection.connected

        這個函數定義在frameworks/base/core/java/android/app/LoadedApk.java檔案中:

final class LoadedApk {
	......

	static final class ServiceDispatcher {
		......

		private static class InnerConnection extends IServiceConnection.Stub {
			......

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

		......
	}

	......
}
           

         這裡它将操作轉發給ServiceDispatcher.connected函數。

         Step 25. ServiceDispatcher.connected

         這個函數定義在frameworks/base/core/java/android/app/LoadedApk.java檔案中:

final class LoadedApk {
	......

	static final class ServiceDispatcher {
		......

		public void connected(ComponentName name, IBinder service) {
			if (mActivityThread != null) {
				mActivityThread.post(new RunConnection(name, service, 0));
			} else {
				......
			}
		}

		......
	}

	......
}
           

        我們在前面Step 4中說到,這裡的mActivityThread是一個Handler執行個體,它是通過ActivityThread.getHandler函數得到的,是以,調用它的post函數後,就會把一個消息放到ActivityThread的消息隊列中去了。

        Step 26. H.post

        由于H類繼承于Handler類,是以,這裡實際執行的Handler.post函數,這個函數定義在frameworks/base/core/java/android/os/Handler.java檔案,這裡我們就不看了,有興趣的讀者可以自己研究一下,調用了這個函數之後,這個消息就真正地進入到ActivityThread的消息隊列去了,與sendMessage把消息放在消息隊列不一樣的地方是,post方式發送的消息不是由這個Handler的handleMessage函數來處理的,而是由post的參數Runnable的run函數來處理的。這裡傳給post的參數是一個RunConnection類型的參數,它繼承了Runnable類,是以,最終會調用RunConnection.run函數來處理這個消息。

       Step 27. RunConnection.run

       這個函數定義在frameworks/base/core/java/android/app/LoadedApk.java檔案中:

final class LoadedApk {
	......

	static final class ServiceDispatcher {
		......

		private final class RunConnection implements Runnable {
			......

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

			......
		}

		......
	}

	......
}
           

        這裡的mCommand值為0,于是就執行ServiceDispatcher.doConnected函數來進一步操作了。

        Step 28. ServiceDispatcher.doConnected

        這個函數定義在frameworks/base/core/java/android/app/LoadedApk.java檔案中:

final class LoadedApk {
	......

	static final class ServiceDispatcher {
		......

		public void doConnected(ComponentName name, IBinder service) {
			......

			// If there is a new service, it is now connected.
			if (service != null) {
				mConnection.onServiceConnected(name, service);
			}
		}


		......
	}

	......
}
           

        這裡主要就是執行成員變量mConnection的onServiceConnected函數,這裡的mConnection變量的類型的ServiceConnection,它是在前面的Step 4中設定好的,這個ServiceConnection執行個體是MainActivity類内部建立的,在調用bindService函數時儲存在LoadedApk.ServiceDispatcher類中,用它來換取一個IServiceConnection對象,傳給ActivityManagerService。

        Step 29. ServiceConnection.onServiceConnected

        這個函數定義在Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃中一文中所介紹的應用程式Broadcast的工程目錄下的src/shy/luo/broadcast/MainActivity.java檔案中:

public class MainActivity extends Activity implements OnClickListener {  
	......

	private ServiceConnection serviceConnection = new ServiceConnection() {  
		public void onServiceConnected(ComponentName className, IBinder service) {  
			counterService = ((CounterService.CounterBinder)service).getService();  

			Log.i(LOG_TAG, "Counter Service Connected");  
		}  
		......
	};  
	
	......
}
           

        這裡傳進來的參數service是一個Binder對象,就是前面在Step 21中從CounterService那裡得到的ConterBinder對象,是以,這裡可以把它強制轉換為CounterBinder引用,然後調用它的getService函數。

        至此,應用程式綁定服務過程中的第三步MainActivity.ServiceConnection.onServiceConnection就完成了。

        Step 30. CounterBinder.getService

        這個函數定義在Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃中一文中所介紹的應用程式Broadcast的工程目錄下的src/shy/luo/broadcast/CounterService.java檔案中:

public class CounterService extends Service implements ICounterService {  
	......

	public class CounterBinder extends Binder {  
		public CounterService getService() {  
			return CounterService.this;  
		}  
	}  

	......
}
           

        這裡就把CounterService接口傳回給MainActivity了。

        至此,應用程式綁定服務過程中的第四步CounterService.CounterBinder.getService就完成了。

        這樣,Android應用程式綁定服務(bindService)的過程的源代碼分析就完成了,總結一下這個過程:

        1. Step 1 -  Step 14,MainActivity調用bindService函數通知ActivityManagerService,它要啟動CounterService這個服務,ActivityManagerService于是在MainActivity所在的程序内部把CounterService啟動起來,并且調用它的onCreate函數;

        2. Step 15 - Step 21,ActivityManagerService把CounterService啟動起來後,繼續調用CounterService的onBind函數,要求CounterService傳回一個Binder對象給它;

        3. Step 22 - Step 29,ActivityManagerService從CounterService處得到這個Binder對象後,就把它傳給MainActivity,即把這個Binder對象作為參數傳遞給MainActivity内部定義的ServiceConnection對象的onServiceConnected函數;

        4. Step 30,MainActivity内部定義的ServiceConnection對象的onServiceConnected函數在得到這個Binder對象後,就通過它的getService成同函數獲得CounterService接口。

老羅的新浪微網誌:http://weibo.com/shengyangluo,歡迎關注!