Android中bindService的细节之四:bindService时,你所忽略的代码流程细节
0. 说明
事先声明:本文所讲的内容,即使被你忽略了,也不影响对bindService()代码流程的理解。
场景: App A绑定App B的MyService时,App B进程之前没有启动,即需要创建App B进程。
本文要讲的内容是,从App B的ActivityThread的main()执行开始到Looper.loop()执行这段时间内的代码流程,这部分流程是 《Android中bindService的细节之一:从进程的角度分析绑定Service的流程【Service所在进程首次启动】》 的一部分,看完整的流程,可以参考这个链接。
本文从创建App B进程后,在App B进程中执行ActivityThread的main()讲起。
注:AMS所在进程为system_server,为突出AMS,将AMS所在进程称为AMS进程。
1. bindService()的代码流程
1.1 ActivityThread的main()
public static void main(String[] args) {
...
Looper.prepareMainLooper();// 创建Looper
ActivityThread thread = new ActivityThread();
thread.attach(false);// 执行这里
...
}
创建ActivityThread,执行attach()。
1.2 thread.attach(false)
attach() @ ActivityThread
参数system为false
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
...
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
// 执行这里
mgr.attachApplication(mAppThread);
} catch ...
...
} else {
...
}
...
}
1.3 mgr.attachApplication(mAppThread)
attachApplication() @ ActivityManagerService
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
1.4 attachApplicationLocked(thread, callingPid)
attachApplicationLocked() @ ActivityManagerService
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
// 执行这里,因为App B进程刚刚创建,ProcessRecord是在Zygote fork进程前创建的
app = mPidsSelfLocked.get(pid);
}
} else ...
...
// makeActive()把App B进程传过来的IApplicationThread binder对象保存到ProcessRecord的成员变量thread中
app.makeActive(thread, mProcessStats);
...
// 在创建进程时,设置了超时处理的消息,在这里取消掉
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
// 获取App B中的provider信息
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
try {
...
// 执行这里,将向App B的消息队列中放入BIND_APPLICATION消息
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, ...);
...
} catch (Exception e) {
...
}
boolean badApp = false;
boolean didSomething = false;
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
// 执行这里,但是在此场景中不创建新的Activity,所以if语句条件不为true
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;// 不执行这里
}
} catch ...
}
// Find any services that should be running in this process...
if (!badApp) {
try {
// 执行这里
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch ...
}
...
return true;
}
1.5 thread.bindApplication(processName, appInfo, providers…)
切换到App B进程。
bindApplication() @ ApplicationThread @ ActivityThread
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
...
) {
...
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
...
/* 向App B的消息队列中放入BIND_APPLICATION消息,
因为Looper.loop()还没有执行,所以BIND_APPLICATION消息放入队列中,没有立即执行
*/
sendMessage(H.BIND_APPLICATION, data);
}
1.6 mServices.attachApplicationLocked(app, processName)
从App B进程回来,继续执行。
attachApplicationLocked() @ ActiveServices
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
/* 在启动App B进程的时候,将要绑定的服务ServiceRecord放入了mPendingServices,代码在bringUpServiceLocked()中,执行mAm.startProcessLocked()之后,执行了
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
*/
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
...
mPendingServices.remove(i);
i--;
...
// 执行这里
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
...
}
} catch ...
}
return didSomething;
}
1.7 realStartServiceLocked(sr, proc, sr.createdFromFg)
realStartServiceLocked() @ ActiveServices
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
r.app = app; // 此时将ServiceRecord中的app赋值
...
boolean created = false;
try {
...
// 执行这里,将向App B的消息队列中放入CREATE_SERVICE消息
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
...
} finally {
...
}
...
// 执行这里
requestServiceBindingsLocked(r, execInFg);
...
}
1.8 app.thread.scheduleCreateService(r, r.serviceInfo,…)
进入App B进程。
scheduleCreateService() @ ApplicationThread @ ActivityThread
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
// 向App B的消息队列中放入CREATE_SERVICE消息
// 因为Looper.loop()还没有执行,所以CREATE_SERVICE消息放入队列中,没有立即执行。此时队列中已经有2个消息,BIND_APPLICATION消息和CREATE_SERVICE消息
sendMessage(H.CREATE_SERVICE, s);
}
1.9 requestServiceBindingsLocked(r, execInFg)
回到AMS进程。
requestServiceBindingsLocked() @ ActiveServices
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
1.10 requestServiceBindingLocked(r, ibr, execInFg, false)
requestServiceBindingLocked() @ ActiveServices
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
// 在realStartServiceLocked()中已经将r.app赋值
if (r.app == null || r.app.thread == null) {
// 不执行这里
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
...
// 执行这里,将向App B的消息队列中放入BIND_SERVICE消息
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
...
}
}
return true;
}
1.11 r.app.thread.scheduleBindService(r, …)
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
...
// 向App B的消息队列中放入BIND_SERVICE消息
// 因为Looper.loop()还没有执行,所以BIND_SERVICE消息放入队列中,没有立即执行。此时队列中已经有3个消息,BIND_APPLICATION消息、CREATE_SERVICE消息和BIND_SERVICE消息
sendMessage(H.BIND_SERVICE, s);
}
以上这些代码都是由于执行ActivityThread的main()方法中的thread.attach(false)
引起的,所以,执行完上面的代码将回到ActivityThread的attach(),继续执行thread.attach(false)
之后的代码。
在本文讨论的场景中,最后ActivityThread将执行Looper.loop()。
1.12 回到ActivityThread的main()
当前在App B进程。
public static void main(String[] args) {
...
Looper.prepareMainLooper();// 创建Looper
ActivityThread thread = new ActivityThread();
// 之前的代码都是由thread.attach()引起的,AMS调用IApplicationThread接口向App B的消息队列中放入3个消息:BIND_APPLICATION消息、CREATE_SERVICE消息和BIND_SERVICE消息
thread.attach(false);
...
// 此时执行这里,监听消息队列中是否有新消息,如果没有消息,则阻塞在这里。
// 但是,此时队列中已经有了3个待处理的消息,loop()之后将依次处理消息
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
1.13 Looper.loop()
public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
// 阻塞在这里,监听消息队列是否有消息到来
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
// 处理之前放入的3个消息
msg.target.dispatchMessage(msg);
} finally {
...
}
...
}
}
1.14 处理App B消息队列中的3个消息
【注:本文只关注3个消息,其实还有其他的消息】
之前放入App B的消息队列中的3个消息:
(1)BIND_APPLICATION消息:
触发消息:AMS调用thread.bindApplication(processName, appInfo, providers,...)
处理消息:handleBindApplication() @ ActivityThread(2)CREATE_SERVICE消息:
触发消息:AMS调用app.thread.scheduleCreateService(r, r.serviceInfo,...)
处理消息:handleCreateService() @ ActivityThread(3)BIND_SERVICE消息:
触发消息:AMS调用r.app.thread.scheduleBindService(r, i.intent.getIntent(),...)
处理消息:handleBindService() @ ActivityThread
1.15 小结
在App B进程创建后,从ActivityThread的main()开始,到Looper.loop()执行这段初始化的过程中,AMS调用App B的IApplicationThread接口,向App B的消息队列中放入了3个消息:BIND_APPLICATION消息、CREATE_SERVICE消息和BIND_SERVICE消息,但是没有立即被处理。
这3个消息都是在Looper.loop()执行的时候,才被处理的,而且按照队列先进先出的顺序,依次处理BIND_APPLICATION消息、CREATE_SERVICE消息和BIND_SERVICE消息。
可以通过在AMS和ActivityThread中加log来验证这个过程,也可以做一个模拟的测试过程。
2. 测试Handler、Looper的消息处理
2.1 模拟AMS
- (1)用于与App B通信的IMyActivityManager.aidl
package com.galian.ams;
interface IMyActivityManager {
void attachApplication(IBinder appThread);
}
- (2)实现IMyActivityManager接口
package com.galian.ams;
...
import com.galian.app_a.IMyAppThread;
public class TestHandlerLooperActivity extends Activity {
private static final String TAG = "AMS/Test";
private EditText mDelaySecondsEditText = null;
private IMyAppThread mAppThread = null;
private class MyActivityManagerService extends IMyActivityManager.Stub {
@Override
public void attachApplication(IBinder appThread) throws RemoteException {
Log.d(TAG, "attachApplication() start");
mAppThread = IMyAppThread.Stub.asInterface(appThread);
if (mAppThread != null) {
mAppThread.bindApplication();
mAppThread.scheduleCreateService();
mAppThread.scheduleBindService();
Log.d(TAG, "call bindApplication()/scheduleCreateService()/scheduleBindService()");
Log.d(TAG, "attachApplication() end");
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_handler_looper);
mDelaySecondsEditText = (EditText) findViewById(R.id.delay_seconds_edittext);
Button test_handler_looper_Button = (Button) findViewById(R.id.test_handler_looper);
test_handler_looper_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Editable edit = mDelaySecondsEditText.getText();
int delaySeconds = 3;
if (!edit.toString().trim().equals("")) {
delaySeconds = Integer.parseInt(edit.toString());
}
Intent intent =new Intent();
intent.setClassName("com.galian.app_a",
"com.galian.app_a.MyHandlerService");
// 通过Intent将binder对象传递给模拟的App B
IMyActivityManager binder = new MyActivityManagerService();
Bundle extras = new Bundle();
extras.putBinder("binder", (IBinder)binder);
extras.putInt("delay", delaySeconds);
intent.putExtras(extras);
Log.d(TAG, "star MyHandlerService");
// App B的ActivityThread的模拟是通过Service来实现的
startService(intent);
}
});
Button finish_test_handler_looper_Button = (Button) findViewById(R.id.finish_test_handler_looper);
finish_test_handler_looper_Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent =new Intent();
intent.setClassName("com.galian.app_a",
"com.galian.app_a.MyHandlerService");
stopService(intent);
}
});
}
}
2.2 模拟App B的ActivityThread
- (1)用于与AMS通信的IMyAppThread.aidl
package com.galian.app_a;
interface IMyAppThread {
void bindApplication();
void scheduleCreateService();
void scheduleBindService();
}
- (2)通过Service + Thread来模拟App B的ActivityThread
package com.galian.app_a;
...
import com.galian.ams.IMyActivityManager;
public class MyHandlerService extends Service {
private static final String TAG = "AppA/MyHandlerService";
IMyAppThread myAppThread = new MyAppThread();
private int delaySeconds = 0;
private MyHandler mHandler = null;
private Looper mLooper = null;
private boolean isLooperOK = false;
@Override
public void onCreate() {
super.onCreate();
// 模拟ActivityThread启动
Thread thread = new MyThread();
thread.start();
Log.d(TAG, "onCreate()");
}
@Override
public void onDestroy() {
mLooper.quitSafely();
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
Bundle extras = intent.getExtras();
IMyActivityManager activityManager = IMyActivityManager.Stub.asInterface(extras.getBinder("binder"));
try {
// 服务启动
if (activityManager != null) {
Log.d(TAG, "attachApplication()");
activityManager.attachApplication(myAppThread.asBinder());
}
} catch (RemoteException e) {
e.printStackTrace();
}
delaySeconds = extras.getInt("delay");
isLooperOK = true;// Looper在延迟几秒后可以正常运行了
}
return Service.START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private class MyAppThread extends IMyAppThread.Stub {
@Override
public void bindApplication() throws RemoteException {
Message msg = Message.obtain();
msg.what = MyHandler.BIND_APP;
Log.d(TAG, "send BIND_APP msg");
mHandler.sendMessage(msg);
}
@Override
public void scheduleCreateService() throws RemoteException {
Message msg = Message.obtain();
msg.what = MyHandler.CREATE_SVC;
Log.d(TAG, "send CREATE_SVC msg");
mHandler.sendMessage(msg);
}
@Override
public void scheduleBindService() throws RemoteException {
Message msg = Message.obtain();
msg.what = MyHandler.BIND_SVC;
Log.d(TAG, "send BIND_SVC msg");
mHandler.sendMessage(msg);
}
}
public class MyHandler extends Handler {
public static final int BIND_APP = 1;
public static final int CREATE_SVC = 2;
public static final int BIND_SVC = 3;
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APP:
Log.d(TAG, "handleBindApplication()");
break;
case CREATE_SVC:
Log.d(TAG, "handleCreateService()");
break;
case BIND_SVC:
Log.d(TAG, "handleBindService()");
break;
default:
break;
}
}
}
private class MyThread extends Thread {
@Override
public void run() {
Log.d(TAG, "thread is running.");
// 创建Handler、Looper
Looper.prepare();
mHandler = new MyHandler();
mLooper = Looper.myLooper();
// 在服务没有执行onStartCommand()的时候,线程处于等待状态
while (!isLooperOK) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 延迟的目的是,确保处理消息的代码一定在规定的延迟时间之后执行
// 这样可以看出只有Looper.loop()执行之后,放入队列的消息才会被处理
Log.d(TAG, "sleep " + delaySeconds + " seconds");
try {
Thread.sleep(delaySeconds*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "Looper.loop()");
Looper.loop();
}
}
}
2.3 模拟测试的结果
- (1)模拟App B进程初次创建:MyHandlerService初次创建
01-30 00:40:06.767 15782 15782 D AMS/Test: star MyHandlerService
01-30 00:40:06.947 4537 4537 D AppA/MyHandlerService: onCreate()
01-30 00:40:06.947 4537 4567 D AppA/MyHandlerService: thread is running.
01-30 00:40:06.947 4537 4537 D AppA/MyHandlerService: attachApplication()
01-30 00:40:06.947 15782 15795 D AMS/Test: attachApplication() start
01-30 00:40:06.947 4537 4537 D AppA/MyHandlerService: send BIND_APP msg
01-30 00:40:06.947 4537 4537 D AppA/MyHandlerService: send CREATE_SVC msg
01-30 00:40:06.947 4537 4537 D AppA/MyHandlerService: send BIND_SVC msg
01-30 00:40:06.957 15782 15795 D AMS/Test: call bindApplication()/scheduleCreateService()/scheduleBindService()
01-30 00:40:06.957 15782 15795 D AMS/Test: attachApplication() end
01-30 00:40:07.447 4537 4567 D AppA/MyHandlerService: sleep 6 seconds
01-30 00:40:13.447 4537 4567 D AppA/MyHandlerService: Looper.loop()
01-30 00:40:13.447 4537 4567 D AppA/MyHandlerService: handleBindApplication()
01-30 00:40:13.447 4537 4567 D AppA/MyHandlerService: handleCreateService()
01-30 00:40:13.447 4537 4567 D AppA/MyHandlerService: handleBindService()
其中pid 4537为模拟App B的进程,pid 15782为AMS进程。
为了描述方便,下面提到的AMS和App B都是上面的代码模拟的出来的,不再说模拟的AMS和模拟的App B进程。
App B进程启动后,调用AMS的attachApplication();
AMS在attachApplication()中调用App B的接口,向App B的消息队列放入了3个消息:BIND_APP、CREATE_SVC和BIND_SVC。可以看到此时3个消息都放入了队列,但是没有被处理;
几秒后,Looper.loop()执行了,立即处理消息队列中的3个消息,而且是依次处理。
- (2)模拟App B进程已经启动:MyHandlerService已经运行,此时往消息队列放入消息
01-30 00:40:52.797 15782 15782 D AMS/Test: star MyHandlerService
01-30 00:40:52.797 4537 4537 D AppA/MyHandlerService: attachApplication()
01-30 00:40:52.807 15782 15795 D AMS/Test: attachApplication() start
01-30 00:40:52.807 4537 4537 D AppA/MyHandlerService: send BIND_APP msg
01-30 00:40:52.807 4537 4567 D AppA/MyHandlerService: handleBindApplication()
01-30 00:40:52.807 4537 4537 D AppA/MyHandlerService: send CREATE_SVC msg
01-30 00:40:52.807 4537 4537 D AppA/MyHandlerService: send BIND_SVC msg
01-30 00:40:52.807 15782 15795 D AMS/Test: call bindApplication()/scheduleCreateService()/scheduleBindService()
01-30 00:40:52.807 15782 15795 D AMS/Test: attachApplication() end
01-30 00:40:52.807 4537 4567 D AppA/MyHandlerService: handleCreateService()
01-30 00:40:52.817 4537 4567 D AppA/MyHandlerService: handleBindService()
可以看到,将消息放入消息队列,消息是被立即处理的。
注:这里说的“立即处理”不是同步处理,AMS进程和App B进程是并行的。
3. 总结
(1)本文所讲的内容,即使被你忽略了,也不影响对bindService()代码流程的理解
(2)在App进程首次创建的时候,在Looper.loop()运行之前,AMS调用IApplicationThread接口放入App 消息队列的消息不会立即被处理。在Looper.loop()运行的时候,将依次处理消息队列中的所有消息。
继续阅读:
《Android中bindService的细节之一:从进程的角度分析绑定Service的流程【Service所在进程首次启动】》
《Android中bindService的细节之二:从进程的角度分析绑定Service的流程【Service所在进程已存在】》