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 IActivityManagerSingleton =
new Singleton() {
@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
在注释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 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,直接创建服务即可。
参考:
startService源码分析