一. 简介
服务 (Service) 是 Android 系统中 4 大应用程序组件之一,主要用途有:后台运行和跨进程访问。通过启动服务可以在不显示界面的前提下在后台执行那些不需要和用户交互且长期运行的任务,即使程序切换到后台,或者用户打开了另一个应用程序,服务仍然能够保持独立运行。通过 AIDL 服务可以实现不同进程之间的数据通信,后面详细解析。
1 服务的形式
Service 的存在形式:本地服务、远程服务和前台服务。
本地服务:是指服务和启动服务的上下文 (如:Activity) 在同一个进程,即服务依附在应用程序主进程而不是独立的进程,由于没有启动新进程因而在一定程度上节约了系统资源,但当主进程被杀掉后,依附于其的服务都会停止运行。
远程服务:是指运行在独立的进程中的服务,由于是独立的进程,因此会占用一定的系统资源,如运行于 System_Server 进程中的系统服务,它们是常驻的,不会因应用进程被杀掉而被强制停止运行。
前台服务:是指那些被认为用户知道 (用户所认可的) 且在系统内存不足的时候不允许系统杀死的服务,用来执行一些用户能注意到的操作。前台服务必须给状态栏提供一个通知,并且放到正在运行 (Ongoing) 标题之下,即与之绑定的通知只有在这个服务被终止或从前台主动移除通知后才能被解除。
2 服务的状态
Service 的状态:启动状态和绑定状态,也可以说成是服务的两种启动方式。
启动状态:通过应用组件 (如:Activity) 调用 startService() 方法启动服务时,服务即处于“启动”状态,便可在后台无限期运行,除非手动调用 stopService() 方法才能停止服务,处于启动状态的服务通常是执行单一操作,而且不会将结果返回给调用方。
绑定状态:通过应用组件 (如:Activity) 调用 bindService() 方法绑定服务时,服务即处于“绑定”状态,绑定服务提供客户端与服务器交互的接口,通过接口可以发送请求并获取结果等,多个组件可以同时绑定到同一个服务上,但只有绑定的服务全部解绑后,该服务才会被销毁。
3 总结
通过本小节的了解,对服务的概念、存在形式、启动方式和状态有了初步的掌握,下面继续来深入学下服务 (Service) 的启动过程。
二. Service 启动
Service 有两种启动方式:startService 和 bindService,两者方式的启动过程不尽相同,接下来分开讨论,首先先看一下 startService 启动 Service 的过程。
1 startService 启动服务
首先要新建 Service 子类然后再启动,Service 子类的构建很简单,不再赘述,也不是本文的重点,先来看一下 startService 的启动入口。
public class ContextWrapper extends Context {
......
@UnsupportedAppUsage
Context mBase;
......
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
......
}
调用 ContextWrapper # startService() 方法来启动 Service,在该方法中将 Service 的启动委托给了 mBase,这里 mBase 是 ContextImpl 实例对象,ContextImpl 是抽象类 Context 的具体实现类,即调用流程委托给 ContextImpl 并调用其 startService() 方法。具体详解参见文章 深度详解 Android 之 Context。
1.1 ContextImpl # startService()
class ContextImpl extends Context {
......
@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);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
......
return cn;
}
......
}
......
}
执行流程如下:
- 调用 ContextImpl # validateServiceIntent() 方法对参数 Intent 进行合法性检查,Android 5.0 后要求 Service 必须通过显式 Intent 启动,否则会直接抛出异常。调用 Intent # prepareToLeaveProcess() 方法对 Intent 的属性进行离开应用进程前的准备工作。
- 获取继承自 IActivityManager.Stub 类的客户端实现类,即获取服务端 AMS 在本地的代理对象 BpBinder,通过代理对象的调用将启动服务的任务跨进程传给了 AMS 中(Binder 有关的知识,读者可自行查阅,笔者暂时没写)。
1.2 AMS # startService()
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {
......
final ActiveServices mServices;
......
public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
......
mServices = new ActiveServices(this);
......
}
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, 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;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
......
}
在 AMS # startService() 方法中,将启动 Service 的任务委托给 ActiveServices 来执行,并调用其 startServiceLocked() 方法,ActiveServices 类是用来辅助 AMS 来管理 Service 的核心类。
1.3 ActiveServices # startServiceLocked()
public final class ActiveServices {
......
final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();
final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();
......
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId)
throws TransactionTooLargeException {
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
callingPackage, callingFeatureId, userId, false);
}
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 {
......
final boolean callerFg;
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
......
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
ServiceLookupResult res =
retrieveServiceLocked(service, null, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false);
......
ServiceRecord r = res.record;
final boolean bgLaunch = !mAm.isUidActiveLocked(r.appInfo.uid);
boolean forcedStandby = false;
if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
......
forcedStandby = true;
}
boolean forceSilentAbort = false;
if (fgRequired) {
......
}
if (forcedStandby || (!r.startRequested && !fgRequired)) {
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
......
if (allowed == ActivityManager.APP_START_MODE_DELAYED || forceSilentAbort) {
......
return null;
}
if (forcedStandby) {
if (fgRequired) {
......
return null;
}
}
UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
......
fgRequired = false;
}
......
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
......
if (fgRequired) {
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) {
......
if (r.delayed) {
......
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
addToStarting = true;
} else if (proc.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
addToStarting = true;
......
}
}
......
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
......
return cmp;
}
......
}
参见方法中的注释,主要执行流程如下:
- 通过 ActiveServices # retrieveServiceLocked() 方法获取 ServiceRecord,其记录了 Service 的所有信息包括属于哪个进程,Service 的名称,应用包名等等,如果服务已存在则获取缓存的 ServiceRecord,否者新建然后加入到缓存中。
- 根据当前启动进程的状态值、启动条件等,设置 ServiceRecord 启动参数, 并为其 pendingStarts 中添加启动项 StartItem,然后继续调用 ActiveServices # startServiceInnerLocked() 方法来启动服务。
1.3.1 ActiveServices # retrieveServiceLocked()
public final class ActiveServices {
......
final SparseArray<ServiceMap> mServiceMap = new SparseArray<>();
final ArrayList<ServiceRecord> mPendingServices = new ArrayList<>();
......
private ServiceLookupResult retrieveServiceLocked(Intent service,
String instanceName, String resolvedType, String callingPackage,
int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
boolean allowInstant) {
ServiceRecord r = null;
......
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId,
false, getAllowMode(service, callingPackage),
"service", callingPackage);
ServiceMap smap = getServiceMapLocked(userId);
final ComponentName comp;
if (instanceName == null) {
...
}
if (comp != null) {
r = smap.mServicesByInstanceName.get(comp);
}
if (r == null && !isBindExternal && instanceName == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
}
if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
&& !callingPackage.equals(r.packageName)) {
r = null;
}
if (r == null) {
try {
int flags = ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
if (allowInstant) {
flags |= PackageManager.MATCH_INSTANT;
}
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, flags, userId, callingUid);
ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null;
......
ComponentName className = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
ComponentName name = comp != null ? comp : className;
......
if (userId > 0) {
......
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
r = smap.mServicesByInstanceName.get(name);
if (r == null && createIfNeeded) {
......
r = new ServiceRecord(mAm, ss, className, name, definingPackageName,
definingUid, filter, sInfo, callingFromFg, res);
r.mRecentCallingPackage = callingPackage;
res.setService(r);
smap.mServicesByInstanceName.put(name, r);
smap.mServicesByIntent.put(filter, r);
for (int i=mPendingServices.size()-1; i>=0; i--) {...}
}
}
......
}
if (r != null) {
if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName,
r.appInfo.uid)) {
return new ServiceLookupResult(null, msg);
}
if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
resolvedType, r.appInfo)) {
return new ServiceLookupResult(null, "blocked by firewall");
}
if (mAm.checkComponentPermission(r.permission,
callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
if (!r.exported) {
......
return new ServiceLookupResult(null, "not exported from uid "
+ r.appInfo.uid);
}
......
return new ServiceLookupResult(null, r.permission);
} else if (r.permission != null && callingPackage != null) {
final int opCode = AppOpsManager.permissionToOpCode(r.permission);
......
}
return new ServiceLookupResult(r, null);
}
return null;
}
......
}
这个方法比较长,删掉一些代码,注释也写了一些,执行流程如下:
- 根据启动服务时的入参,从 mServiceMap 缓存中获取 ServiceMap 实例,然后由 ComponentName 和 Intent.FilterComparison 从 ServiceMap 实例的两个缓存集合中获取对应的 ServiceRecord 实例。
- 如果获取不到,则先获取 PMS 内部类 PackageManagerInternalImpl,并调用其 resolveService() 方法,在该方法中会继续调用 PMS 的 resolveServiceInternal() 方法来获取 ResolveInfo 实例,主要是为了获取 ResolveInfo 实例中生成的 ServiceInfo 实例来新建 ServiceRecord 实例,然后将新建的 ServiceRecord 实例加入到 ServiceMap 实例的两个缓存集合中,如果可以获取到,则复用 ServiceRecord 实例即可。
- 最后对新建或复用的 ServiceRecord 实例进行权限校验、防火墙检测等,并将其封装到 ServiceLookupResult 实例中返回。
总结:就是查询这个启动的这个 Service 是否合法,是否完成,是否可以启动,如果可以就设置信息,组装成最终结果ServiceLookupResult 实例对象返回,如果有问题里面就抛异常或者返回 null。
AppOpsManager:Google 在 Android 4.3 里面引进的应用程序操作(权限)的管理类,核心实现类为 AppOpsService。AppOpsManager 还提供了跟踪记录的功能,以方便开发者了解系统敏感操作的访问记录。
1.3.2 ServiceRecord.StartItem 类
final class ServiceRecord extends Binder implements ComponentName.WithComponentName {
......
static class StartItem {
final ServiceRecord sr;
final boolean taskRemoved;
final int id;
final int callingId;
final Intent intent;
final NeededUriGrants neededGrants;
long deliveredTime;
int deliveryCount;
int doneExecutingCount;
UriPermissionOwner uriPermissions;
String stringName;
StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
NeededUriGrants _neededGrants, int _callingId) {
sr = _sr;
taskRemoved = _taskRemoved;
id = _id;
intent = _intent;
neededGrants = _neededGrants;
callingId = _callingId;
}
}
......
}
StartItem 是 ServiceRecord 的内部类,表示一次 startService 的动作,每调用 startService 一次,只生成一个 ServiceRecord 实例,但会生成多个 StartItem,并且每次 StartItem # id 自增 1。
新创建 ServiceRecord 实例后,会遍历 mPendingServices 去重,如果存在与新建的 ServiceRecord 实例一样的则移除掉,确保 ServiceRecord 实例只有一个。
1.4 ActiveServices # startServiceInnerLocked()
public final class ActiveServices {
......
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;
FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, r.appInfo.uid,
r.name.getPackageName(), r.name.getClassName(),
FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__START);
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
......
if (first) {
smap.rescheduleDelayedStartsLocked();
}
} else if (callerFg || r.fgRequired) {
smap.ensureNotStartingBackgroundLocked(r);
}
return r.name;
}
......
}
ServiceRecord 的成员变量 callStart 是一个 boolean 类型的标志位,该值为 true 时表示(先前运行的)Service 由于内存不足被杀死后进行自动重启 (一个典型的实例是 Service # onStartCommand() 返回 START_STICKY) ,当前待启动的 Service 是通过 startService 方式来启动一个新的服务而非自动重启先前被杀掉的服务,所以此处该值被置为 false。
ActiveServices # startServiceInnerLocked() 方法中,继续调用 ActiveServices # bringUpServiceLocked() 方法启动目标 Service,如果启动失败则抛出异常。
1.5 ActiveServices # bringUpServiceLocked()
public final class ActiveServices {
......
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && mRestartingServices.contains(r)) {
return null;
}
......
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
if (r.delayed) {
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
......
bringDownServiceLocked(r);
return msg;
}
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
}
......
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
.......
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
}
......
}
} else {
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);
}
}
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (r.fgRequired) {
......
mAm.tempWhitelistUidLocked(r.appInfo.uid,
SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
......
stopServiceLocked(r);
}
}
return null;
}
}
方法代码很长,参见方法中的注释,主要执行流程如下:
- 如果待启动 Service 已经启动过,则直接调用 ActiveServices # sendServiceArgsLocked() 方法,之后通过跨进程通信将启动过程交给应用进程 ApplicationThread 并回调执行 Service # onStartCommand() 方法。
- 如果待启动 Service 未启动,但其所在的进程不为空,则调用 ActiveServices # realStartServiceLocked() 方法创建并启动服务。
- 如果待启动 Service 未启动且其所在的进程为空,则调用 AMS 的 startProcessLocked() 方法创建一个新的进程,并将保存待启动 Service 信息的 ServiceRecord 添加到队列中等待执行。
接下来分三个部分来分别讨论上诉三种情况,首先待启动 Service 已经启动过的情况,调用 ActiveServices # sendServiceArgsLocked() 方法来处理。
1.5.1 ActiveServices # sendServiceArgsLocked()
public final class ActiveServices {
......
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
ArrayList<ServiceStartArgs> args = new ArrayList<>();
while (r.pendingStarts.size() > 0) {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
......
if (si.intent == null && N > 1) {
continue;
}
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
if (si.neededGrants != null) {
mAm.mUgmInternal.grantUriPermissionUncheckedFromIntent(si.neededGrants,
si.getUriPermissionsLocked());
}
mAm.grantImplicitAccess(r.userId, si.intent, si.callingId,
UserHandle.getAppId(r.appInfo.uid)
);
bumpServiceExecutingLocked(r, execInFg, "start");
if (!oomAdjusted) {
oomAdjusted = true;
mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
}
if (r.fgRequired && !r.fgWaiting) {
if (!r.isForeground) {
......
scheduleServiceForegroundTransitionTimeoutLocked(r);
} else {
......
r.fgRequired = false;
}
}
int flags = 0;
if (si.deliveryCount > 1) {
flags |= Service.START_FLAG_RETRY;
}
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
}
ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
slice.setInlineCountLimit(4);
Exception caughtException = null;
try {
r.app.thread.scheduleServiceArgs(r, slice);
}
......
if (caughtException != null) {
final boolean inDestroying = mDestroyingServices.contains(r);
for (int i = 0; i < args.size(); i++) {
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
}
.......
}
}
......
}
参见方法中的注释,主要执行流程如下:
- 遍历保存在 ServiceRecord 的 pendingStarts 列表,将获取的 StartItem 保存到 ServiceRecord 的 deliveredStarts 中,表明数据开始分发。并由 StartItem 实例的 Intent、flag、id 等属性构建用于在应用端分发的 ServiceStartArgs 对象,并将其添加到 ArrayList<ServiceStartArgs> 类型的列表中,之后将列表保存到类型为 ParceledListSlice<ServiceStartArgs> 的可序列化对象中。
- 调用 ApplicationThread 的 scheduleServiceArgs() 方法将 ServiceRecord (其本身是 AMS 进程的 Binder 实体类) 和相关的启动参数通过 IPC 传递给应用进程,并最终回调目标 Service 的 onStartCommand() 方法对启动参数进行解析和处理。
ParceledListSlice:是 Android 系统提供的一个利用 IPC 传输 Parcelable 可序列化对象列表的工具类,当列表中元素的数量足够多时,会自动将其拆分为多个 transaction 依次处理。
1.5.1.1 ApplicationThread # scheduleServiceArgs()
public final class ActivityThread extends ClientTransactionHandler {
......
final H mH = new H();
......
class H extends Handler {
......
public void handleMessage(Message msg) {
switch (msg.what) {
......
case SERVICE_ARGS:
......
handleServiceArgs((ServiceArgsData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
......
}
}
}
......
private class ApplicationThread extends IApplicationThread.Stub {
......
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;
sendMessage(H.SERVICE_ARGS, s);
}
}
......
}
......
void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
......
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
}
ApplicationThread # scheduleServiceArgs() 方法中,遍历保存在 ParceledListSlice 可序列化对象中的启动参数列表,由 ServiceRecord 实例及列表中的每个 ServiceStartArgs 实例来构建 ServiceArgsData 实例,最后通过 ActivityThread 的内部类 H 发送 SERVICE_ARGS 类型的 Handler 消息,进而流程将调用到 ActivityThread # handleServiceArgs() 方法处理 Service 的启动。
ActivityThread 的内部类 H 是一个 Handler,其主要作用是切换系统进程的 Binder 线程和 UI 主线程的,应用进程中 ActivityThread 与系统进程中的服务是通过 ActivityThread 的内部类 ApplicationThread 以 Binder 跨进程通信的方式进行交互,当 ApplicationThread 接收到系统进程的请求或回调后,通过 ActivityThread 的内部类 H 发送指定类型的 Handler 消息将流程切换到应用进程的 UI 主线程进行处理。
1.5.1.2 ActivityThread # handleServiceArgs()
public final class ActivityThread extends ClientTransactionHandler {
......
@UnsupportedAppUsage
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
......
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess();
}
int res;
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
QueuedWork.waitToFinish();
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
......
}
}
......
}
参见方法中的注释,主要执行流程如下:
- 在 mServices 中获取 ServiceRecord 对应的已经启动的 Service 对象,如果 ServiceArgsData 的 taskRemoved 标志位为 false (都为false,除非是进程销毁时候才会出现 taskRemoved 是 true),则回调 Service 的 onStartCommand() 方法,否则则回调 Service 的 onTaskRemoved() 方法。
- 调用 QueuedWork 的 waitToFinish() 方法,同步等待写入任务完成才会继续执行后续任务。
- 调用 AMS 的 serviceDoneExecuting() 方法移除 ANR 超时消息。
QueuedWork:是 Android 中的内部工具类,用于跟踪那些未完成的或尚未结束的全局任务,新任务可通过 QueuedWork # queue() 方法加入,也可以通过 QueuedWork # addFinisher() 方法添加 finisher - runnables,并由 QueuedWork # waitToFinish() 方法保证执行,以确保任务已被处理完成。
1.5.1.3 Service # onStartCommand()
public abstract class Service extends ContextWrapper implements ComponentCallbacks2,...{
......
public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
......
}
当通过调用 startService() 方法请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 方法来停止服务。注意:在绑定状态下,无需实现此方法。
1.5.1.4 时序图
至此,待启动 Service 已启动过情况下的流程分析完毕,结合上面的时序图加深理解。
接下来分析待启动 Service 未启动,但其所在的进程不为空的情况,此时流程调用 ActiveServices # realStartServiceLocked() 方法来创建并启动服务。
1.5.2 ActiveServices # realStartServiceLocked()
public final class ActiveServices {
......
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
......
r.setProcess(app);
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.startService(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, false);
mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
boolean created = false;
try {
......
FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_LAUNCH_REPORTED, r.appInfo.uid,
r.name.getPackageName(), r.name.getClassName());
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
mAm.appDiedLocked(app, "Died when creating service");
throw e;
} finally {
if (!created) {
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
if (newService) {
app.stopService(r);
r.setProcess(null);
}
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
if (newService && created) {
app.addBoundClientUidsOfNewService(r);
}
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r);
}
}
}
......
}
参见方法中的注释,主要执行流程如下:
- ServiceRecord 设置进程,即 ServiceRecord 和 ProcessRecord 绑定,然后将 ServiceRecord 添加到 ProcessRecord 的 mServices 集合中,表示当前 Service 在指定进程中已经处于运行状态。
- 跨进程调用 App 端的 ApplicationThread 的 scheduleCreateService() 方法,创建 Service 对象并执行其 onCreate() 方法。注意:如果是前台服务,需创建通知栏中的通知信息。如果创建新服务失败,则根据条件判断置空进程信息,并尝试再次启动 Service。
- 调用 ActiveServices # requestServiceBindingsLocked() 方法处理 Service 的绑定过程,其最终会通过跨进程回调 Service # onBind() 方法(后面章节讲解)。事实上以 startService 方式启动 Service 时,原本并不需要处理绑定过程,但是当 Service 对应的进程尚未创建时,会将对应的 ServiceRecord 对象暂时保存在 mPendingServices 中。如果在进程创建的过程中,恰好又以 bindService 方式提交了其它启动请求,那么自然就需要额外处理 Service 的绑定过程。
- 调用 ActiveServices # sendServiceArgsLocked() 方法发送启动服务消息,具体流程参见 1.5.1 ActiveServices # sendServiceArgsLocked(),最终回调 Service 的 onStartCommand() 方法。
1.5.2.1 ApplicationThread # scheduleCreateService()
public final class ActivityThread extends ClientTransactionHandler {
......
final H mH = new H();
......
class H extends Handler {
......
public void handleMessage(Message msg) {
switch (msg.what) {
......
case CREATE_SERVICE:
......
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
......
}
}
}
......
private class ApplicationThread extends IApplicationThread.Stub {
......
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);
}
......
}
......
void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
......
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
}
ApplicationThread # scheduleCreateService() 方法中,更新进程的状态值,并将入参 token、ServiceInfo 等封装成 CreateServiceData 实例对象,最后通过 ActivityThread 的内部类 H 发送 CREATE_SERVICE 类型的 Handler 消息,进而流程将调用到 ActivityThread # handleCreateService() 方法创建 Service。
1.5.2.2 ActivityThread # handleCreateService()
public final class ActivityThread extends ClientTransactionHandler {
......
@UnsupportedAppUsage
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
......
@UnsupportedAppUsage
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
......
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
......
}
......
}
参见方法中的注释,主要执行流程如下:
- 获取 LoadedApk 实例,LoadedApk 是 Apk 安装文件在内存中的数据 , 可以在 LoadedApk 中得到 Apk 文件中的代码、资源文件、Activity 与 Service 等组件及 AndroidManifest 配置文件等。
- 创建服务的 Context,这里 ContextImpl 是 Context 的具体实现类,然后通过 LoadedApk 对象加载并构建 Application 和 Service 实例对象。
- 调用 Service # attach() 方法绑定上下文 Context 和创建服务用到的信息,注意:这里 data.token 即系统进程中 AMS 跨进程传递给应用进程的 ServiceRecord 实例。
- 调用 Service # onCreate() 方法,首次创建服务时,系统将调用此方法来执行一次性设置程序 ( 在调用 onStartCommand() 或onBind() 方法之前 )。如果服务已在运行,则不会调用此方法,该方法只调用一次。
- 将新建的服务 Service 缓存到 mServices 中,mServices 是 ActivityThread 类的一个 ArrayMap<IBinder, Service> 类型的成员变量,它的键是系统进程中 AMS 的 ServiceRecord 在应用进程中的 Binder 代理对象,它的值是应用进程的 Service 对象。
- 调用 AMS 的 serviceDoneExecuting() 方法,通知 AMS 新的 Service 已启动完毕,并移除掉指定条件下的缓存数据。
1.5.2.3 时序图
至此,待启动 Service 未启动,但其所在的进程不为空情况下的流程分析完毕,结合上面的时序图加深理解。
最后来分析待启动 Service 未启动且其所依附的进程为空的情况,此时流程调用 AMS 的 startProcessLocked() 方法创建一个新的进程,然后创建并启动需在此新进程中运行的 Service。
1.5.3 AMS # startProcessLocked()
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 ,
keepIfLarge, null , null ,
null , null );
}
......
}
文章篇幅有限,有关通过 AMS 创建新进程的过程可以参考文章 深度详解 Android R(11.0)Activity 启动过程 的第三部分和第四部分的源码解析。
简述进程的创建流程:
- 调用 AMS # startProcessLocked() 方法,传入进程名、ApplicationInfo 应用信息等参数,继续调用 ProcessList # startProcessLocked() 方法获取 ProcessRecord 实例对象,然后调用重载的另一个 startProcessLocked() 方法,根据初始化好的 entryPoint、processName、uid、gids 等参数通过调用 Process 的 start() 方法,在方法内部通过 Zygote 进程 fork 出一个新的进程并启动。
- 新进程创建的过程中指定待加载的类名 entryPoint 是 “android.app.ActivityThread” 类,在启动新进程后通过 ClassLoader 加载获取类实例并通过反射调用该类的 main() 方法。在 ActivityThread # main() 方法中会开启消息循环,然后创建一个 ActivityThread 实例,并调用 ActivityThread # attach() 方法然后通过 AMS # attachApplication() 方法,将 ActivityThread 实例的内部类 ApplicationThread 和 AMS 进行绑定。
下面来具体分析如何进行 Application 的初始化和 Service 的启动,首先来看一下 AMS 绑定 Application 的过程。
1.5.3.1 AMS # attachApplication()
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
final ActiveServices mServices;
.......
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
......
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
long bindApplicationTimeMillis;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
if (app != null && (app.startUid != callingUid || app.startSeq != startSeq)) {
......
cleanUpApplicationRecordLocked(app, false, false, -1, true );
removePidLocked(app);
app = null;
}
} else {
app = null;
}
if (app == null && startSeq > 0) {
final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
if (pending != null && pending.startUid == callingUid && pending.startSeq == startSeq
&& mProcessList.handleProcessStartedLocked(pending, pid, pending
.isUsingWrapper(), startSeq, true)) {
app = pending;
}
}
if (app == null) {
......
if (pid > 0 && pid != MY_PID) {
killProcessQuiet(pid);
mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
ApplicationExitInfo.SUBREASON_UNKNOWN, "attach failed");
}
......
return false;
}
if (app.thread != null) {
handleAppDiedLocked(app, true, true);
}
......
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
mOomAdjuster.setAttachingSchedGroupLocked(app);
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, 0, false);
......
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
......
try {
......
if (app.isolatedEntryPoint != null) {
......
} else if (instr2 != null) {
......
} else {
thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.mDisabledCompatChanges);
}
......
app.makeActive(thread, mProcessStats);
mProcessList.updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
}
......
mPersistentStartingProcesses.remove(app);
......
boolean badApp = false;
boolean didSomething = false;
......
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch (Exception e) {
badApp = true;
}
}
......
.......
if (badApp) {
handleAppDiedLocked(app, false, true);
return false;
}
if (!didSomething) {
updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
}
......
return true;
}
......
}
在 AMS # attachApplication() 方法中继续调用 AMS # attachApplicationLocked() 方法,参见方法中的注释,其主要执行流程如下:
- 首先获取 mPidsSelfLocked 中保存的该进程对应的 ProcessRecord 实例,如果获取不到则从 mPendingStarts 列表根据 startSeq 查找进程,此时如果 application 记录仍然依附在以前的进程,则需清理掉。
- 移除启动进程时埋下的进程启动超时处理的逻辑,调用 ApplicationThread # bindApplication() 方法创建绑定 Application 实例,然后更新 mProcessList 保存的进程信息(Lru:最近使用过要调整到列表头部)。
- 调用 ActiveServices # attachApplicationLocked() 方法筛选出应该在此进程中运行的 Service 并启动。
1.5.3.2 ApplicationThread # bindApplication()
public final class ActivityThread extends ClientTransactionHandler {
......
final H mH = new H();
......
class H extends Handler {
......
public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
......
}
}
}
......
private class ApplicationThread extends IApplicationThread.Stub {
......
@Override
public final void bindApplication(String processName, ApplicationInfo appInfo,...) {
......
setCoreSettings(coreSettings);
AppBindData data = new AppBindData();
data.processName = processName;
......
sendMessage(H.BIND_APPLICATION, data);
}
......
}
......
void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
......
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
}
ApplicationThread # bindApplication() 方法中,首先校验以确保应用程序可以获取到传入的 Service,并将入参 processName、appInfo 等封装成 AppBindData 实例对象,最后通过 ActivityThread 的内部类 H 发送 BIND_APPLICATION 类型的 Handler 消息,进而流程将调用到 ActivityThread # handleBindApplication() 方法创建绑定 Application 实例。
1.5.3.3 ActivityThread # handleBindApplication()
public final class ActivityThread extends ClientTransactionHandler {
......
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
......
Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
......
Process.setArgV0(data.processName);
......
final InstrumentationInfo ii;
if (data.instrumentationName != null) {
try {
ii = new ApplicationPackageManager(
null, getPackageManager(), getPermissionManager())
.getInstrumentationInfo(data.instrumentationName, 0);
}
......
} else {
ii = null;
}
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
updateLocaleListFromAppContext(appContext,
mResourcesManager.getConfiguration().getLocales());
......
if (ii != null) {
ApplicationInfo instrApp;
try {
instrApp = getPackageManager().getApplicationInfo(ii.packageName, 0,
UserHandle.myUserId());
} catch (RemoteException e) {
instrApp = null;
}
if (instrApp == null) {
instrApp = new ApplicationInfo();
}
ii.copyTo(instrApp);
instrApp.initForUser(UserHandle.myUserId());
final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true, false);
......
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi,
appContext.getOpPackageName());
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
}
......
final ComponentName component = new ComponentName(ii.packageName, ii.name);
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
......
} else {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
}
......
Application app;
......
try {
app = data.info.makeApplication(data.restrictedBackupMode, null);
app.setAutofillOptions(data.autofillOptions);
app.setContentCaptureOptions(data.contentCaptureOptions);
mInitialApplication = app;
......
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
......
}
}
......
}
......
}
参见方法中的注释,其主要执行流程如下:
- 设置进程名、时区/地区初始化、Debug Waiting、Http 代理初始化、安装 Network Security Config Provider 等等。
- 创建 Application 实例对象并通过 Instrumentation 回调 Application # OnCreate() 方法。
至此,完成新进程创建,并且每个进程的 Application 实例对象也创建完成,现在回到 Service 的启动过程,在 Service 所在的进程不存在的情况下通过 AMS 创建所需的新进程,并将保存待启动 Service 信息的 ServiceRecord 添加到队列中等待执行。
回到 1.5.3.1 AMS # attachApplication() 方法的分析,在创建绑定完 Application 实例对象后,调用 ActiveServices # attachApplicationLocked() 方法找到应该在此进程中运行的 Service 并启动。
1.5.3.4 ActiveServices # attachApplicationLocked()
public final class ActiveServices {
......
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
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.longVersionCode,
mAm.mProcessStats);
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
if (!isServiceNeededLocked(sr, false, false)) {
bringDownServiceLocked(sr);
}
}
}
......
}
if (mRestartingServices.size() > 0) {
ServiceRecord sr;
for (int i=0; i<mRestartingServices.size(); i++) {
sr = mRestartingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
mAm.mHandler.removeCallbacks(sr.restarter);
mAm.mHandler.post(sr.restarter);
}
}
return didSomething;
}
......
}
在方法中,判断进程中待启动 Service 队列 mPendingServices 中是否有挂起的 Service 需在此进程中启动并运行的,如果有则通过 ActiveServices # realStartServiceLocked() 方法来启动 Service,具体启动流程参见 1.5.2 ActiveServices # realStartServiceLocked() 的具体分析。
1.5.3.5 时序图
至此,待启动 Service 未启动,且依附进程为空情况下的流程分析完毕,结合上面的时序图加深理解。
1.6 总结
至此,startService 启动服务的流程已分析完毕,由简入难,步步深入。
首先分析,待启动 Service 已启动过的情况,调用 ActiveServices # sendServiceArgsLocked() 方法,后通过跨进程通信将启动过程交给应用进程 ApplicationThread 执行 Service 的 onStartCommand() 方法启动 Service。
其次分析,待启动 Service 未启动,但其依附的进程不为空的情况,调用 ActiveServices # realStartServiceLocked() 方法创建 Service 并启动。
最后分析,待启动 Service 未启动,且依附进程为空的情况,则调用 AMS 的 startProcessLocked() 方法创建一个新的进程,并将保存待启动 Service 信息的 ServiceRecord 添加到队列中,等到新进程创建完毕并启动后,遍历该队列获取需在此新进程中启动并运行的 Service。
2 bindService 绑定服务
通过 bindService 绑定服务,要先构建 Service 子类,然后调用 bindService() 方法时还需传入 ServiceConnection 接口的实现,通过 ServiceConnection # onServiceConnected() 方法,获取 Service 端的 IBinder 对象,使用该对象可以进行客户端和 Service 端的跨进程通信,代码如下所示:
class TestServiceActivity : Activity() {
private val TAG: String = TestServiceActivity::class.java.simpleName
private var conn = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_service)
btnBindService.setOnClickListener {
val intent = Intent(this, SimpleService::class.java)
bindService(intent, conn, 0)
}
btnUnbindService.setOnClickListener {
unbindService(conn)
}
}
}
2.1 ContextWrapper # bindService()
public class ContextWrapper extends Context {
......
@UnsupportedAppUsage
Context mBase;
......
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
......
}
调用 ContextWrapper # bindService() 方法来绑定 Service,在该方法中将绑定 Service 的过程委托给了 mBase,这里 mBase 是 ContextImpl 实例对象,ContextImpl 是抽象类 Context 的具体实现类,即调用流程委托给 ContextImpl 并调用其 bindService() 方法。具体详解参见文章 深度详解 Android 之 Context。
2.2 ContextImpl # bindService()
class ContextImpl extends Context {
......
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
getUser());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
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);
int res = ActivityManager.getService().bindIsolatedService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, 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();
}
}
......
}
执行流程如下:
- 调用 ContextImpl # validateServiceIntent() 方法对参数 Intent 进行合法性检查,Android 5.0 后要求 Service 必须通过显式 Intent 启动,否则会直接抛出异常。调用 Intent # prepareToLeaveProcess() 方法对 Intent 的属性进行离开应用进程前的准备工作。
- 获取继承自 IActivityManager.Stub 类的客户端实现类,即获取服务端 AMS 在本地的代理对象 BpBinder,通过代理对象的调用将启动服务的任务跨进程传给 AMS 并调用其 bindIsolatedService() 方法继续绑定 Service。
2.3 AMS # bindIsolatedService()
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {
......
final ActiveServices mServices;
......
public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
......
mServices = new ActiveServices(this);
......
}
......
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
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 (instanceName != null) {
for (int i = 0; i < instanceName.length(); ++i) {
char c = instanceName.charAt(i);
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9') || c == '_' || c == '.')) {
throw new IllegalArgumentException("Illegal instanceName");
}
}
}
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
......
}
在 AMS # bindIsolatedService() 方法中,将绑定 Service 的任务委托给 ActiveServices 来执行,并调用其 bindServiceLocked() 方法,ActiveServices 类是用来辅助 AMS 来管理 Service 的核心类。
2.4 ActiveServices # bindServiceLocked()
public final class ActiveServices {
......
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, String callingPackage, final int userId)
throws TransactionTooLargeException {
......
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) { ...
ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
if (token != null) {
activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
......
return 0;
}
......
......
final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
ServiceLookupResult res =
retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
callerFg, isBindExternal, allowInstant);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
ServiceRecord s = res.record;
boolean permissionsReviewRequired = false;
if (mAm.getPackageManagerInternalLocked().isPermissionsReviewRequired(
s.packageName, s.userId)) {
......
final ServiceRecord serviceRecord = s;
final Intent serviceIntent = service;
RemoteCallback callback = new RemoteCallback(
new RemoteCallback.OnResultListener() {
@Override
public void onResult(Bundle result) {
synchronized(mAm) {
final long identity = Binder.clearCallingIdentity();
try {
if (!mPendingServices.contains(serviceRecord)) {
return;
}
if (!mAm.getPackageManagerInternalLocked()
.isPermissionsReviewRequired(
serviceRecord.packageName,
serviceRecord.userId)) {
try {
bringUpServiceLocked(serviceRecord,
serviceIntent.getFlags(),
callerFg, false, false);
} catch (RemoteException e) {
}
} else {
unbindServiceLocked(connection);
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
});
......
}
final long origId = Binder.clearCallingIdentity();
try {
......
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent,
callerApp.uid, callerApp.processName, callingPackage);
IBinder binder = connection.asBinder();
s.addConnection(binder, c);
b.connections.add(c);
if (activity != null) {
activity.addConnection(c);
}
b.client.connections.add(c);
......
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
......
if (s.app != null) {
......
mAm.updateLruProcessLocked(s.app,
(callerApp.hasActivitiesOrRecentTasks() && s.app.hasClientActivities())
|| (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP
&& (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0),
b.client);
mAm.updateOomAdjLocked(s.app, OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
}
......
if (s.app != null && b.intent.received) {
try {
c.conn.connected(s.name, b.intent.binder, false);
} catch (Exception e) {
......
}
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
maybeLogBindCrossProfileService(userId, callingPackage, callerApp.info.uid);
getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
......
}
方法比较长,删减部分代码,参见方法中的注释,其主要执行流程如下:
- 获取 mLruProcesses 中缓存的调用进程 caller 对应的 ProcessRecord,获取不到则抛出异常。然后获取 ServiceConnection 的宿主 Activity,即在哪里调用的 bindService,获取不到则返回 0 即 Activity 没有在栈中绑定不了 Service。
- 调用 ActiveServices # retrieveServiceLocked() 方法获取包含 ServiceRecord 的 ServiceLookupResult 实例,参见 1.3.1 ActiveServices # retrieveServiceLocked() 的解析,然后获取 ServiceLookupResult 中的 ServiceRecord 实例。
- 绑定 Service 时是否需要校验权限,如需要则构建 Intent 实例并通过主线程的 Handler 发送,弹出 UI 动态申请权限界面,如果用户同意,则在 RemoteCallback 的回调里面继续调用 ActiveServices # bringUpServiceLocked() 方法创建 Service 并启动,不同意则解除绑定。
- 绑定 Service 时如果设置 flag 为 BIND_AUTO_CREATE,其表示如果服务没有开启则调用 ActiveServices # bringUpServiceLocked() 方法自动创建并启动服务。
- 如果 Service 已经启动并运行,则直接调用 IServiceConnection 的 connect() 方法,最后回调 bindService 时传入的 ServiceConnection 的 onServiceConnected() 方法,稍后 2.5.5 节解析。
2.5 ActiveServices # requestServiceBingingsLocked()
回看 1.5 ActiveServices # bringUpServiceLocked() 的源码解析,在方法中继续调用 1.5.2 ActiveServices # realStartServiceLocked() 方法来真正的启动 Service,在 ActiveServices # realStartServiceLocked() 方法中与 bindService() 有关的逻辑还未分析,即 ActiveServices # requestServiceBingingsLocked() 方法,代码如下:
public final class ActiveServices {
......
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) {
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.getReportedProcState());
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
}
......
}
return true;
}
......
}
方法中首先获取已绑定到服务的特定 Intent,然后继续调用 ActiveServices # requestServiceBindingLocked() 方法,在该方法中通过跨进程通信,调用 ApplicationThread 的 scheduleBindService() 方法绑定服务。
2.5.1 ApplicationThread # scheduleBindService()
public final class ActivityThread extends ClientTransactionHandler {
......
final H mH = new H();
......
class H extends Handler {
......
public void handleMessage(Message msg) {
switch (msg.what) {
......
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
......
}
}
}
......
private class ApplicationThread extends IApplicationThread.Stub {
......
@Override
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;
......
sendMessage(H.BIND_SERVICE, s);
}
......
}
......
void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
......
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
}
ApplicationThread # scheduleBindService() 方法中,首先更新进程的状态值,并将入参 token、intent 等封装成 BindServiceData 实例对象,最后通过 ActivityThread 的内部类 H 发送 BIND_SERVICE 类型的 Handler 消息,进而流程将调用到 ActivityThread # handleBindService() 方法绑定到 Service。
2.5.2 ActivityThread # handleBindService()
public final class ActivityThread extends ClientTransactionHandler {
......
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
......
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
......
}
}
......
}
由 token 标识获取 mServices 中缓存的 Service 实例,如果不是重新绑定,则回调自定义 Service 的 onBind() 方法,然后调用 AMS 的 publishService() 方法发布服务 (重新绑定逻辑感兴趣的可以自行查阅源码)。
2.5.3 AMS # publishService()
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
......
final ActiveServices mServices;
......
public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
......
mServices = new ActiveServices(this);
......
}
......
public void publishService(IBinder token, Intent intent, IBinder service) {
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);
}
}
......
}
方法中首先校验 Intent 是否为空,是否有文件描述符等,后校验要发布的 Service 的 token 标识是不是 ServiceRecord 类型的,如果都满足则调用 mServices # publishServiceLocked() 方法发布 Service。
2.5.4 ActiveServices # publishServiceLocked()
public final class ActiveServices {
......
final ArrayMap<IBinder, ArrayList<ConnectionRecord>> mServiceConnections = new ArrayMap<>();
......
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
......
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;
ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
for (int conni = connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
......
continue;
}
......
try {
c.conn.connected(r.name, service, false);
}
......
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
......
}
方法中,遍历获取保存的每个 ConnectionRecord 实例,如果该 ConnectionRecord 匹配到指定的 Intent.FilterComparison 则异步回调连接 ConnectionRecord 的成员 IServiceConnection 的 connected() 方法,注意:这里 IServiceConnection 的实现类是 InnerConnection,其实现了 IServiceConnection.Stub 接口。
2.5.5 LoadedApk # ServiceDispatcher # InnerConnection # connected()
public final class LoadedApk {
......
static final class ServiceDispatcher {
......
private final Handler mActivityThread;
......
private static class InnerConnection extends IServiceConnection.Stub {
@UnsupportedAppUsage
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}
......
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
......
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
......
}
......
}
在 InnerConnection # connected() 方法中继续调用 LoadedApk # ServiceDispatcher 的 connected() 方法,回看 2.2 ContextImpl # bindService() 的解析可知,在调用 ContextImpl # bindServiceCommon() 方法时传入了 mMainThread # getHandler() 获取到的主线程的 Handler,而 Executor 传入为空,因此这里将通过主线程的 Handler # post() 一个 Runnable 任务后续会执行其 run() 方法,在 run() 方法中由于 mCommand 被赋值为 0,因此将执行 ServiceDispatcher # doConnected() 方法。
2.5.6 LoadedApk # ServiceDispatcher # doConnected()
public final class LoadedApk {
......
static final class ServiceDispatcher {
......
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return;
}
if (service != null) {
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) {
......
mActiveConnections.remove(name);
return;
}
} else {
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
mConnection.onNullBinding(name);
}
}
......
}
......
}
该方法主要作用是回调 bindService 时传入的 ServiceConnection 的 onServiceConnected() 方法。
2.6 时序图
2.7 总结
至此,bindService 的启动流程分析完毕,结合上面的时序图加深理解。
三. 交流
相信本文对于理解 Service 的启动应该会有很大帮助的,另外 Service 重启有关的代码流程,这里篇幅有限下一篇文章继续分析,如有分析错误或者别的理解,还望不吝赐教–留言或者私信笔者讨论,共同学习。
|