簡介
我們做app經(jīng)常會(huì)接觸到service這個(gè)組件,書上也經(jīng)常說,我們應(yīng)該把一些耗時(shí)的操作放到service中,那么問題來了,為什么我們要把耗時(shí)的操作放到service中,service有什么特殊的意義?放到service中就安然無恙了嗎?我們帶著這些問題,來看看我們今天的主角service,故事就這樣展開了。
掃個(gè)盲
- AMP:ActivityManagerProxy
- AMN:ActivityManagerNative
- AMS:ActivityManagerService
- AT:ApplicationThread
- ATP:ApplicationThreadProxy
- ATN:ApplicationThreadNative
我們看看這些寶貝類或者接口的關(guān)系圖:
使用
<service android:enabled=["true" | "false"]
android:exported[="true" | "false"]
android:icon="drawable resource"
android:label="string resource"
android:name="string"
android:permission="string"
android:process="string">
<intent-filter >
<action android:name="com.android.server.TestService.TestAction" />
</intent-filter>
</service>
在代碼中:
..............
Intent serviceIntent = new Intent(mContext, TestService.class);
serviceIntent.putExtra("Args", mArgs);
mContext.startService(serviceIntent);
..............
public class TestService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
...........
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
..............
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
..........
}
}
使用結(jié)果說明:
- onBind() :bind service的時(shí)候使用
- onCreate()
- onStartCommand()
- START_STICKY
當(dāng)Service因?yàn)閮?nèi)存不足而被系統(tǒng)kill后,在接下來的某個(gè)時(shí)間內(nèi),當(dāng)系統(tǒng)內(nèi)存足夠可用的情況下,系統(tǒng)將會(huì)嘗試重新創(chuàng)建此Service; 一旦創(chuàng)建成功后,將回調(diào)onStartCommand方法,但一般情況下,參數(shù)中的Intent將是null。
- START_NOT_STICKY
當(dāng)Service因?yàn)閮?nèi)存不足而被系統(tǒng)kill后,在接下來的某個(gè)時(shí)間內(nèi),即使系統(tǒng)內(nèi)存足夠可用,系統(tǒng)也不會(huì)嘗試重新創(chuàng)建此Service。
- START_REDELIVER_INTENT
與START_STICKY相同,當(dāng)Service因?yàn)閮?nèi)存不足而被系統(tǒng)kill后,在接下來的某個(gè)時(shí)間內(nèi),當(dāng)系統(tǒng)內(nèi)存足夠可用的情況下,系統(tǒng)將會(huì)嘗試重新創(chuàng)建此Service; 唯一不同的是,Service創(chuàng)建成功后,回調(diào)onStartCommand方法時(shí),傳入的參數(shù)將是最后一次調(diào)用startService時(shí)使用的intent。
- START_STICKY
需要注意的是,只有系統(tǒng)kill掉Service時(shí)上述返回值才有意義,如果是人為地kill掉Service進(jìn)程,系統(tǒng)不會(huì)按照onStartCommand的返回值重啟Service。
最后,客戶端無論調(diào)用多少次startService,只需要一次stopService即可將此Service終止(畢竟onCreate函數(shù)也之調(diào)用過一次),此時(shí)AMS將回調(diào)Service的onDestroy函數(shù)。
service啟動(dòng)的兩種方式
-
顯示啟動(dòng)
........... Intent startIntent = new Intent(); ComponentName componentName = new ComponentName("service的packagename", "service的classname"); startIntent.setComponent(componentName); mContext.startService(startIntent); ............
........... Intent startIntent = new Intent(mContext, TestService.class); mContext.startService(startIntent); ............
-
隱式啟動(dòng)
............ Intent startIntent = new Intent(); startIntent.setAction("com.android.server.TestService.TestAction"); mContext.startService(startIntent); ............
隱式啟動(dòng)在5.0以后廢棄
分析
先從Acvitiy說起,比如我們現(xiàn)在最常見的就是從Activity進(jìn)行startService(),我們先看一下繼承關(guān)系
Context
ContextWrapper
ContextThemeWrapper
Activity
當(dāng)我們調(diào)用startService的時(shí)候,其實(shí)是調(diào)用了ContextWrapper
中的方法。當(dāng)我們分析Activity如何創(chuàng)建的時(shí)候我們在來說ContextWrapper
是在那里創(chuàng)建的。
- 黃色表示當(dāng)前要啟動(dòng)service的進(jìn)程
- 綠色表示systemserver進(jìn)程
- service所在進(jìn)程(有可能在同一個(gè)進(jìn)程,也有可能不再同一個(gè)進(jìn)程)
核心方法
AS.startServiceLocked()
part1
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
................
final boolean callerFg;
if (caller != null) {
//通過AMS得到調(diào)用方的進(jìn)程信息
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
................
//判斷調(diào)用方是否屬于前臺(tái)進(jìn)程
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
//檢索待啟動(dòng)的Service
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);//[part1-1]
..................
//從ServiceLookupResult中取出ServiceRecord
ServiceRecord r = res.record;
.................
如果調(diào)用者為null,則callerFg = true,否則callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;通過這個(gè)來判斷是不是處于后臺(tái)
補(bǔ)充知識(shí):
- 內(nèi)核負(fù)責(zé)了進(jìn)程的CPU調(diào)度,所有運(yùn)行中的進(jìn)程并非能平等的能獲取相等的時(shí)間片。在ProcessRecord中,通過Schedule Group來記錄進(jìn)程的調(diào)度組:
- 它們可能的取值定義在ProcessList.java中:
// Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE
static final int SCHED_GROUP_BACKGROUND = 0;
// Activity manager's version of Process.THREAD_GROUP_DEFAULT
static final int SCHED_GROUP_DEFAULT = 1;
// Activity manager's version of Process.THREAD_GROUP_TOP_APP
static final int SCHED_GROUP_TOP_APP = 2;
// Activity manager's version of Process.THREAD_GROUP_TOP_APP
// Disambiguate between actual top app and processes bound to the top app
static final int SCHED_GROUP_TOP_APP_BOUND = 3;
其中獲取CPU資源的能力來看,
SCHED_GROUP_TOP_APP_BOUND
最高,其次SCHED_GROUP_TOP_APP
應(yīng)該強(qiáng)于SCHED_GROUP_DEFAULT
, 最后才輪到SCHED_GROUP_BACKGROUND
part1-1 retrieveServiceLocked()
private ServiceLookupResult retrieveServiceLocked(.......) {
ServiceRecord r = null;
..........
//得到當(dāng)前用戶的UserId
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
//每個(gè)UserId有對應(yīng)的ServiceMap,統(tǒng)一保存在ActiveServices中
ServiceMap smap = getServiceMap(userId);
//對于顯示啟動(dòng)
final ComponentName comp = service.getComponent();
if (comp != null) {
//根據(jù)ComponentName從ServiceMap中取出對應(yīng)的ServiceRecord
r = smap.mServicesByName.get(comp);
}
//對于隱式啟動(dòng)
if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
//根據(jù)Intent對應(yīng)的Filter,從ServiceMap中取出匹配的ServiceRecord
r = smap.mServicesByIntent.get(filter);
}
//特殊情況的處理
//對于包含F(xiàn)LAG_EXTERNAL_SERVICE的service,將運(yùn)行于調(diào)用方進(jìn)程中
//對于這種特殊服務(wù),
//如果根據(jù)Component或Filter找到了一個(gè)正在運(yùn)行的Service,但其運(yùn)行進(jìn)程與當(dāng)前調(diào)用進(jìn)程不一致
//那么必須重新在調(diào)用進(jìn)程中創(chuàng)建該ServiceRecord,于是將r置為null
if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
&& !callingPackage.equals(r.packageName)) {
// If an external service is running within its own package, other packages
// should not bind to that instance.
r = null;
}
//以上均是在緩存信息中,查找ServiceRecord
//如果查詢不到,則必須通過PKMS進(jìn)行查找
if (r == null) {
try {
//PKMS根據(jù)參數(shù)得到對應(yīng)Pkg中Serivce的ResolveInfo
ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId);
//從ResolveInfo中取出ServiceInfo
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
//構(gòu)造出Service對應(yīng)的ComponentName
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
//特殊情況處理
if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
if (isBindExternal) {
..............
// Run the service under the calling package's application.
//FLAG_EXTERNAL_SERVICE將運(yùn)行在調(diào)用方進(jìn)程中,此處就是修改PKMS檢索出的ServiceInfo
//先得到調(diào)用方的應(yīng)用信息
ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
............
//將ServiceInfo中的信息,改為調(diào)用方應(yīng)用的信息
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
sInfo.applicationInfo.packageName = aInfo.packageName;
sInfo.applicationInfo.uid = aInfo.uid;
name = new ComponentName(aInfo.packageName, name.getClassName());
service.setComponent(name);
} else {
//拋出異常
.....
}
} else if(isBindExternal) {
//拋出異常
............
}
//多用戶的處理
if (userId > 0) {
//檢查服務(wù)是否為單例且可被調(diào)用的
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)
&& mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
//對于多用戶而言,每個(gè)用戶啟動(dòng)的服務(wù),運(yùn)行于對應(yīng)用戶所在進(jìn)程組中
//但如果待啟動(dòng)服務(wù)為單例的,那么該服務(wù)還是得運(yùn)行在系統(tǒng)用戶的進(jìn)程組中
//于是此次將userId置為0
userId = 0;
//ServiceMap都被調(diào)整為系統(tǒng)用戶對應(yīng)的
smap = getServiceMap(0);
}
sInfo = new ServiceInfo(sInfo);
//此處使用了userId
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
r = smap.mServicesByName.get(name);
if (r == null && createIfNeeded) {
..............
//創(chuàng)建出對應(yīng)的ServiceRecord
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
..............
//保存到ServiceMap中
smap.mServicesByName.put(name, r);
smap.mServicesByIntent.put(filter, r);
}
} catch(RemoteException ex) {
...........
}
}
if (r != null) {
//進(jìn)行一些權(quán)限檢查和有效性檢查
.................
//沒有問題時(shí),返回正常結(jié)果
return new ServiceLookupResult(r, null);
}
return null;
}
- 得到當(dāng)前用戶的userId
- 根據(jù)userId得到ServiceMap,這個(gè)ServiceMap保存在ActiveServices中
- 根據(jù)顯示啟動(dòng)和隱式啟動(dòng)從ServiceMap中拿出來ServiceRecord
- 上面信息都是從當(dāng)前ActiveServices中的ServiceMap(緩存)中查找,如果沒有找到則通過PKMS進(jìn)行查找
- 最后確保沒有問題返回一個(gè)包裝ServiceRecord對象的ServiceLookupResult對象
part2
//進(jìn)行一些檢查工作
.............
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record;
if (!mAm.getUserManagerLocked().exists(r.userId)) { //檢查是否存在啟動(dòng)服務(wù)的user
return null;
}
//如果這個(gè)服務(wù)在重啟列表中,清空對應(yīng)的信息
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
.................
}
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
//startService可以多次向Service傳遞信息,每次的信息都是一個(gè)StartItem,對應(yīng)著一個(gè)StartId
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
............
//addToStarting決定是否將待啟動(dòng)的Service
//加入到ActiveServices維護(hù)的mStartingBackground隊(duì)列
boolean addToStarting = false;
//如果啟動(dòng)服務(wù)的不是前臺(tái)進(jìn)程
//同時(shí)服務(wù)對應(yīng)的ServiceRecord中沒有記錄對應(yīng)進(jìn)程的信息(即初次使用)
if (!callerFg && r.app == null
//并且user已經(jīng)啟動(dòng)過其它進(jìn)程
&& mAm.mUserController.hasStartedUserState(r.userId)) {
//通過AMS查詢Service對應(yīng)的進(jìn)程信息
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
//若Service對應(yīng)的進(jìn)程未啟動(dòng),或優(yōu)先級過低,則有可能需要延遲啟動(dòng)服務(wù)
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
.....................
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
return r.name;
}
//若當(dāng)前用戶啟動(dòng)的后臺(tái)服務(wù)數(shù)量過多,則延遲啟動(dòng)服務(wù)
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
................
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
..............
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
addToStarting = true;
................
} ..........
............
} ............
...............
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
- 做一些檢查工作
- 如果這個(gè)服務(wù)在重啟列表中將晴空對應(yīng)信息
- startService可以多次向Service傳遞信息,每次的信息都是一個(gè)StartItem,對應(yīng)著一個(gè)StartId
- boolean addToStarting決定是否將待啟動(dòng)的Service加入到ActiveServices維護(hù)的mStartingBackground隊(duì)列
- 如果啟動(dòng)服務(wù)的不是前臺(tái)進(jìn)程,同時(shí)服務(wù)對應(yīng)的ServiceRecord中沒有記錄對應(yīng)進(jìn)程的信息(即初次使用)并且user已經(jīng)啟動(dòng)過其它進(jìn)程則
- 通過AMS查詢Service對應(yīng)的進(jìn)程信息
- 如果Service對應(yīng)進(jìn)程沒有啟動(dòng),或者優(yōu)先級低,則有可能需要延遲啟動(dòng)服務(wù)
- 如果當(dāng)前用戶啟動(dòng)的后臺(tái)服務(wù)數(shù)量大于后臺(tái)啟動(dòng)最大服務(wù)數(shù)量,則延遲啟動(dòng)
//若當(dāng)前用戶啟動(dòng)的后臺(tái)服務(wù)數(shù)量過多,則延遲啟動(dòng)服務(wù) if (smap.mStartingBackground.size() >= mMaxStartingBackground) { ................ smap.mDelayedStartList.add(r); r.delayed = true; return r.name; }
- addToStarting = true;(當(dāng)服務(wù)對應(yīng)的ServiceRecord沒有記錄對應(yīng)的進(jìn)程信息,如果不是延遲啟動(dòng))||(包含service的進(jìn)程已經(jīng)存在并且proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE//
Process is in the background running a service.
)
概述:
判斷當(dāng)前Service是否需要延遲啟動(dòng)。
若需要延遲啟動(dòng),則將ServiceRecord保存到smap中的mDelayedStartList中,并結(jié)束本啟動(dòng)流程;
否則,調(diào)用startServiceInnerLocked函數(shù),進(jìn)入啟動(dòng)Service的下一個(gè)階段。
AS.startServiceInnerLocked()
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ProcessStats.ServiceState stracker = r.getTracker();
if (stracker != null) {
//更新ServiceRecord的ServiceState
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked(); //用于耗電統(tǒng)計(jì),開啟運(yùn)行的狀態(tài)
}
//核心啟動(dòng)service的方法
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
if (error != null) {
return new ComponentName("!!", error);
}
//
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
if (first) {
smap.rescheduleDelayedStarts();
}
} else if (callerFg) {
smap.ensureNotStartingBackground(r);
}
return r.name;
}
- 通過
bringUpServiceLocked
真正啟動(dòng)service - 當(dāng)啟動(dòng)完成的時(shí)候設(shè)置啟動(dòng)超時(shí)時(shí)間
- 啟動(dòng)成功之后將ServiceRecord加入到smap中的mStartingBackground中
- 如果是第一次啟動(dòng)則需要從smap.rescheduleDelayedStarts();中移除MSG_BG_START_TIMEOUT(service未啟動(dòng)ANR)并且從mStartingBackground(后臺(tái)啟動(dòng)service列表中)移除,仔細(xì)研究見下文
AS.rescheduleDelayedStarts()
void rescheduleDelayedStarts() {
//前面的注釋已經(jīng)提到過,后臺(tái)進(jìn)程啟動(dòng)Service超時(shí)會(huì)發(fā)送MSG_BG_START_TIMEOUT消息
//該消息被處理時(shí),也會(huì)調(diào)用rescheduleDelayedStarts函數(shù)
//因此,進(jìn)入該函數(shù)時(shí),先移除掉該信息
removeMessages(MSG_BG_START_TIMEOUT);
final long now = SystemClock.uptimeMillis();
for (int i=0, N=mStartingBackground.size(); i<N; i++) {
ServiceRecord r = mStartingBackground.get(i);
//將超時(shí)的Service從mStartingBackground中移除
if (r.startingBgTimeout <= now) {
Slog.i(TAG, "Waited long enough for: " + r);
mStartingBackground.remove(i);
N--;
i--;
}
}
//存在延遲Service,同時(shí)后臺(tái)Service較少時(shí)
while (mDelayedStartList.size() > 0
&& mStartingBackground.size() < mMaxStartingBackground) {
ServiceRecord r = mDelayedStartList.remove(0);
.................
r.delayed = false;
try {
//啟動(dòng)延遲Service,啟動(dòng)后會(huì)修改mStartingBackground.size
startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true);
} catch (TransactionTooLargeException e) {
..........
}
if (mStartingBackground.size() > 0) {
ServiceRecord next = mStartingBackground.get(0);
//決定延遲發(fā)送消息的時(shí)間
long when = next.startingBgTimeout > now ? next.startingBgTimeout : now;
................
Message msg = obtainMessage(MSG_BG_START_TIMEOUT);
//一旦超時(shí),就會(huì)發(fā)送MSG_BG_START_TIMEOUT
sendMessageAtTime(msg, when);
}
.....................
}
}
- 移除MSG_BG_START_TIMEOUT消息
- 將超時(shí)的Service從mStartingBackground中移除
- 存在延時(shí)service并且沒有達(dá)到后臺(tái)啟動(dòng)service最大數(shù)量的時(shí)候啟動(dòng)延時(shí)的service
- 在mStartingBackground.size()>0后,發(fā)送延時(shí)啟動(dòng)消息一旦時(shí)間到達(dá)或者時(shí)間時(shí)間超出,則發(fā)送信號(hào)重新調(diào)用rescheduleDelayedStarts()
概述:
- 判斷mStartingBackground中啟動(dòng)的Service是否超時(shí)
- 判斷能否啟動(dòng)mDelayedStartList中,被延遲啟動(dòng)的服務(wù)。
AS.bringUpServiceLocked()
private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException {
//處理Service已經(jīng)啟動(dòng)的情況,此時(shí)只是發(fā)送新的StartItem
if (r.app != null && r.app.thread != null) {
//調(diào)用service.onStartCommand()過程
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && r.restartDelay > 0) {
return null; //等待延遲重啟的過程,則直接返回
}
// 啟動(dòng)service前,把service從重啟服務(wù)隊(duì)列中移除
if (mRestartingServices.remove(r)) {
r.resetRestartCounter();
clearRestartingIfNeededLocked(r);
}
//service正在啟動(dòng),將delayed設(shè)置為false
if (r.delayed) {
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
//確保擁有該服務(wù)的user已經(jīng)啟動(dòng),否則停止;
if (mAm.mStartedUsers.get(r.userId) == null) {
String msg = "";
bringDownServiceLocked(r);
return msg;
}
//服務(wù)正在啟動(dòng),設(shè)置package停止?fàn)顟B(tài)為false
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
//根據(jù)進(jìn)程名和uid,查詢ProcessRecord
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
//能進(jìn)入此循環(huán)說明對應(yīng)進(jìn)程已經(jīng)啟動(dòng)
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 啟動(dòng)服務(wù)
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
app = r.isolatedProc;
}
//對于進(jìn)程沒有啟動(dòng)的情況
if (app == null) {
//啟動(dòng)service所要運(yùn)行的進(jìn)程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
String msg = ""
bringDownServiceLocked(r); // 進(jìn)程啟動(dòng)失敗
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
//mPendingServices保存待啟動(dòng)服務(wù),當(dāng)進(jìn)程啟動(dòng)后,會(huì)重新啟動(dòng)該服務(wù)
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
//服務(wù)還未完成啟動(dòng),就收到結(jié)束請求時(shí),會(huì)直接停止該服務(wù)
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r); //停止服務(wù)
}
}
return null;
}
- service已經(jīng)啟動(dòng)過了,則調(diào)用sendServiceArgsLocked函數(shù),將新的待處理信息發(fā)送給Service
- service未啟動(dòng)過,但對應(yīng)的進(jìn)程已啟動(dòng),那么調(diào)用realStartServiceLocked函數(shù),啟動(dòng)服務(wù)即可;
- service對應(yīng)的進(jìn)程并沒有啟動(dòng),那么先啟動(dòng)進(jìn)程。在啟動(dòng)進(jìn)程過程中會(huì)調(diào)用realStartServiceLocked啟動(dòng)service
所以這里,如果service啟動(dòng)過了,現(xiàn)在重新調(diào)用啟動(dòng)函數(shù)的話,則只是將intent的信息發(fā)送給service進(jìn)行處理,如果service沒有啟動(dòng)但是進(jìn)程啟動(dòng)了,那么就會(huì)啟動(dòng)service,如果連進(jìn)程都沒有啟動(dòng)則會(huì)啟動(dòng)進(jìn)程,然后在啟動(dòng)進(jìn)程的過程中會(huì)啟動(dòng)service
AS.realStartServiceLocked()
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
//發(fā)送delay消息
bumpServiceExecutingLocked(r, execInFg, "create");
//更新進(jìn)程對應(yīng)的優(yōu)先級信息
mAm.updateLruProcessLocked(app, false, null);
mAm.updateOomAdjLocked();
boolean created = false;
try {
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
//更改進(jìn)程狀態(tài)為PROCESS_STATE_SERVICE
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//服務(wù)進(jìn)入 onCreate()
//此時(shí)又是Binder通信,發(fā)送消息給目標(biāo)進(jìn)程的ApplicationThread,通知去創(chuàng)建服務(wù)
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
mAm.appDiedLocked(app); //當(dāng)是被時(shí)候會(huì)讓這個(gè)進(jìn)程也掛掉
throw e;
} finally {
if (!created) {
//如果服務(wù)創(chuàng)建失敗,則看是不是mDestroyingServices列表中有記錄,如果有則執(zhí)行一些銷毀動(dòng)作
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
if (newService) {
app.services.remove(r);
r.app = null;
}
//嘗試重新啟動(dòng)服務(wù)
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
//Service被綁定過,才會(huì)調(diào)用onBind函數(shù)
requestServiceBindingsLocked(r, execInFg);
//如果客戶端Bind Service成功,按需更新服務(wù)端進(jìn)程優(yōu)先級
updateServiceClientActivitiesLocked(app, null, true);
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
//會(huì)調(diào)用sendServiceArgsLocked()方法發(fā)送參數(shù)
sendServiceArgsLocked(r, execInFg, true);
//如果Service是延遲啟動(dòng)的,那么此時(shí)可以將其從mDelayedStartList移除
if (r.delayed) {
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
//若Service被要求停止,那么結(jié)束服務(wù)
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r); //停止服務(wù)
}
}
}
- 對service的狀態(tài)進(jìn)行記錄(bumpServiceExecutingLocked)
- 更新進(jìn)程對應(yīng)的優(yōu)先級信息(mAm.updateOomAdjLocked();)
- 強(qiáng)制更改進(jìn)程的狀態(tài)(為PROCESS_STATE_SERVICE)
- 通過Binder通信發(fā)送消息給進(jìn)程的ApplicationThread,創(chuàng)建服務(wù)(app.thread.scheduleCreateService())
- 如果創(chuàng)建失敗則會(huì)kill進(jìn)程
- 如果符合重啟條件則會(huì)重啟service
- 如果調(diào)用過Bind service,則會(huì)調(diào)用(requestServiceBindingsLocked()---> OnBind函數(shù))
- 如果Bind成功則會(huì)按照需求更新service進(jìn)程的優(yōu)先級
- 構(gòu)造一個(gè)StartItem然后通過sendServiceArgsLocked發(fā)送參數(shù)(sendServiceArgsLocked())
- 如果service是延時(shí)啟動(dòng)的則將其從mDelayedStartList中移除(getServiceMap(r.userId).mDelayedStartList.remove(r);)
- 如果service被主動(dòng)要求停止那么調(diào)用(stopServiceLocked(r))
小節(jié)重點(diǎn):
- 對service的狀態(tài)進(jìn)行記錄(bumpServiceExecutingLocked)
- 通過Binder通信發(fā)送消息給進(jìn)程的ApplicationThread,創(chuàng)建服務(wù)(app.thread.scheduleCreateService())
- 構(gòu)造一個(gè)StartItem然后通過sendServiceArgsLocked發(fā)送參數(shù)(sendServiceArgsLocked())
AS.bumpServiceExecutingLocked()
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
..............
long now = SystemClock.uptimeMillis();
//executeNesting用于記錄Service待處理的請求數(shù)量
if (r.executeNesting == 0) {
//處理第一個(gè)命令時(shí),即初次啟動(dòng)Service時(shí)
r.executeFg = fg;
ServiceState stracker = r.getTracker();
if (stracker != null) {
//記錄時(shí)間
stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
if (r.app != null) {
//更新進(jìn)程ProcessRecord中關(guān)于Service的記錄
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
if (r.app.executingServices.size() == 1) {
//設(shè)置啟動(dòng)Service超時(shí)的時(shí)間
//即Service初次啟動(dòng)時(shí),如果進(jìn)程中只有這一個(gè)Service
//那么一旦啟動(dòng)超時(shí),將觸發(fā)AMS發(fā)送ANR
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
//前臺(tái)進(jìn)程向后臺(tái)服務(wù)發(fā)送命令時(shí),也會(huì)設(shè)置超時(shí)時(shí)間,一旦超時(shí),也會(huì)ANR
//發(fā)送一次后,該值變?yōu)閠rue,相當(dāng)與變成前臺(tái)服務(wù)了
r.app.execServicesFg = true;
scheduleServiceTimeoutLocked(r.app);
}
r.executeFg |= fg;
//每處理一個(gè)命令,executeNesting均會(huì)+1
r.executeNesting++;
r.executingStart = now;
}
這個(gè)方法主要將service和進(jìn)程關(guān)聯(lián)起來(更新ServiceRecord中的信息),并且如果進(jìn)程中只有一個(gè)service那么一旦超時(shí)就會(huì)給AMS發(fā)送ANR信息
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
//進(jìn)程中需要執(zhí)行service和當(dāng)前進(jìn)程都得存活
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
long now = SystemClock.uptimeMillis();
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg,
//前臺(tái)超時(shí)的時(shí)間為20s,后臺(tái)為200s
proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}
這里看到?jīng)],是通過proc.execServicesFg判斷service是否在前后臺(tái)
AS.scheduleCreateService()
AS.scheduleCreateService()-->ActivityThread發(fā)送H.CREATE_SERVICE-->ActivityThread.handleCreateService()
private void handleCreateService(CreateServiceData data) {
....................
//得到這個(gè)進(jìn)程對應(yīng)的LoadedApk
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//通過反射創(chuàng)建出實(shí)例
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
..................
}
try {
............
//創(chuàng)建service的ContextImpl對象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//實(shí)際工作類為ContextImpl,其代理設(shè)置為service
context.setOuterContext(service);
//得到app的Application對象
Application app = packageInfo.makeApplication(false, mInstrumentation);
//將一些重要的信息和對象綁定到service中
//此處傳遞的this是ActivityThread,這就是大家常說的:service也是運(yùn)行在主線程中的原因
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//調(diào)用Service的onCreate函數(shù)
service.onCreate();
//mServices中存儲(chǔ)了ActivityThread中運(yùn)行的服務(wù)
//key值為Service對應(yīng)的IBinder,是從Service對應(yīng)的ServiceRecord中取出的
mServices.put(data.token, service);
try {
//通知AMS service啟動(dòng)成功,進(jìn)行取消超時(shí)消息等操作
//后文再分析該函數(shù)
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
.............
}
}
- 得到Service對應(yīng)的LoadedApk信息
- 通過反射創(chuàng)建出service實(shí)例
- 創(chuàng)建service的ContextImpl
- 將service類設(shè)置成代理,實(shí)際工作的是ContextImpl
- 將service綁定一些常用的對象(service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault());)其中this是當(dāng)前進(jìn)程的ActiveThread對象
- 調(diào)用service.onCreate()方法
- 將當(dāng)前service添加到ActivityThread的mServices中利用鍵值對方式(mServices.put(data.token, service);)
- 通知AMS service啟動(dòng)成功,進(jìn)行取消ANR那個(gè)消息(ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);)
小節(jié):
- 得到LoadedApk反射得到service
- 讓service持有當(dāng)前進(jìn)程的核心對象(service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault());)其中this是當(dāng)前進(jìn)程的ActiveThread對象
- 調(diào)用service.onCreate()方法
- 移除啟動(dòng)爆發(fā)那個(gè)ANR消息
AS.sendServiceArgsLocked()
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
...............
//本次需發(fā)送的信息,在調(diào)用sendServiceArgsLocked前,已經(jīng)加入到了pendingStarts中
//通過循環(huán),將pending的信息發(fā)送完
while (r.pendingStarts.size() > 0) {
...........
try {
//依次取出
si = r.pendingStarts.remove(0);
............
si.deliveredTime = SystemClock.uptimeMillis();
//記錄發(fā)送時(shí)間和發(fā)送次數(shù)
r.deliveredStarts.add(si);
si.deliveryCount++;
...........
int flags = 0;
//發(fā)送次數(shù)大于1,添加對應(yīng)flag
if (si.deliveryCount > 1) {
flags |= Service.START_FLAG_RETRY;
}
//這個(gè)應(yīng)該是service被kill掉后,系統(tǒng)重啟服務(wù)發(fā)送的Intent,于是添加對應(yīng)的flag
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
//Binder通信給ApplicationThread
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} ..........
...........
}
}
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),service, neededGrants));這個(gè)方法我們在許多地方調(diào)用比如在startServiceLocked()中,我們是將需要給service傳遞的信息封裝成一個(gè)startItem,在這個(gè)方法中我們將其發(fā)送給setvice,下面我們就看發(fā)送流程
- 取出StartItem消息
- 記錄發(fā)送時(shí)間和次數(shù)
- 當(dāng)發(fā)送次數(shù)大于1,則添加對應(yīng)的flag
- 通過binder方式給ApplicationThread發(fā)送這個(gè)startItem
r.app.thread.scheduleServiceArgs()-->
H.SERVICE_ARGS-->
ActivityThread.handleServiceArgs()
ActivityThread.handleServiceArgs()
private void handleServiceArgs(ServiceArgsData data) {
//取出IBinder對應(yīng)的Service
Service s = mServices.get(data.token);
if (s != null) {
try {
.........
int res;
//通常情況,taskRemoved為false
if (!data.taskRemoved) {
//調(diào)用Service的onStartCommand函數(shù),處理Intent攜帶的內(nèi)容
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
//在通知AMS消息處理完成前,現(xiàn)完成本地等待處理的任務(wù)
//這里與啟動(dòng)BroadcastReceiver對應(yīng)進(jìn)程的情況相似
//進(jìn)程可能是由于創(chuàng)建Service才被啟動(dòng)的,Service處理完畢后,AMS可能進(jìn)行進(jìn)程管理
//殺死Service對應(yīng)進(jìn)程,因此先確保工作做完
QueuedWork.waitToFinish();
try {
//再次調(diào)用AMS的serviceDoneExecuting函數(shù),通知AMS消息處理完畢
//本次的flag為SERVICE_DONE_EXECUTING_START
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
ensureJitEnabled();
} catch(Exception e) {
........
}
}
}
很明確這里是會(huì)調(diào)用Service.onConmmand函數(shù),處理Intent攜帶的內(nèi)容
所以我們可以知道,Service.onConmmand函數(shù)可以調(diào)用多次,但是Service.onCreate()方法只能調(diào)用一次
然后再次調(diào)用AMS的serviceDoneExecuting函數(shù)通知執(zhí)行結(jié)果。
不過這里需要注意的是當(dāng)前調(diào)用onStartCommand之后會(huì)有一個(gè)結(jié)果返回,要根據(jù)這個(gè)結(jié)果AMS要做一些處理。我們先補(bǔ)充一點(diǎn)使用onStartCommand的知識(shí)。
(1):onstart()方法和onStartCommand()方法的區(qū)別:
onstart()方法是在android2.0一下的版本中使用。而在android2.0以上則使用onstartCommand()方法。它們兩個(gè)方法放在一起使用時(shí),不會(huì)產(chǎn)生沖突。
(2):onStartComand使用時(shí),返回的是一個(gè)(int)整形。
這個(gè)整形可以有四個(gè)返回值:start_sticky、start_no_sticky、START_REDELIVER_INTENT、START_STICKY_COMPATIBILITY。
它們的含義分別是:
1):START_STICKY:如果service進(jìn)程被kill掉,保留service的狀態(tài)為開始狀態(tài),但不保留遞送的intent對象。隨后系統(tǒng)會(huì)嘗試重新創(chuàng)建service,由于服務(wù)狀態(tài)為開始狀態(tài),所以創(chuàng)建服務(wù)后一定會(huì)調(diào)用onStartCommand(Intent,int,int)方法。如果在此期間沒有任何啟動(dòng)命令被傳遞到service,那么參數(shù)Intent將為null。
2):START_NOT_STICKY:“非粘性的”。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)不會(huì)自動(dòng)重啟該服務(wù)
3):START_REDELIVER_INTENT:重傳Intent。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)會(huì)自動(dòng)重啟該服務(wù),并將Intent的值傳入。
4):START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保證服務(wù)被kill后一定能重啟。
然后我們看看通過 ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);調(diào)用之后的結(jié)果
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
............
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
//Service每執(zhí)行完一次命令都會(huì)通知AMS,serviceDoneExecutingLocked將被多次調(diào)用
//因此,該函數(shù)中需要處理的場景比較多
//先判斷該Service是否destroy
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
//Service的onStartCommand函數(shù)被調(diào)用后,通知AMS的type為SERVICE_DONE_EXECUTING_START
if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
r.callStart = true;
//處理onStartCommand的返回值
switch (res) {
case Service.START_STICKY_COMPATIBILITY:
case Service.START_STICKY: {
//找到startId對應(yīng)的StartItem,并移除(true)
r.findDeliveredStart(startId, true);
//這個(gè)值置為false后,Service被殺掉還有機(jī)會(huì)重啟
r.stopIfKilled = false;
break;
}
case Service.START_NOT_STICKY: {
//找到startId對應(yīng)的StartItem,并移除(true)
r.findDeliveredStart(startId, true);
if (r.getLastStartId() == startId) {
//服務(wù)kill掉,不再重啟
r.stopIfKilled = true;
}
break;
}
case Service.START_REDELIVER_INTENT: {
//找到startId對應(yīng)的StartItem,不移除(false)
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
si.deliveryCount = 0;
si.doneExecutingCount++;
r.stopIfKilled = true;
}
break;
}
.............
}
} else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
//Service的onStop函數(shù)被調(diào)用時(shí),通知AMS的type為SERVICE_DONE_EXECUTING_STOP
//打一些log而已,無實(shí)際操作
..................
}
..........
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
..........
} else {
........
}
}
主要針對處理onStartCommand的返回值
- Service.START_STICKY_COMPATIBILITY+Service.START_STICKY
1.找到startId對應(yīng)的StartItem,并移除(true) 2.這個(gè)值置為false后,Service被殺掉還有機(jī)會(huì)重啟
- Service.START_NOT_STICKY
1.找到startId對應(yīng)的StartItem,并移除(true) 2.服務(wù)kill掉,不再重啟
- Service.START_REDELIVER_INTENT
1.找到startId對應(yīng)的StartItem,不移除(false) 2.重傳Intent。使用這個(gè)返回值時(shí),如果在執(zhí)行完onStartCommand后,服務(wù)被異常kill掉,系統(tǒng)會(huì)自動(dòng)重啟該服務(wù),并將Intent的值傳入。
隨后調(diào)用serviceDoneExecutingLocked()
方法
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
...............
//ServiceRecord的一個(gè)命令執(zhí)行完畢,executeNesting -1
//這些操作與前面提過的bumpServiceExecutingLocked函數(shù),一一對應(yīng)
r.executeNesting--;
//所有命令執(zhí)行完畢
if (r.executeNesting <= 0) {
if (r.app != null) {
..............
r.app.execServicesFg = false;
//ServiceRecord被從executingServices移除,處理超時(shí)消息時(shí),不會(huì)處理該Service
r.app.executingServices.remove(r);
//整個(gè)進(jìn)程所有的Service命令均處理完畢
if (r.app.executingServices.size() == 0) {
............
//移除time out消息
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
// Need to re-evaluate whether the app still needs to be in the foreground.
for (int i=r.app.executingServices.size()-1; i>=0; i--) {
if (r.app.executingServices.valueAt(i).executeFg) {
//有一個(gè)Service是前臺(tái)服務(wù),則app仍是前臺(tái)的
r.app.execServicesFg = true;
break;
}
}
}
if (inDestroying) {
.......
mDestroyingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app);
}
r.executeFg = false;
if (r.tracker != null) {
//更新ServiceRecord的ServiceState
r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
if (finishing) {
r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
if (finishing) {
//若Service結(jié)束,將其從進(jìn)程對應(yīng)的記錄信息中移除
if (r.app != null && !r.app.persistent) {
r.app.services.remove(r);
.............
}
r.app = null;
}
}
}
主要進(jìn)行對ServiceRecord的收尾工作