1.Service整体交互结构
Service作为Android四大组件之一,其生命周期是通过system_server进程中的ActivityManagerService(AMS)管理的,大致了解Service通信过程中涉及到的几个主要角色。
-
App端进程: -
ContextImpl Context抽象类所有api的实现,是Service、Activity和其他组件base Context。 -
ActivityThread 代表着App的主线程,是App的入口,Application、Activity、Service都在ActivityThread中创建,维护着该App所有运行中的Service实例。其中有一个IApplicationThread类型成员mAppThread,用于被AMS跨进程调用。 -
Service 具体提供服务的Service,被ActivityThread管理。 -
ServiceConnection 监听Service连接状态的接口,用于bindService。 -
AMS端: -
ActivityManagerService 四大组件的大管家,是Framework中极为重要的一个类。 -
ActiveServices AMS中管理Service的具体类。 -
ServiceRecord Service结构的具体描述。 -
ServiceMap 描述了一个用户(App)的所有Service记录,主要用于检索。 -
ConnectionRecord Client端与Service端绑定的抽象描述。
2. Service启动过程
2.1 startService
首先看入口:
ContextImpl.java
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), requireForeground, getOpPackageName(), user.getIdentifier());
......
return cn;
}
ContextImpl中只做了validateServiceIntent校验(target 21之后限制隐式启动),然后调用了AMS的startService方法。再看AMS中的实现:
ActivityManagerService.java
@Override
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
......
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
直接调用了ActiveServices的startServiceLocked方法。
ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
......
ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg, false);
......
ServiceRecord r = res.record;
......
if (!r.startRequested && !fgRequired) {
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName, r.appInfo.targetSdkVersion, callingPid, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service " + service + " to " + r.name.flattenToShortString() + " from pid=" + callingPid + " uid=" + callingUid + " pkg=" + callingPackage);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
......
r.startRequested = true;
......
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.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
addToStarting = true;
}
......
}
......
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
这个方法中做了几个检查操作:
- 从mServiceMap中查询SerivceRecord缓存,如果没有则创建一个;
- 如果不是启动前台服务,会检查启动方是否能启动Service,如果启动方应用不在前台,且未在允许后台启动Service的白名单中,将禁止启动。(白名单的逻辑在后面介绍)
- 如非前台调用,也非启动前台服务,且app进程未启动,且正在启动的后台Service过多,该Service会被延时启动,避免在短时间内启动大量进程。
- 通过了前面的检查,调用startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
......
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
......
return r.name;
}
startServiceInnerLocked调用bringUpSrviceLocked启动Service。
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 (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
}
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, hostingType, r.name, false, isolated, false)) == null) {
bringDownServiceLocked(r);
return msg;
}
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
......
return null;
}
这个方法做了3件事情:
- 如果此Service已经被启动,直接调用onStartCommand;
- 如果此Service未启动,但所属进程已启动,则调用realStartServiceLocked进入真正启动Service的流程;
- 如果Service所属进程尚未启动,则先启动进程,如app进程启动失败则销毁此Service;如启动成功,则加入Pengding启动列表,待App进程启动结束后再启动Service。
下面看真正启动Service的方法realStartServiceLocked:
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
.....
final boolean newService = app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(r.app, false);
mAm.updateOomAdjLocked();
boolean created = false;
try {
......
mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_SERVICE); app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState);
r.postNotification();
created = true;
}
......
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
sendServiceArgsLocked(r, execInFg, true);
......
}
- 通知AMS调整应用进程优先级
- 跨进程调用,通过Service所属进程的IApplicationThread,即ActivityThread创建Service实例,再调用其onCreate方法;
如果已经设置通知,则创建前台通知; - 如果Service已经被绑定,则调用onBind方法;
- 调用sendServiceArgsLocked
- 这个方法主要做了2个事情:
1)如启动前台服务,则发送一个5s的延时消息,如5s内未调用Service.startForeground,应用将ANR; 2)通知ActivityThread调用Service的onStartCommand方法;
参考 : https://www.jianshu.com/p/77fe505e2287
|