启动Service分为两种方式,分别是start方式和bind方式。
start方式对应的是Service由Context.startService(Intent service)方法来启动,从创建到销毁经历的生命周期方法是onCreate、onStartCommand、onDestory。已经在后台运行的Service,如果外界调用Context.stopService(Intent service)方法或者Service自己调用stopSelf()方法,Service会执行onDestory生命周期方法,然后结束运行。start状态的Service与Activity相互独立,即使Activity销毁,Service还是会存在。每次start方式启动Service,其onStartCommand方法均会被调用。
bind方式对应的是Service由Context.bindService(Intent service, ServiceConnection conn, int flags)方法来启动,从创建到销毁经历的生命周期方法是onCreate、onBind、onUnbind、onDestory。bind状态的Service与Activity相互关联,可以认为Service与Activity的生命周期绑定。多次bind启动同一个Service,其onBind方法只会被调用一次。bind启动的Service,可以调用Context.unbindService(ServiceConnection conn)方法来解除绑定,Activity销毁的时候也会自动与bind状态的Service解除绑定。当Service上的所有绑定都解除后,Service会被销毁。
注意:Service的周期方法中不管是多次start还是多次bind启动,onCreate方法只会调用一次。Service不同状态的启动方法和销毁方法是对应的,假如用start方式启动,调用unbind是没有效果的,只有调用对用的stop方法才可以销毁Service;反之同理。
简单来说,start状态和bind状态的区别有4点:
a. 启动方式不同
b. 生命周期阶段不同
c. 销毁方式不同。
d. 交互不同,以start方式启动的Service,组件与Service是无法交互的。以bind方式启动的Service,组件可以与Service进行交互。
Service可以以start方式和bind方式混合启动,如果一个Service通过start方式和bind方式启动,想要停止这个Service的话,它的stopService和unbindService都要调用,调用顺序没有关系,只调用一个是无法停止Service的。还要注意一点,多次startService只要一次stopService就可以了,但是如果多次bindService就需要多次unBindService,或者与Service绑定的组件结束其生命周期。
下面按照start方式和bind方式来分别介绍Service的启动过程。
start方式启动
不管是start方式还是bind方式,启动一个Service都是通过ContextWrapper的方法来的,例如:
# android.content.ContextWrapper
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
其实最终它还是通过mBase来启动,这是典型的桥接模式。Application、Activity、Service在对象创建完毕之后第一件事就是调用他们自身的attach方法,在attach方法中又会调用attachBaseContext方法,进而对mBase进行赋值。这个mBase实际上就是ContextImpl对象,ContextImpl的创建过程在Activity启动过程之生命周期方法回调分析中也有介绍。
我们直接看一下ContextImpl的startService方法,这个方法后面调用了startServiceCommon方法。而startServiceCommon中通过ActivityManagerNative的getDefault对象去startService。相信看过Activity启动过程分析这篇文章的应该很明白,ActivityManagerNative.getDefault()获取的是ActivityManagerService在本地进程的一个代理对象,通过Binder机制,进行一次IPC过程调用到ActivityManagerService的startService方法。
# android.app.ContextImpl
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), 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());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
ActivityManagerNative相关内容我们就不多做介绍了,直接看一下ActivityManagerService的startService方法。在该方法中又会调用mServices的startServiceLocked方法,这个mServices是ActiveServices类型,用来是辅助AMS对Service进行启动管理的。
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
...
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
ActiveServices的startServiceLocked中会对所要启动的Service进行检查,包括其它一些安全方面的校验。如果所有的检查都通过,就会调用ActiveServices自身的startServiceInnerLocked方法。
# com.android.server.am.ActiveServices
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
// 对所要启动的Service进行检查
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");
}
...
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
在ActiveServices的startServiceInnerLocked中,会继续调用bringUpServiceLocked方法。
# com.android.server.am.ActiveServices
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
...
return r.name;
}
在ActiveServices的startServiceInnerLocked中,如注释1处,首先判断当前的Service是否已经启动过,如果已经启动多的话会通过一个IPC过程调用ApplicationThread的scheduleServiceArgs,然后通过Hander的切换调用到ActivityThread的handleServiceArgs方法,进而调用Service的onStartCommand方法。这里我们先不细说了,继续分析Service的启动过程。
在这个方法中还是根据当前启动的Service是否需要一个独立的进程,如果不需要独立的进程并且当前的进程已经存在的话就会调用realStartServiceLocked。如果进程不存在话还会先创建一个进程,进程的创建是通过ActivityManagerService的startProcessLocked方法来进行的。
# com.android.server.am.ActiveServices
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//Slog.i(TAG, "Bring up service:");
//r.dump(" ");
// 1 判断当前的Service是否已经启动过
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && r.restartDelay > 0) {
// If waiting for a restart, then do nothing.
return null;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent);
// We are now bringing the service up, so no longer in the
// restarting state.
if (mRestartingServices.remove(r)) {
r.resetRestartCounter();
clearRestartingIfNeededLocked(r);
}
// Make sure this service is no longer considered delayed, we are starting it now.
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;
}
// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
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;
}
// Service is now being launched, its package can't be stopped.
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);
}
// 2 判断是否需要独立的进程
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);
if (app != null && app.thread != null) {
try {
// 3 进程存在,
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.
}
} else {
// If this service runs in an isolated process, then each time
// we call startProcessLocked() we will get a new isolated
// process, starting another process if we are currently waiting
// for a previous process to come up. To deal with this, we store
// in the service any current isolated process it is running in or
// waiting to have come up.
app = r.isolatedProc;
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
// 4 进程不存在,需要创建进程
if (app == null && !permissionsReviewRequired) {
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;
}
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
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 (in bring up): " + r);
stopServiceLocked(r);
}
}
return null;
}
我们假设进程已经存在,现在开始分析ActiveServices的realStartServiceLocked方法,看名字也能猜到,在这里是真的要启动一个Service了。在该方法中有一段代码app.thread.scheduleCreateService
,app.thread 表示的就是IApplicationThread在本地的一个代理,这个方法通过一个IPC过程会调用到ApplicationThread的scheduleCreateService方法。
# com.android.server.am.ActiveServices
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");
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.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
// 1 通过IPC过程创建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) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
// Cleanup.
if (newService) {
app.services.remove(r);
r.app = null;
}
// Retry.
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
// 2 在该方法中会通过IPC过程调动Service的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);
}
}
}
我们来看一下,ApplicationThread的scheduleCreateService方法,其实ApplicationThread的中的方法都像套路一样,均会发送一个消息,然后进入ActivityThread的内部类H的handleMessage方法中。这个传递的参数对象是一个CreateServiceData,就是一个JavaBean对象,封装了IBinder、ServiceInfo、CompatibilityInfo,可以看到这里面传递的也是一个IBinder的token,这个token就是用于识别这个对应的Service。AMS那边实际上存的也是这个token。
# andorid.app.ActivityThread$ApplicationThread
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);
}
在Handler中又会调用ActivityThread的handleCreateService方法。
# andorid.app.ActivityThread$H
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
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;
}
...
}
在ActivityThread的handleCreateService方法中,做的事情清晰明了,其实与Activity的创建过程类似,可以查看Activity启动过程之生命周期方法回调分析。
- 通过getPackageInfoNoCheck方法获取LoadedApk对象
- 通过LoadedApk中的ClassLoader对象创建Service对象,对于一个已经安装的Apk来讲,这个ClassLoader一般指的就是PathClassLoader。
- 创建ContextImpl对象
- 调用LoadedApk的makeApplication创建Application对象,一个LoadedApk只会对应一个Application,如果已经存在的话直接返回该对象。
- 调用attach方法,绑定一些必须的参数,注意这个context就是ContextImpl对象,也就是我们之前讲的在ContextWrapper中获取的mBase对象就是它
- 调用Service的onCreate方法
- mServices.put(data.token, service),用于缓存一个App进程中已经创建的Service
- 通过IPC调用AMS的serviceDoneExecuting方法,这个传递的type是SERVICE_DONE_EXECUTING_ANON类型,实际上在AMS那边是没有做处理的。这里我们暂时不分析它。
# andorid.app.ActivityThread
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();
// 1 获取LoadedApk对象
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
// 2 创建Service对象
try {
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);
// 3 创建ContextImpl对象,
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
//4 调用LoadedApk的makeApplication创建Application对象,一个LoadedApk只会对应一个Application
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 5 调用attach方法,绑定一些必须的参数,注意这个context就是ContextImpl对象,也就是我们之前讲的在ContextWrapper中获取的mBase对象就是它
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
// 6 调用Service的onCreate方法
service.onCreate();
// 7 存储起来
mServices.put(data.token, service);
// 8 通过IPC调用AMS的serviceDoneExecuting方法
try {
ActivityManagerNative.getDefault().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);
}
}
}
这个方法执行完毕之后,这次IPC过程就结束了。但是AMS那边的方法还没有执行完毕呢?
我们接着分析realStartServiceLocked方法。
在这个方法中实际上还会尝试通过requestServiceBindingsLocked进而来调用bindService的方法,不过因为我们是以start方式启动的,因此ServiceRecord中是没有bind意图的,因此也不会调用bind方法,这里我们就不分析它了,留到在bind方式启动的时候再来看它。
在方法中还会调用sendServiceArgsLocked方法,该方法中会通过IPC过程调动Service的onStartCommand方法,还记得我们之前说过吗,如果Service已经创建的话实际上ActiveServices就是会直接调用sendServiceArgsLocked这个方法。
# com.android.server.am.ActiveServices
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
// 1 通过IPC过程创建Service
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
...
} finally {
...
}
...
// 2 请求调用bindService
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null));
}
// 3 在该方法中会通过IPC过程调动Service的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);
}
}
}
我们来看一下ActiveServices的sendServiceArgsLocked方法,在该方法中会调用r.app.thread.scheduleServiceArgs方法,这是一个IPC过程,调用ApplicationThread的 scheduleServiceArgs方法。
# com.android.server.am.ActiveServices
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 = null;
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;
}
// 1 通过IPC调用ApplicationThread的 scheduleServiceArgs方法
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
...
} catch (Exception e) {
...
}
...
}
}
# andorid.app.ActivityThread$ApplicationThread
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);
}
# andorid.app.ActivityThread$H
public void handleMessage(Message msg) {
...
switch (msg.what) {
case SERVICE_ARGS:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceStart: " + String.valueOf(msg.obj)));
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
...
}
我们来看一下ActivityThread的handleServiceArgs方法,该方法比较简单
- 就是首先通过token从mServices中获取对应的Service
- 给Intent设置extrasClassLoader,主要是为了反序列化Intent中携带的一个Parcelable类型的对象
- 调用Service的onStartCommand方法,获取其返回值
- 通过IPC告知AMS调用结果,注意这个时候把onStartCommand的返回值传递过去了,结果类型type为SERVICE_DONE_EXECUTING_START。
private void handleServiceArgs(ServiceArgsData data) {
// 1 获取Service
Service s = mServices.get(data.token);
if (s != null) {
try {
// 2. 给Intent设置extrasClassLoader,主要是为了反序列化Intent中携带的一个Parcelable类型的对象
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess();
}
int res;
// 3 调用Service的onStartCommand方法
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
QueuedWork.waitToFinish();
// 4 通过IPC告知AMS调用结果,注意这个时候把onStartCommand的返回值传递过去了
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
ensureJitEnabled();
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}
看一下ActivityManagerService的serviceDoneExecuting方法,其实也就是做了一下中转,中间做了一下校验,要保证客户端传递来的token是正确的类型。之后会调用ActiveServices的serviceDoneExecutingLocked方法。
# com.android.server.am.ActivityManagerService
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
在 serviceDoneExecutingLocked方法中会根据传递过来的type,来进行对应的处理,此时传递的是SERVICE_DONE_EXECUTING_START,然后就会根据对应的res来进行处理。正常情况下这个res就是Service的onStartCommand的返回值。
# com.android.server.am.ActiveServices
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
// This is a call from a service start... take care of
// book-keeping.
r.callStart = true;
switch (res) {
case Service.START_STICKY_COMPATIBILITY:
case Service.START_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, true);
// Don't stop if killed.
r.stopIfKilled = false;
break;
}
case Service.START_NOT_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, true);
if (r.getLastStartId() == startId) {
// There is no more work, and this service
// doesn't want to hang around if killed.
r.stopIfKilled = true;
}
break;
}
case Service.START_REDELIVER_INTENT: {
// We'll keep this item until they explicitly
// call stop for it, but keep track of the fact
// that it was delivered.
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
si.deliveryCount = 0;
si.doneExecutingCount++;
// Don't stop if killed.
r.stopIfKilled = true;
}
break;
}
case Service.START_TASK_REMOVED_COMPLETE: {
// Special processing for onTaskRemoved(). Don't
// impact normal onStartCommand() processing.
r.findDeliveredStart(startId, true);
break;
}
default:
throw new IllegalArgumentException(
"Unknown service start result: " + res);
}
if (res == Service.START_STICKY_COMPATIBILITY) {
r.callStart = false;
}
} else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
// This is the final call from destroying the service... we should
// actually be getting rid of the service at this point. Do some
// validation of its state, and ensure it will be fully removed.
if (!inDestroying) {
// Not sure what else to do with this... if it is not actually in the
// destroying list, we don't need to make sure to remove it from it.
// If the app is null, then it was probably removed because the process died,
// otherwise wtf
if (r.app != null) {
Slog.w(TAG, "Service done with onDestroy, but not inDestroying: "
+ r + ", app=" + r.app);
}
} else if (r.executeNesting != 1) {
Slog.w(TAG, "Service done with onDestroy, but executeNesting="
+ r.executeNesting + ": " + r);
// Fake it to keep from ANR due to orphaned entry.
r.executeNesting = 1;
}
}
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
Binder.restoreCallingIdentity(origId);
} else {
Slog.w(TAG, "Done executing unknown service from pid "
+ Binder.getCallingPid());
}
}
onStartCommand方法的返回值是int型,返回值有4种。
START_STICKY_COMPATIBILITY = 0,这个是START_STICKY的兼容版本,被杀死后重启并不保证一定调用onStartCommand方法。这个一般是在android系统小于5 的时候使用。
START_STICKY = 1,当Service已经启动后,如果onStartCommand方法返回值是这个,表示的是如果因内存不足Service被系统杀掉,系统会在后续内存空闲时尝试着重新创建这个Service,但是不会再传递上次启动Service的Intent,onStartCommand中的Intent参数会为null。
START_NOT_STICKY = 2,系统把Service杀死后,不会尝试重新创建这个Service。
START_REDELIVER_INTENT = 3,系统把Service杀死后,会尝试重新创建这个Service,并且会把之前启动Service的最后一个Intent重新传递回来。
到此,我们就分析完Service的start方式启动的过程了。我们小结一下
小结
startService启动Service调用的是ContextImpl的startService方法,在ContextImpl中通过一个IPC过程调用到AMS端的startService方法,AMS再去委托ActiveServices去对Service的启动进行管理。ActiveServices首先回去校验Service的合法性,如果合法的话判断Service所在进程是否已经启动,如果没有启动的话会先去创建进程再来启动Service。如果Service所在进程已经启动,就会通过一个IPC过程调用ApplicationThread的scheduleCreateService方法,进而调用ActivityThread的handleCreateService方法,完成Service的创建以及绑定上下文环境并调用Service的onCreate方法。
创建Service的IPC过程结果之后,会返回ActiveServices的方法调用处接着执行方法,然后会再通过一个IPC过程来调用Service的onStartCommand方法,并且该方法结束之后会把onStartCommand的返回值告知AMS,AMS又会通知ActiveServices去进行处理。当Service因空间不足被系统杀死后,会根据不同的返回值来对Service进行相应处理。
bind方式启动Service
前面也说了,startService、bindService均是通过ContextImpl进行。直接看一下ContextImpl的bindService方法。
# android.app.ContextImpl
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
bindService方法有3个参数,第一个参数Intent,不同说就是表示启动的Service对应的意图,第2个参数ServiceConnection是一个接口用来监控bind方式启动的Service的连接状态。第3个参数是一个flag,一般传递的是Context.BIND_AUTO_CREATE。
需要说明的是,ServiceConnection的onServiceConnected会在Service的onBind方法返回IBinder对象之后调用,而其onServiceDisconnected是在Service意外挂掉,比如Service被系统杀死的时候才会被回调。
# android.content.ServiceConnection
public interface ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service);
public void onServiceDisconnected(ComponentName name);
}
ContextImpl的bindService方法会调用其bindServiceCommon方法。
# android.app.ContextImpl
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
// 1 调用LoadedApk的getServiceDispatcher方法
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
// 2 通过IPC过程调用AMS的bindService方法
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
package android.app;
import android.content.ComponentName;
oneway interface IServiceConnection {
void connected(in ComponentName name, IBinder service);
}
bindServiceCommon方法中主要完成两件事情。
首先会调用LoadedApk的getServiceDispatcher方法,该方法会创建一个IServiceConnection对象,IServiceConnection是用AIDL写的,在这里实际上就是ServiceDispatcher.InnerConnection对象。这是因为ServiceConnection必须借助Binder来让远端server回调自己的方法,但是ServiceConnection不具有跨进程通信的能力,而ServiceDispatcher.InnerConnection是一个Binder对象,刚好可以充当这个跨进程通信的角色。ServiceDispatcher在ServiceDispatcher.InnerConnection和ServiceConnection之间起着桥梁的作用。
# android.app.LoadedApk
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
上面的方法中mServices是一个ArrayMap,存储了一个应用当前活动的ServiceConnection和ServiceDispatcher的映射关系。键表示一个Context,说明每个Context对象中是可以存放一组映射关系的。
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
系统首先会搜索ServiceConnection对应 ServiceDispatcher是否存在,如果不存在的话会创建一个ServiceDispatcher对象,在ServiceDispatcher的构造方法中会创建一个InnerConnection对象并持有ServiceDispatcher的引用,而ServiceDispatcher中又持有ServiceConnection的引用,因此当服务端回调的时候可以通过InnerConnection间接的找到ServiceConnection,回调它的方法。
接着分析ContextImpl的bindServiceCommon方法,LoadedApk的getServiceDispatcher返回一个IServiceConnection对象(InnerConnection类型),接着通过一个IPC过程调用了AMS的bindService方法来完成Service的绑定过程,注意此时把IServiceConnection对象传递到了服务端,当然了,服务端拿到的实际上是IServiceConnection的代理对象。
看一下AMS的bindService方法。
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
// 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");
}
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
bindService中主要做了一些校验,接下来,AMS会调用ActiveServices的bindServiceLocked方法。bindServiceLocked方法会调用bringUpServiceLocked,bringUpServiceLocked会调用realStartServiceLocked方法,realStartServiceLocked方法和之前讲的start方式启动Service的逻辑一致,均是通过ApplicationThread来完成Service的创建并执行其onCreate方法,这里就不重复讲解了。和start方式不同的是,在realStartServiceLocked方法中,当执行完app.thread.scheduleCreateService
过程,完成Service的创建和onCreate方法回调之后,还会接着调用ActiveServices的requestServiceBindingsLocked方法。
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can't yet bind.
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
// Keep the executeNesting count accurate.
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
throw e;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
return false;
}
}
return true;
}
Service有一个特性,同一个ServiceConnection多次绑定一个Service,Service的onBind方法只会被调用一次。一个ServiceConnection对应AMS端的一个IntentBindRecord。在上面的代码中也可以看出,对于同一个IntentBindRecord只会调用onBind一次。
在ActiveServices的bindServiceLocked方法中会调用ServiceRecord的retrieveAppBindingLocked方法,在这里会用一个Map集合bindings存放bind信息。Intent.FilterComparison是键,它实际上包裹了一个请求Service的Intent,比较两个Intent.FilterComparison是否相等是根据Intent的filterHashCode方法,这个与Intent的mAction、mType、mType、mPackage、mComponent、mCategories有关。我们知道,5.0以上的系统,Service只能够显式启动。具体的是在ContextImpl的validateServiceIntent方法中。
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
在requestServiceBindingLocked中, r.app.thread
指的就是ApplicationThread的本地代理对象,通过一个IPC过程调用到ApplicationThread的scheduleBindService方法。
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
if (DEBUG_SERVICE)
Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
sendMessage(H.BIND_SERVICE, s);
}
这种套路我们已经分析太多了,通过Handler H来发送一个H.BIND_SERVICE消息。然后会交给ActivityThread的handleBindService方法。在该方法中首先根据token获取对应的Service,然后给Intent设置extrasClassLoader, 如果不是重新绑定,就调用Service的onBind方法,并且返回IBinder对象,并传递给AMS。如果是重新绑定,调用Service的onRebind方法。
private void handleBindService(BindServiceData data) {
// 1 根据token获取Service
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
// 2. 给Intent设置extrasClassLoader
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
// 3 如果不是重新绑定,就调用Service的onBind方法,并且返回IBinder对象,并传递给AMS
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
// 4 如果是重新绑定,直接调用Service的onRebind方法
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
当Service的onBind方法调用之后,会通过IPC过程调用AMS的publishService方法。
# com.android.server.am.ActivityManagerService
public void publishService(IBinder token, Intent intent, IBinder service) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
从上面的代码可以看出,AMS的publishService方法将具体的工作交给了ActiveServices来完成,调用了它的publishServiceLocked方法。
# com.android.server.am.ActiveServices
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
...
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
...
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
publishServiceLocked方法中看起来很多,核心点就一个地方c.conn.connected(r.name, service)
。c的类型是ConnectionRecord,c.conn返回的是IServiceConnection对象,实际上就是一个本地代理。真实的对象是ServiceDispatcher.InnerConnection。c.conn.connected
实际上就是一个IPC过程调用到ServiceDispatcher.InnerConnection的connected方法。参数中的service就是调用Service的onBind方法返回的Ibinder对象。
来看一下ServiceDispatcher.InnerConnection的定义。
# android.app.LoadedApk.ServiceDispatcher.InnerConnection
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service);
}
}
}
InnerConnection的connected方法中会调用ServiceDispatcher的connected方法。
# android.app.LoadedApk.ServiceDispatcher
public void connected(ComponentName name, IBinder service) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0));
} else {
doConnected(name, service);
}
}
mActivityThread是一个Handler,实际上就是ActivityThread的H这个Handler,是在ContextImpl的bindService方法中一路传递过来的,作为了ServiceDispatcher的成员变量。所以mActivityThread不为null,就会调用Handler的post方法来切换到主线程中。后面RunConnection的run方法会执行。注意此时传递的第三个参数为0。
看一下RunConnection。
# android.app.LoadedApk.ServiceDispatcher.RunConnection
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command) {
mName = name;
mService = service;
mCommand = command;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
}
RunConnection是ServiceDispatcher的非静态内部类,在run方法中又调用了ServiceDispatcher的doConnected方法。
# android.app.LoadedApk.ServiceDispatcher
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
// We unbound before receiving the connection; ignore
// any connection received.
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
// Huh, already have this one. Oh well!
return;
}
if (service != null) {
// A new service is being connected... set it all up.
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
// This service was dead before we got it... just
// don't do anything with it.
mActiveConnections.remove(name);
return;
}
} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// If there was an old service, it is not disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
// If there is a new service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
在ServiceDispatcher的doConnected方法最后,调用了mConnection的onServiceConnected方法,也就是调用了在bindService的时候传递的ServiceConnection的onServiceConnected方法。
到此,Service的bind启动过程也分析完毕了。
至于Service的unBind过程,会调用到ActiveServices的unbindServiceLocked方法,在该方法中又调用removeConnectionLocked方法。会去移除ServiceConnetion,当Service上所有的bind 的ServiceConnetion都移除的时候,会通过IPC调用ApplicationThread的scheduleUnbindService方法,然后调用Service的unBind方法。接下来,unbindServiceLocked中还会调用其bringDownServiceLocke方法,在该方法中调用ApplicationThread的scheduleStopService方法,进而调用Service的onDestory方法。