最近在看關於插件化的知識,遇到了如何實現Service
插件化的問題,所以,先學習一下Service
內部的實現原理,這裏面會涉及到應用進程和ActivityManagerService
的通訊,建議你們先閱讀一下以前的這篇文章 Framework 源碼解析知識梳理(1) - 應用進程與 AMS 的通訊實現,整個Service
的啓動過程離不開和AMS
的通訊,從整個宏觀上來看,它的模型以下,是否是和咱們以前分析的通訊過程如出一轍: java
當咱們在Activity/Service/Application
中,經過下面這個方法啓動Service
時:緩存
public ComponentName startService(Intent service)
複製代碼
與以前分析過的不少源碼相似,最終會調用到ContextImpl
的同名方法當中,而該方法又會調用內部的startServiceCommon(Intent, UserHandle)
: bash
Intent
的合法性,對於Android 5.0
之後,咱們要求Intent
中須要制定Package
和Component
中至少一個,不然會拋出異常。Binder
通訊調用到ActivityManagerService
的對應方法,關於調用的詳細過程能夠參考 Framework 源碼解析知識梳理(1) - 應用進程與 AMS 的通訊實現 中對於應用進程到ActivityManagerService
的通訊部分分析。ActivityManagerService
中的實現爲: 數據結構
mServices
變量來去實現
Service
的啓動,而
mServices
的類型爲
ActiveServices
,它是
ActivityManagerService
中負責處理
Service
相關業務的類,不管咱們是經過
start
仍是
bind
方式啓動的
Service
,都是經過它來實現的,它也被稱爲「應用服務」的管理類。
從經過ActiveServices
調用startServiceLocked
,到Service
真正被啓動的過程以下圖所示,下面,咱們就來一一分析每個階段究竟作了什麼: app
咱們首先來看入口函數startServiceLocked
的內部實現:ide
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
final boolean callerFg;
//caller是調用者進程在AMS的遠程代理對象,類型爲ApplicationThreadProxy。
if (caller != null) {
//得到調用者的進程信息。
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
//經過傳遞的信息,解析出要啓動的Service,封裝在ServiceLookupResult中。
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
//對於每一個被啓動的Service,它們在AMS端的數據結構爲ServiceRecord。
ServiceRecord r = res.record;
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
return null;
}
//判斷是否容許啓動該服務。
if (!r.startRequested) {
final long token = Binder.clearCallingIdentity();
try {
final int allowed = mAm.checkAllowBackgroundLocked(
r.appInfo.uid, r.packageName, callingPid, true);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.name.flattenToShortString()
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage);
return null;
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
//是否須要配置相應的權限。
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
if (Build.PERMISSIONS_REVIEW_REQUIRED) {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
callingUid, service, callerFg, userId)) {
return null;
}
}
//若是該Service正在等待被從新啓動,那麼移除它。
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
//給ServiceRecord添加必要的信息。
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
//其它的一些邏輯,與第一次啓動無關,就先不分析了。
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
複製代碼
簡單地來講,就是根據Intent
查找須要啓動的Service
,封裝成ServiceRecord
對象,初始化其中的關鍵變量,在這一過程當中,加入了一些必要的邏輯判斷,最終調用了startServiceInnerLocked
方法。函數
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
//...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
//...
return r.name;
}
複製代碼
這裏面的邏輯咱們先忽略掉一部分,只須要知道在正常狀況下它會去調用bringUpServiceLocked
來啓動Service
:源碼分析
private final String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting) throws TransactionTooLargeException {
//若是該Service已經啓動。
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
//若是正在等待被從新啓動,那麼什麼也不作。
if (!whileRestarting && r.restartDelay > 0) {
return null;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent);
//清除等待被從新啓動的狀態。
if (mRestartingServices.remove(r)) {
r.resetRestartCounter();
clearRestartingIfNeededLocked(r);
}
//由於咱們立刻就要啓動該Service,所以去掉它的延時屬性。
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
//若是該Service所屬的用戶沒有啓動,那麼調用 bringDownServiceLocked 方法。
if (mAm.mStartedUsers.get(r.userId) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": user " + r.userId + " is stopped";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.packageName + ": " + e);
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
//若是不是運行在獨立的進程。
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
//若是該進程已經啓動,那麼調用realStartServiceLocked方法。
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
//在Service所屬進程已經啓動的狀況下調用的方法。
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;
}
//若是該Service所對應的進程沒有啓動,那麼首先啓動該進程。
if (app == null) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
//將該ServiceRecord加入到等待的集合當中,等到新的進程啓動以後,再去啓動它。
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Applying delayed stop (in bring up): " + r);
stopServiceLocked(r);
}
}
return null;
}
複製代碼
bringUpServiceLocked
的邏輯就比較複雜了,它會根據目標Service
及其所屬進程的狀態,走向不一樣的分支:post
Service
已經啓動:sendServiceArgsLocked
Service
沒有啓動:realStartServiceLocked
startProcessLocked
,而且將ServiceRecord
加入到mPendingServices
中,等待進程啓動以後再去啓動該Service
。下面,咱們就來一塊兒分析一下這三種狀況。學習
首先來當進程已經存在,且目標Service
已經啓動時所調用的sendServiceArgsLocked
方法:
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
while (r.pendingStarts.size() > 0) {
Exception caughtException = null;
ServiceRecord.StartItem si;
try {
si = r.pendingStarts.remove(0);
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Sending arguments to: "
+ r + " " + r.intent + " args=" + si.intent);
if (si.intent == null && N > 1) {
// If somehow we got a dummy null intent in the middle,
// then skip it. DO NOT skip a null intent when it is
// the only one in the list -- this is to support the
// onStartCommand(null) case.
continue;
}
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
if (si.neededGrants != null) {
mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
si.getUriPermissionsLocked());
}
bumpServiceExecutingLocked(r, execInFg, "start");
if (!oomAdjusted) {
oomAdjusted = true;
mAm.updateOomAdjLocked(r.app);
}
int flags = 0;
if (si.deliveryCount > 1) {
flags |= Service.START_FLAG_RETRY;
}
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (TransactionTooLargeException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large: intent="
+ si.intent);
caughtException = e;
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take care of this. if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r); caughtException = e; } catch (Exception e) { Slog.w(TAG, "Unexpected exception", e); caughtException = e; } if (caughtException != null) { // Keep nesting count correct final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying); if (caughtException instanceof TransactionTooLargeException) { throw (TransactionTooLargeException)caughtException; } break; } } } 複製代碼
這裏面最關鍵的就是調用了r.app.thread
的scheduleServiceArgs
方法,它其實就是Service
所屬進程的ApplicationThread
對象在AMS
端的一個遠程代理對象,也就是ApplicationThreadProxy
,經過binder
通訊,它最終會回調到Service
所屬進程的ApplicationThread
的scheduleServiceArgs
中:
private class ApplicationThread extends ApplicationThreadNative {
public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags ,Intent args) {
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;
sendMessage(H.SERVICE_ARGS, s);
}
}
複製代碼
sendMessage
函數會經過ActivityThread
內部的mH
對象發送消息到主線程當中,mH
其實是一個Handler
的子類,在它的handleMessage
回調中,處理H.SERVICE_ARGS
這條消息:
handleServiceArgs
方法,就會從
mServices
去查找對應的
Service
,調用咱們熟悉的
onStartCommand
方法,至於
Service
對象是如何被加入到
mServices
中的,咱們在
2.2
節中進行分析。
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess();
}
int res;
if (!data.taskRemoved) {
//調用 onStartCommand 方法。
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
QueuedWork.waitToFinish();
try {
//通知AMS啓動完成。
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {
// nothing to do.
}
ensureJitEnabled();
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}
複製代碼
這裏面,咱們會取得onStartCommand
的返回值,再經過Binder
將該返回值傳回到AMS
端,在AMS
的mServices
的serviceDoneExecutingLocked
中,會根據該返回值來修改ServiceRecord
的屬性,這也就是咱們常說的onStartCommand
方法的返回值,會影響到該Services
以後的一些行爲的緣由,關於這些返回值之間的差異,能夠查看Service.java
的註釋,也能夠查看網上的一些教程:
下面,咱們來看Service
沒有啓動的狀況,這裏會調用realStartServiceLocked
方法:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
if (DEBUG_MU)
Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
+ ", ProcessRecord.uid = " + app.uid);
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
//更新Service所在進程的oom_adj值。
mAm.updateLruProcessLocked(app, false, null);
mAm.updateOomAdjLocked();
boolean created = false;
try {
if (LOG_SERVICE_START_STOP) {
String nameTerm;
int lastPeriod = r.shortName.lastIndexOf('.');
nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
EventLogTags.writeAmCreateService(
r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
}
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//通知應用端建立Service對象。
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
if (!created) {
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
if (newService) {
app.services.remove(r);
r.app = null;
}
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
//這裏面會遍歷 ServiceRecord.bindings 列表,由於咱們這裏是用startService方式啓動的,所以該列表爲空,什麼也不會調用。
requestServiceBindingsLocked(r, execInFg);
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));
}
//這個在第一種狀況中分析過了,會調用 onStartCommand 方法。
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
// Oh and hey we've already been asked to stop! r.delayedStop = false; if (r.startRequested) { if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Applying delayed stop (from start): " + r); stopServiceLocked(r); } } } 複製代碼
這段邏輯,有三個地方須要注意:
app.thread.scheduleCreateService
:經過這裏會在應用進程建立Service
對象requestServiceBindingsLocked
:若是是經過bindService
方式啓動的,那麼會去調用它的onBind
方法。sendServiceArgsLocked
:正如2.1
節中所分析,這裏最終會觸發應用進程的Service
的onStartCommand
方法被調用。第二點因爲咱們今天分析的是startService
的方式,因此不用在乎,而第三點咱們以前已經分析過了。因此咱們主要關注app.thread.scheduleCreateService
這一句,和2.1
中的過程相似,它會回調到H
中的下面這個消息處理分支當中:
handleCreateService
的處理邏輯以下圖所示:
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//根據Service的名字,動態的加載該Service類。
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
//1.建立ContextImpl對象。
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//2.將 Service 做爲它的成員變量 mOuterContext 。
context.setOuterContext(service);
//3.建立Application對象,若是已經建立那麼直接返回,不然先調用Application的onCreate方法。
Application app = packageInfo.makeApplication(false, mInstrumentation);
//4.調用attach方法,將ContextImpl做爲它的成員變量mBase。
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//5.調用Service的onCreate方法。
service.onCreate();
//6.將該Service對象緩存起來。
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
複製代碼
以上的邏輯分爲如下幾個部分:
Service
的名字,經過ClassLoader
加載該類,並生成一個Service
實例。ContextImpl
對象,並將第一步中建立的Service
實例做爲它的mOuterContext
變量。Application
對象,這裏會先判斷當前進程所對應的Application
對象是否已經建立,若是已經建立,那麼就直接返回,不然會先建立它,並依次調用它的attachBaseContext(Context context)
和onCreate()
方法。Service
的attach
方法,初始化成員變量。
Service
的onCreate()
方法。Service
經過token
做爲key
,緩存在mServices
列表當中,以後Service
生命週期的回調,都依賴於該列表。在這種狀況下,Service
天然也不會存在,咱們會走到mAm.startProcessLocked
的邏輯,這裏會去啓動Service
所在的進程,它到底是怎麼啓動的咱們先不去細看,只須要知道它是這個目的就能夠了,此外,還須要注意的是它將該ServiceRecord
加入到了mPendingServices
中。
對於Service
所在的進程,它的入口函數爲ActivityThread
的main()
方法,在main
方法中,會建立一個ApplicationThread
對象,並調用它的attach
方法:
attach
方法中,會調用到
AMS
的
attachApplication
方法:
attachApplication
方法中,又會去調用內部的
attachApplicationLocked
:
mServices
對象:
ActiveServices
中的該方法中,就會去遍歷前面談到的
mPendingServices
列表,再依次調用
realStartServiceLocked
方法,至於這個方法作了什麼,你們能夠回到前面的
2.2
節去看,這裏就再也不重複分析了。
以上就是startService
的整個流程,bindService
也是相似一個調用過程,其過程並不複雜,本質上仍是 Framework 源碼解析知識梳理(1) - 應用進程與 AMS 的通訊實現 所談到的通訊過程,咱們所須要學習的是AMS
端和Service
所在的應用進程對於Service
是如何管理的。
系統當中的全部Service
都是經過AMS
的mServices
變量,也就是ActiveServices
類來進行管理的,而且每個應用進程中的Service
都會在AMS
端會對應一個ServiceRecord
對象,ServiceRecord
中維護了應用進程中的Service
對象所須要的狀態信息。
而且,不管咱們調用多少次startService
方法,在應用進程側都會只存在一個Service
的實例,它被存儲到ActivityThread
的ArrayMap
類型的mServices
變量當中。