startService過程原始碼分析
startService過程原始碼分析
一、簡介
Service是Android四大元件之一,service有兩種使用方式分別是startService和bindService,startService方式啟動service之後我們無法控制service,即使呼叫service的元件死亡也不會導致啟動的service死亡。startService方式啟動service後至service死亡鎖經歷的生命週期如下:oncreate—>onstartcommon—>ondestory。本篇文章會分析startService過程原始碼,下篇文章會分析bindService過程原始碼。
二、原始碼分析
我們一般是呼叫ContextWrapper的startService,然後它又呼叫mBase.startService,此處mBase是一個ContextImpl物件。在ContextImpl類的startService方法中又呼叫了startServiceCommon
//android.content.ContextWrapper @Override public ComponentName startService(Intent service) { return mBase.startService(service); } //ContextImpl.java public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, false, mUser); }
startServiceCommon如下所示:
private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) { try { validateServiceIntent(service); service.prepareToLeaveProcess(this); //1呼叫了AMS的startService方法 ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( getContentResolver()), requireForeground, getOpPackageName(), user.getIdentifier()); return cn; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
在註釋1處通過ActivityManager.getService()獲取AMS的本地代理,然後通過該代理呼叫AMS的startService方法。
下面是獲取ActivityManager.getService()獲取AMS的本地代理的流程,可以看出是通過這是一個單例模式。獲取AMS的方式是通過ServiceManager.getService來獲取一個AMS的binder代理,然後轉化為一個IActivityManager返回。因為AMS和呼叫client在不同程序所以返回的am是一個遠端binder代理。
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
//IActivityManager.java
private static class Proxy implements android.app.IActivityManager
{
@Override public android.content.ComponentName startService(android.app.IApplicationThread caller, android.content.Intent service, java.lang.String resolvedType, boolean requireForeground, java.lang.String callingPackage, int userId) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.content.ComponentName _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((caller!=null))?(caller.asBinder()):(null)));s
if ((service!=null)) {
_data.writeInt(1);
service.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
_data.writeString(resolvedType);
_data.writeInt(((requireForeground)?(1):(0)));
_data.writeString(callingPackage);
_data.writeInt(userId);
mRemote.transact(Stub.TRANSACTION_startService, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.content.ComponentName.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
AMS的startService方法如下所示:
//ActivityManagerService.java
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) {
//1獲取呼叫者的pid和uid
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
//2、呼叫ActiveServices的startServiceLocked方法
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
AMS的startService方法在註釋1處獲取呼叫者的pid和uid,然後在註釋2處呼叫ActiveServices的startServiceLocked方法並傳入在註釋1處獲取呼叫者的pid和uid。
ActiveServices的startServiceLocked方法如下所示:
//ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
//1、獲取呼叫程序ProcessRecord,如果為null則丟擲異常
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + callingPid
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
}
//2、通過retrieveServiceLocked解析啟動service的intent,並將解析結果放在res.record中
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
//解析的serviceRecord為null且permission不為null則判斷返回缺少許可權
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record;
//3、呼叫startServiceInnerLocked
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
在註釋1處獲取呼叫程序的ProcessRecord,如果為null則丟擲異常,在註釋2處呼叫retrieveServiceLocked解析啟動service的intent,解析結果包含serviceRecord和啟動該service所需許可權,在註釋3處呼叫startServiceInnerLocked。
startServiceInnerLocked如下所示:
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
//1、呼叫bringUpServiceLocked,注意bringUpServiceLocked函式如果返回非null則表示啟動出錯。
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
}
在bringUpServiceLocked中我們來分析service與呼叫者不在同一程序且service所在程序尚未啟動的情況,這是最複雜的情況了。此時會呼叫startProcessLocked啟動
service程序。
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//1、如果service所在程序和主執行緒均為非空那麼表示該service已經存在了,直接呼叫其onStartCommand方法
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
//...
ProcessRecord app;
if (!isolated) {
//2、service所在程序已經啟動則直接呼叫realStartServiceLocked啟動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.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
}
if (app == null && !permissionsReviewRequired) {
//3、service與呼叫者不在同一程序且service所在程序尚未啟動則呼叫startProcessLocked啟動service程序
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, 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;
}
//4、service所在程序還未啟動,將先將這個serviceRecord儲存到mPendingServices中表示等待啟動的service
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
}
}
在註釋1處會先判斷service是否已經啟動過,如果啟動過則直接呼叫其onStartCommand方法,在註釋2處判斷service所在程序是否啟動,如果程序啟動但是service尚未啟動那麼會呼叫realStartServiceLocked啟動service。在註釋3處則是service所在程序未啟動那麼會先啟動service程序,因為程序啟動是非同步的所以在註釋4處會先把service存放到mPendingServices中表示等待啟動的service。
下面我們先來看下service所在程序未啟動的情況,該情況是呼叫startProcessLocked,如下所示:
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
//呼叫startProcessLocked
return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
//呼叫startProcessLocked
startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
}
經過呼叫最終是通過startProcessLocked來啟動新的程序
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
if (entryPoint == null) entryPoint = “android.app.ActivityThread”;
//1、Process.start建立新的程序
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
建立程序過程之前在Android應用程序啟動分析一文中說過,詳細過程請參考 Android應用程序啟動過程.md
建立完新程序之後會呼叫android.app.ActivityThread的main函式,在Android程式中每個程序都有自己的android.app.ActivityThread。至此下面的這些操作都是在新啟動的程序中,呼叫者所在程序已完成它的命令返回了。
//ActivityThread.java
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
//1、看下attach
thread.attach(false);
Looper.loop();
}
private void attach(boolean system) {
final IActivityManager mgr = ActivityManager.getService();
try {
//1、呼叫了AMS的attachApplication
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
在ActivityThread的main函式中會呼叫attach函式,而attach又呼叫了AMS的attachApplication。
AMS的attachApplication函式如下所示:
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
//1、呼叫attachApplicationLocked
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
在註釋1處呼叫attachApplicationLocked,如下所示:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find any services that should be running in this process…
if (!badApp) {
try {
//1、呼叫ActiveServices的attachApplicationLocked檢視是否有需要啟動的service
didSomething |= mServices.attachApplicationLocked(app, processName);
checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
badApp = true;
}
}
}
attachApplicationLocked中我們只關注跟service啟動有關的內容,就是代用attachApplicationLocked檢視是否有需要啟動的service
ActiveServices的attachApplicationLocked如下所示:
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
// Collect any services that are waiting for this process to come up.
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
//1、mPendingServices中儲存了需要在該程序啟動的service,這裡依次取出並啟動
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
mPendingServices.remove(i);
i--;
proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
mAm.mProcessStats);
//2、呼叫realStartServiceLocked啟動service
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
if (!isServiceNeededLocked(sr, false, false)) {
// We were waiting for this service to start, but it is actually no
// longer needed. This could happen because bringDownServiceIfNeeded
// won't bring down a service that is pending... so now the pending
// is done, so let's drop it.
bringDownServiceLocked(sr);
}
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting service "
+ sr.shortName, e);
throw e;
}
}
}
在註釋1處取出要啟動的service並在註釋2處呼叫realStartServiceLocked啟動service
realStartServiceLocked如下所示:
private final void realStartServiceLocked(ServiceRecord r,ProcessRecord app, boolean execInFg) throws RemoteException {
//1、傳送delay訊息
bumpServiceExecutingLocked(r, execInFg, "create");
...
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.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//2、呼叫ApplicationThread的scheduleCreateService方法
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
...
//3、service已經start,呼叫service的onStartCommand
sendServiceArgsLocked(r, execInFg, true);
}
}
在註釋1處會發送一個延遲處理的訊息SERVICE_TIMEOUT_MSG。在方法scheduleCreateService執行完成,也就是onCreate回撥執行完成之後,便會remove掉該訊息。但是如果沒能在延時時間之內remove該訊息,則會進入執行service timeout流程。註釋2處scheduleCreateService會建立service並回調其onCreate生命週期函式。在註釋3處則回撥用service的onStartCommand。
先來看下bumpServiceExecutingLocked,如下所示
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executeFg = fg;
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
if (r.app != null) {
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
if (r.app.executingServices.size() == 1) {
//後臺啟動的服務
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
//前臺啟動的服務
scheduleServiceTimeoutLocked(r.app);
}
}
呼叫scheduleServiceTimeoutLocked,如下所示:
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
//傳送延遲訊息SERVICE_TIMEOUT_MSG
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
scheduleServiceTimeoutLocked主要任務是傳送延遲訊息SERVICE_TIMEOUT_MSG,針對前後臺service延遲時間會有所不同:
- 對於前臺服務,則超時為SERVICE_TIMEOUT,即timeout=20s;
- 對於後臺服務,則超時為SERVICE_BACKGROUND_TIMEOUT,即timeout=200s;
延遲訊息傳送後就會呼叫scheduleCreateService建立service,scheduleCreateService如下所示
//ApplicationThread.java
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;
//給H傳送了一個message
sendMessage(H.CREATE_SERVICE, s);
}
//ActivityThread.java
H是ActivityThread的一個內部類,繼承自Handler
public void handleMessage(Message msg) {
switch (msg.what) {
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, (“serviceCreate: " + String.valueOf(msg.obj)));
//1、H接收到CREATE_SERVICE的message之後呼叫handleCreateService
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
scheduleCreateService通過handler傳送了一個CREATE_SERVICE的message,H類收到該訊息後會呼叫handleCreateService進行處理,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.
//當應用處於後臺即將進行GC,而此時被調回到活動狀態,則跳過本次gc
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//1、呼叫ClassLoader建立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);
//建立ContextImpl物件
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//如果Application不存在則建立Application物件
Application app = packageInfo.makeApplication(false, mInstrumentation);
//2、回撥service.attach
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//3、回撥onCreate()
service.onCreate();
mServices.put(data.token, service);
try {
//4、
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
可以看出handleCreateService是真正建立service的地方。在註釋1處通過反射生成service例項在註釋2處呼叫attach,在註釋3處回撥onCreate。在註釋4處呼叫AMS的serviceDoneExecuting方法取消之前傳送service啟動超時的延遲訊息。
之後便是onStartCommand方法的回撥,上面我們在AS的realStartServiceLocked函式中註釋3處呼叫了sendServiceArgsLocked,sendServiceArgsLocked如下所示:
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
...
try {
//呼叫ApplicationThread的scheduleServiceArgs
r.app.thread.scheduleServiceArgs(r, slice);
}
}
ApplicationThread的scheduleServiceArgs如下所示:
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List<ServiceStartArgs> list = args.getList();
for (int i = 0; i < list.size(); i++) {
ServiceStartArgs ssa = list.get(i);
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = ssa.taskRemoved;
s.startId = ssa.startId;
s.flags = ssa.flags;
s.args = ssa.args;
//1、傳送SERVICE_ARGS訊息
sendMessage(H.SERVICE_ARGS, s);
}
}
在註釋1處傳送SERVICE_ARGS訊息,該訊息是在handleServiceArgs函式中處理的,如下所示:
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) {
//呼叫service的onStartCommand
res = s.onStartCommand(data.args, data.flags, data.startId);
}
}
至此service啟動完畢。
啟動流程:
- Process A程序採用Binder IPC向system_server程序發起startService請求;
- system_server程序接收到請求後,向zygote程序傳送建立程序的請求;
- zygote程序fork出新的子程序Remote Service程序;
- Remote Service程序,通過Binder IPC向sytem_server程序發起attachApplication請求;
- system_server程序在收到請求後,進行一系列準備工作後,再通過binder IPC向remote Service程序傳送scheduleCreateService請求;
- Remote Service程序的binder執行緒在收到請求後,通過handler向主執行緒傳送CREATE_SERVICE訊息;
- 主執行緒在收到Message後,通過發射機制建立目標Service,並回調Service.onCreate()方法。
到此,服務便正式啟動完成。當建立的是本地服務或者服務所屬程序已建立時,則無需經過上述步驟2、3,直接建立服務即可。