Android中bindService是一個(gè)異步的過程,什么意思呢?使用bindService無非是想獲得一個(gè)Binder服務(wù)的Proxy,但這個(gè)代理獲取到的時(shí)機(jī)并非由bindService發(fā)起端控制,而是由Service端來控制,也就是說bindService之后,APP端并不會(huì)立刻獲得Proxy,而是要等待Service通知APP端,具體流程可簡化如下:
- APP端先通過bindService去AMS登記,說明自己需要綁定這樣一個(gè)服務(wù),并留下派送地址
- APP回來,繼續(xù)做其他事情,可以看做是非阻塞的
- AMS通知Service端啟動(dòng)這個(gè)服務(wù)
- Service啟動(dòng),并通知AMS啟動(dòng)完畢
- AMS跟住之前APP端留下的地址通知APP端,并將Proxy代理傳遞給APP端
通過代碼來看更直接
void test(){
bindService(intent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
Log.v(TAG, "onServiceConnected..." );
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}, Context.BIND_AUTO_CREATE);
Log.v(TAG, "end..." );
}
bindService的過程中,上面代碼的Log應(yīng)該是怎么樣的呢?如果bindService是一個(gè)同步過程,那么Log應(yīng)該如下:
TAG onServiceConnected ...
TAG end ...
但是由于是個(gè)異步過程,真實(shí)的Log如下
TAG end ...
TAG onServiceConnected ...
也就是說bindService不會(huì)阻塞等待APP端獲取Proxy,而是直接返回,這些都可以從源碼獲得支持,略過,直接去ActivityManagerNative去看
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
int flags, int userId) 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);
data.writeInt(userId);
<!--阻塞等待-->
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
data.recycle();
reply.recycle();
return res;
}
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0)確實(shí)會(huì)讓APP端調(diào)用線程阻塞,等待AMS執(zhí)行BIND_SERVICE_TRANSACTION請(qǐng)求,不過AMS在執(zhí)行這個(gè)請(qǐng)求的時(shí)候并非是喚醒Service才返回,它返回的時(shí)機(jī)更早,接著看ActivityManagerService,
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
...
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType,
connection, flags, userId);
}
}
ActivityManagerService直接調(diào)用ActiveServices的函數(shù)bindServiceLocked,請(qǐng)求綁定Service,到這里APP端線程依舊阻塞,等待AMS端返回,假定Service所處的進(jìn)程已經(jīng)啟動(dòng)但是Service沒有啟動(dòng),這時(shí)ActiveServices會(huì)進(jìn)一步調(diào)用bindServiceLocked->realStartServiceLocked來啟動(dòng)Service,有趣的就在這里:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app) throws RemoteException {
...
<!--請(qǐng)求Service端啟動(dòng)Service-->
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo));
...
<!--請(qǐng)求綁定Service-->
requestServiceBindingsLocked(r);
app.thread.scheduleCreateService也是一個(gè)Binder通信過程,他其實(shí)是AMS異步請(qǐng)求ActivityThread中的ApplicationThread服務(wù),系統(tǒng)服務(wù)請(qǐng)求客戶端的本地服務(wù)一般都是異步的:
// 插入消息,等待主線程執(zhí)行
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo) {
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
<!--向Loop的MessagerQueue插入一條消息就返回-->
queueOrSendMessage(H.CREATE_SERVICE, s);
}
不過,這個(gè)請(qǐng)求直接向Service端的ActivityThread線程中直接插入一個(gè)消息就返回了,而并未等到該請(qǐng)求執(zhí)行,因?yàn)锳MS使用的非常頻繁,不可能老等待客戶端完成一些任務(wù),所以AMS端向客戶端發(fā)送完命令就直接返回,這個(gè)時(shí)候其實(shí)Service還沒有被創(chuàng)建,也就是這個(gè)請(qǐng)求只是完成了一半,onServiceConnected也并不會(huì)執(zhí)行,onServiceConnected什么時(shí)候執(zhí)行呢?app.thread.scheduleCreateService向APP端插入第一條消息,是用來創(chuàng)建Service的, requestServiceBindingsLocked其實(shí)就是第二條消息,用來處理綁定的
private final boolean requestServiceBindingLocked(ServiceRecord r,
IntentBindRecord i, boolean rebind) {
...
<!-- 第二個(gè)消息,請(qǐng)求處理綁定-->
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
第二條消息是處理一些綁定需求,Android的Hanlder消息處理機(jī)制保證了第二條消息一定是在第一條消息之后執(zhí)行,
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);
}
以上兩條消息插入后,AMS端被喚醒,進(jìn)而重新喚醒之前阻塞的bindService端,而這個(gè)時(shí)候,Service并不一定被創(chuàng)建,所以說這是個(gè)未知的異步過程,Service端處理第一條消息的時(shí)會(huì)創(chuàng)建Service,
private void handleCreateService(CreateServiceData data) {
...
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
...
執(zhí)行第二條消息的時(shí)候, 會(huì)向AMS請(qǐng)求publishService,其實(shí)就是告訴AMS,服務(wù)啟動(dòng)完畢,可以向之前請(qǐng)求APP端派發(fā)代理了。
private 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);
...
AMS端收到publishService消息之后,才會(huì)向APP端發(fā)送通知,進(jìn)而通過Binder回調(diào)APP端onServiceConnected函數(shù),同時(shí)傳遞Proxy Binder服務(wù)代理
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
...
try {
<!--通過binder 回到APP端的onServiceConnected-->
c.conn.connected(r.name, service);
} catch (Exception e) {
到這里,onServiceConnected才會(huì)被回調(diào),不過,至于Service端那兩條消息什么時(shí)候執(zhí)行,誰也不能保證,也許因?yàn)樘厥庠?,那兩條消息永遠(yuǎn)不被執(zhí)行,那onServiceConnected也就不會(huì)被回調(diào),但是這不會(huì)影響AMS與APP端處理其他問題,因?yàn)檫@些消息是否被執(zhí)行已經(jīng)不能阻塞他們兩個(gè)了,簡單流程如下:

最后,其實(shí)startService也是異步。
作者:看書的小蝸牛
Android面試題:bindService獲取代理是同步還是異步
僅供參考,歡迎指正