考察內容:
- service啓動有哪幾種方式?
- service啓動過程中主要流程有哪些?
- service啓動過程涉及哪些參與者,通信過程是怎樣的?
Service啓動原理
用startService啓動Service:
@Override
public ComponentName startService(Intent service) {
return startServiceCommon(service, mUser);
}
ComponentName startServiceCommon(Intent service, ...){
ComponentName cn = ActivityManagerNative.getDefault()
.startService(mMainThread.getApplicationThread(), service, ...);
return cn;
}
AMS中的處理:
ComponentName startService(IApplicationThread caller, Intent service, ...){
ComponentName res = mServices.startServiceLocked(caller, service, ...);
return res;
}
根據intent 查詢service Record對象:
每個應用端的Service在AMS中都對應一個ServiceRecore對象
ComponentName startServiceLocked(Intent service, ...){
ServiceLookupResult res = retrieveServiceLocked(service, ...);
ServiceRecord r = res.record;
...
//查到ServiceRecord之後new了一個StartItem並加到pendingStart裏面,
//爲後面調用onStartCommand準備
r.pendingStart.add(new ServiceRecord.StartItem(r, ...));
...
return startServiceInnerLocked(smap, service, r, ...);
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ...){
bringUpServiceLocked(r, service.getFlags(), callerFg, false);
}
final String bringUpServiceLocked(ServiceRecord r, ...){
if(r.app != null && r.app.thread != null) {
//如果Service已經啓動了,就調用下面這個函數,
//它將觸發應用端的onStartCommand
sendServiceArgsLocked(r, ...);
return null;
}
//Service還沒啓動的情況:
ProcessRecord app = mAm.getProcessRecordLocked(procName, ...);
if(app != null && app.thread != null){
//如果Service所在的進程已經啓動了,真正啓動Service
//r.app就是在下面這個函數中設置的
realStartServiceLocked(r, app, execInFg);
return null;
}
//Service所在進程沒有啓動或者雖然已經啓動但還沒就緒的情況:
if(app == null){
//app進程還沒啓動,啓動進程
app = mAm.startProcessLocked(procName, ...);
}
if(!mPendingServices.contains(r)){
//把ServiceRecord加到pending列表裏面,等待進程啓動後再處理
mPendingServices.add(r);
}
...
}
進程啓動的流程圖:
- AMS通過socket向Zygote發起啓動進程的請求
- Zygote收到請求之後就會啓動進程
- 應用進程向AMS發起attachApplication的binder調用,把自己的binder對象註冊到AMS(註冊完之後對於AMS來說這個應用就算是就緒了)
- 通過應用進程註冊過來的applicationThread嚮應用端發起bindApplication調用,主應用初始化application(這步完事後AMS就可以處理Pending的組件了)
AMS中處理attachApplication的函數:
boolean attachApplicationLocked(IApplicationThread thread, ...) {
...
mServices.attachApplicationLocked(app, processName);
...
return true;
}
//處理pending的Service
boolean attachApplicationLocked(ProcessRecord proc, ...){
for(int i = 0; i < mPendingServices.size(); i++){
sr = mPendingServices.get(i);
...
mPendingServices.remove(i--);
//對每一個pending的service調用realStartServiceLocked函數真正啓動service
realStartServiceLocked(sr, proc, ...);
}
...
}
void realStartServiceLocked(ServiceRecord r, ProcessRecord app, ...){
r.app = app;
...
//嚮應用端發起IPC調用,應用收到後就會創建Service,執行應用裏的onCreate回調
//參數r其實是一個binder對象: final class ServiceRecord extends Binder{}
//這是要存在應用端的,應用端有一個用來保存service對象的map,這裏的r就是key
app.thread.scheduleCreateService(r, r.serviceInfo, ...);
...
//觸發應用端Service的onStartCommand
sendServiceArgsLocked(r, ...);
}
應用端是如何處理AMS發過來的CreateServicd請求的:
private void handleCreateService(CreateServiceData data){
//先拿到loadedApk
LoadedApk packageInfo = getPackageInfoNoCheck(...);
//加載Service類,並通過newInstance調用其構造函數,從而獲得Service對象
Service service = (Service)cl.loadClass(data.info.name).newInstance();
//給這個Service創建一個Context對象
ContextImpl context = ContextImpl.createAppContext(this, ...);
//獲取Application,這個application是在應用啓動的時候創建的
Application app = packageInfo.makeApplication(flase, ...);
//給service賦予上下文
service.attach(context, this, ...);
//執行Service的生命週期
service.onCreate();
mServices.put(data.token, service);
...
}
mServices是一個map:
ArrayMap<IBinder, Service>
private final void sendServiceArgsLocked(ServiceRecord r, ){
while(r.pendingStarts.size() > 0){
//取出每一個pending的startItem
StartItem si = r.pendingStarts.remove(0);
...
//嚮應用端發起IPC調用
r.app.thread.scheduleServiceArgs(r, ...);
}
}
AMS是如何觸發應用端Service的onStartCommand的
AMS調用r.app.thread.scheduleServiceArgs(r, …)後,應用端的處理:
public final void scheduleServiceArgs(IBinder token, ...) {
//封裝了一個ServiceArgsData對象
ServiceArgsData s = new ServiceArgsData();
...
//丟到應用的主線程去處理
sendMessage(H.SERVICE_ARGS, s);
}
//應用端主線程的處理:
private void handleServiceArgs(ServiceArgsData data) {
//首先從mServices中把Service對象取出來。mService是一個map,其中:
//key就是AMS中的ServiceRecord的對象
//value就是應用端的Service對象
//data.token就是AMS中的ServiceRecord對象
Service s = mServices.get(data.token);
if(s != null){
...
//調用Service的onStartCommand
s.onStartCommand(data.args, data.flags, data.startId);
...
}
}
總結Service啓動的流程:
AMS端:
- 先看Service啓動了沒有:如果啓動了就直接發指令,讓應用端執行onStartCommand()
- 如果Service沒有啓動,就看它所在進程啓動了沒有:如果已經啓動,就去啓動Service,等Service啓動了之後再發送指令讓其執行onStartCommand
- 如果進程沒有啓動就去啓動進程,等進程啓動後再啓動Service
應用端:
- 先創建Service對象
- 再賦予上下文
- 最後調用生命週期onCreate()
用bindService啓動Service
啓動Service還有另一種情況:bindService的時候帶上BIND_AUTO_CREATE標記
int bindServiceLocked(IApplicationThread caller, ...){
...
if((flags & Context.BIND_AUTO_CREATE) != 0){
//如果帶上BIND_AUTO_CREATE標記
bringUpServiceLocked(s, ...);
}
...
}
binderService和startService的區別:
- binderService不會觸發應用端的onStartCommand函數
- 因爲binderService沒有把ServiceRecord加到mPendingStart隊列中
迴歸:說說service的啓動原理
- service啓動有幾種方式?
a) startService
b) bindService帶BIND_AUTO_CREATE - service啓動過程主要流程有哪些?
a)AMS端:
1)先看Service啓動了沒有:如果啓動了就直接發指令,讓應用端執行onStartCommand()
2)如果Service沒有啓動,就看它所在進程啓動了沒有:如果已經啓動,就去啓動Service,等Service啓動了之後再發送指令讓其執行onStartCommand
3)如果進程沒有啓動就去啓動進程,等進程啓動後再啓動Service
b)應用端:
1)先創建Service對象
2)再賦予上下文
3)最後調用生命週期onCreate()
- service啓動過程中有哪些參與者,通信過程是怎樣的?
a)參考下圖: