Service是Android另外一個常用的組件笛园,其啟動的過程與Activity有相似之處谋旦。Service的啟動過程遂蛀,我們也拆分成兩部分來介紹:ContextWrapper調用AMS的過程以及AMS調用ActivityThread啟動Service的過程匙铡。本文主要分為三部分:ContextWrapper調用AMS源碼分析、AMS調用ActivityThread啟動Service源碼分析底靠、總結√芈粒快速了解可以直接看總結苛骨。
1.ContextWrapper調用AMS
通常我們在Activity中啟動一個Service代碼類似下邊這樣:
Intent intent = new Intent("ACTION");
startService(intent);
startService方法的實現(xiàn)在ContextWrapper中:
/**
* Proxying implementation of Context that simply delegates all of its calls to
* another Context. Can be subclassed to modify behavior without changing
* the original Context.
*/
public class ContextWrapper extends Context {
@UnsupportedAppUsage
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
...
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
...
}
上面的代碼其實很簡單篱瞎,startService
方法調用后執(zhí)行了mBase.startService()
,看代碼我們很明顯的發(fā)現(xiàn)mBase
是個Context類型的。了解這個具體實現(xiàn)到底是什么痒芝,ContextWrapper如何初始化的就很重要俐筋,我們閃回到ActivityThread 啟動 Activity:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
return activity;
}
上面的代碼可以看出,傳入Activity的context是ContextImpl
严衬,attach
方法會把Activity的上下文appContext與傳入的ContextImpl
關聯(lián)起來澄者。具體看下ContextImpl appContext
的賦值的方法createBaseContextForActivity()
:
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
// For debugging purposes, if the activity's package name contains the value of
// the "debug.use-second-display" system property as a substring, then show
// its content on a secondary display if there is one.
String pkgName = SystemProperties.get("debug.second-display.pkg");
if (pkgName != null && !pkgName.isEmpty()
&& r.packageInfo.mPackageName.contains(pkgName)) {
for (int id : dm.getDisplayIds()) {
if (id != Display.DEFAULT_DISPLAY) {
Display display =
dm.getCompatibleDisplay(id, appContext.getResources());
appContext = (ContextImpl) appContext.createDisplayContext(display);
break;
}
}
}
return appContext;
}
從上面的代碼可以看出appContext是ContextImpl類型的,也就是最上面的mBase是ContextImpl類型的请琳,那我們看下ContextImpl內startService是如何實現(xiàn)的:
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
//調用AMS方法
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
} else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
上面代碼中粱挡,startService方法調用了startServiceCommon方法《砭可以看到在startServiceCommon方法中询筏,調用了AMS的代理IActivityManager的startService方法。
2.AMS調用ActivityThread啟動Service
上面介紹完了ContextWrapper啟動AMS的過程竖慧,接著上面的內容嫌套,我看下AMS的startService方法:
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
根據上面的代碼,我們看到調用了mServices的startServiceLocked
方法圾旨,mServices從上面的部分可以看到是ActiveServices類型的踱讨,那我們看下其內部又是如何實現(xiàn)startServiceLocked
方法的,這惡搞方法比較長砍的,我們關注下重點的代碼段:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
...
//查找對應的Service信息
ServiceLookupResult res =
retrieveServiceLocked(service, null, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record;
...
NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
service, callingUid, r.packageName, r.userId);
...
//ServiceRecord記錄必要的Service信息
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
if (fgRequired) {//是否需要運行在前臺
// We are now effectively running a foreground service.
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
r.lastActivity);
}
mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null,
true, false, null, false);
}
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;
if (!callerFg && !fgRequired && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.getCurProcState() > ActivityManager.PROCESS_STATE_RECEIVER) {
//如果調用不是來自于前臺的調用者痹筛,并且已經有其他后臺的Service啟動了,則延時啟動廓鞠。
// 這是為了避免很多應用都處理注冊的廣播導致進程濫發(fā)信息帚稠。
if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
+ r + " in " + proc);
if (r.delayed) {
// Service已經在延時執(zhí)行列表里了,保持Service繼續(xù)等待
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
//有其他運行的處理床佳,延時執(zhí)行Service
Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
addToStarting = true;
} else if (proc.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
// Service可以執(zhí)行
addToStarting = true;
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STARTS) {
StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.getCurProcState())
.append(' ').append(proc.adjType);
String reason = proc.makeAdjReason();
if (reason != null) {
sb.append(' ');
sb.append(reason);
}
sb.append("): ");
sb.append(r.toString());
Slog.v(TAG_SERVICE, sb.toString());
}
} else if (DEBUG_DELAYED_STARTS) {
...
}
if (allowBackgroundActivityStarts) {
r.whitelistBgActivityStartsOnServiceStart();
}
//核心賦值
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
if (!r.mAllowWhileInUsePermissionInFgs) {
r.mAllowWhileInUsePermissionInFgs =
shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, callingPid,
callingUid, service, r, allowBackgroundActivityStarts);
}
return cmp;
}
上面代碼中retrieveServiceLocked獲取與Service對應的ServiceRecord等信息翁锡。如果ServiceRecord不存在,方法內部通過PackageManagerService獲取ServiceRecord信息夕土。最后調用方法startServiceInnerLocked:
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
...
return r.name;
}
這個方法比較簡單馆衔,主要是調用了bringUpServiceLocked,我們重點看下這個方法:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
...
if (!whileRestarting && mRestartingServices.contains(r)) {
// 等待重啟不進行任何操作
return null;
}
...
// 準備拉起Service,從重啟中移除
// restarting state.
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
// 確保Service不再延時執(zhí)行怨绣,準備啟動Service
if (r.delayed) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
...
// Service已經啟動角溃, 所在Package不能停止.
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;
//獲取Service將要運行的進程名
final String procName = r.processName;
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
ProcessRecord app;
if (!isolated) {
//運行Service的進程是否存在
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, 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.shortInstanceName, e);
}
}
} else {
//如果Service在獨立的進程中運行, 每次調用startProcessLocked()方法
//都會得到一個新的獨立的進程篮撑,如果目前在等待則另外啟動一個新的進程减细。
// 為了處理這種情況,在Service內存儲當前獨立的進程是正要運行還是等待喚起赢笨。
app = r.isolatedProc;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
}
if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
r.definingUid);
}
}
//如果進程不存在則啟動進程未蝌, 把Service已經執(zhí)行的狀態(tài)存儲起來驮吱。
if (app == null && !permissionsReviewRequired) {
// TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service
// was initiated from a notification tap or not.
//啟動進程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, 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);
//記錄ServiceRecord
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
...
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;
}
核心的處理已經在上面代碼中注釋了,很明顯啟動Service的方法是realStartSeviceLocked萧吠,多余的:
/**
* Note the name of this method should not be confused with the started services concept.
* The "start" here means bring up the instance in the client, and this method is called
* from bindService() as well.
*/
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
boolean created = false;
try {
...
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//創(chuàng)建Service
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app, "Died when creating service");
throw e;
} finally {
...
}
...
}
上面代碼可以看到創(chuàng)建Service調用了scheduleCreateService方法左冬, app.thread是IApplicationThread類型的,其實現(xiàn)是ActivityThread的內部類ApplicationThread纸型。具體看下ApplicationThread的scheduleCreateService方法:
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;
sendMessage(H.CREATE_SERVICE, s);
}
這個方法其實不是很復雜拇砰,封裝即將啟動的Service信息到CreateServiceData中,然后向H類發(fā)送消息:
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
H類是ActivityThread的內部類狰腌,繼承自Handler除破,這個在Android Activity原理簡介與源碼分析一文中有介紹。這是應用程序主線程的一個消息管理類琼腔,下面我們看下H累的sendMessage方法:
public void handleMessage(Message msg) {
switch (msg.what) {
...
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
....
}
可以看到瑰枫,當消息是CREATE_SERVICE的時候,會調用handleCreateService方法:
private void handleCreateService(CreateServiceData data) {
// 如果切到后臺后準備GC了丹莲,service要激活了光坝,所以需要跳過GC
unscheduleGcIdler();
//獲取將要啟動Service的應用程序的包信息
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//獲取類加載器
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//創(chuàng)建Service實例
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
...
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
//創(chuàng)建Service上下文ContextImpl
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//獲取應用程序進程
Application app = packageInfo.makeApplication(false, mInstrumentation);
//初始化Service
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//啟動Service
service.onCreate();
//將Service加入到ActivityThread的成員變量mServices中,記錄Service
mServices.put(data.token, service);
try {
//記錄已經執(zhí)行的Service
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
...
}
}
上面就是Service最終的啟動過程圾笨。
3.總結
這里總結不做過多的文字描述直接上序列圖來總結下Service的啟動過程教馆。
3.1 ContextWrapper調用AMS
3.1 AMS調用ActivityThread啟動Service
如有意見和建議歡迎大家留言逊谋,謝謝