主要的调用关系:
startService [ContextImpl.java]
--->startServiceCommon [ContextImpl.java]
--->startService [ActivityManagerService.java]
--->startServiceLocked [ActivityService.java]
--->retrieveServiceLocked //主要是检查和创建ServiceRecord
--->startServiceInnerLocked
--->bringUpServiceLocked
--情况1--->sendServiceArgsLocked //onStartCommand
--情况2--->realStartServiceLocked //依次调用service.onCreate()和onStartCommand()
--情况3--->startProcessLocked //AMS-->zygote创建APP进程.........
service运行的进程
一般在AndroidManifest.xml配置service组件信息时,都会设置android:process属性,其值的格式“:XXX”,如下所示:
<service android:name="com.godin.demo.tmp.TmpService1"
android:process=":serviceThread"></service>
如果不设置android:process属性,那么service就可能会和其他组件,例如activity运行在一个进程中的UI线程,也就是主线程中。那么在这种情况下,service中执行耗时的操作是比较危险的。
service的启动方式:
1-startService(),启动service之后,启动者和service之间的关系比较松散,启动者仅能停止service,不能和service之间交互。而且启动者,比如activity被销毁后,service不受影响,还可以继续运行。
2-bindService(),启动的service和启动者可以交互,启动者可以调用service的方法,即rpc。启动者销毁后,如果没有其他组件绑定该service,那么该service也被销毁。
两个方法都是异步的,也就是说当这两个方法返回的时候,service可能还没创启动好,还没执行相应的回调方法。
不管是哪种启动方式,终究还是由AMS来启动的,因为service毕竟是一个组件,而AMS是组件的管理者。startService与bindService 区别在于没有connection 是否销毁
service的启动:
frameworks/base/core/java/android/app/ContextImpl.java
ContextImpl.startService():
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser); ----> 继续调用startServiceCommon
}
frameworks/base/core/java/android/app/ContextImpl.java
startServiceCommon:
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService( ---> 这里走到了AMS
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
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());
} else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
AMS:startService
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,-----> 这里走到了ActivityService.java:startServiceLocked
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
frameworks/base/services/core/java/com/android/server/am/ActivityService.java
startServiceLocked:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
final boolean callerFg;
if (caller != null) {---> // 检查调用者是否处于前台,是的话设置callerFg为true
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + callingPid
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, ---》// 检查AMS是否存在该service的ServiceRecord,没的话创建,res 是ServiceRecord 的封装
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");
}
ServiceRecord r = res.record; ---》 这里提取了返回的ServiceRecord
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
return null;
}
// If this isn't a direct-to-foreground start, check our ability to kick off an
// arbitrary service
if (!r.startRequested && !fgRequired) {
// Before going further -- if this app is not allowed to start services in the
// background, then at this point we aren't going to let it period.
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);
if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
// In this case we are silently disabling the app, to disrupt as
// little as possible existing apps.
return null;
}
// This app knows it is in the new model where this operation is not
// allowed, so tell it what has happened.
UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
// If permissions need a review before any of the app components can run,
// we do not start the service and launch a review activity if the calling app
// is in the foreground passing it a pending intent to start the service when
// review is completed.
if (mAm.mPermissionReviewRequired) {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
callingUid, service, callerFg, userId)) {
return null;
}
}
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
/*
下面代码的无非就是设置一下ServiceRecord的一些字段,注意这里没有设置ServiceRecord.app,也就是说如果这个ServiceRecord对象是新创建的,那么它还没有与进程关联,此时r.app为NULL.如果ServiceRecord已经存在,也就是service已经启动了,那么r.app就不会为null。
重点看r.pendingStarts.add操作。这个操作将启动service所需要的信息,如intent等都保存了起来,只要这个pendingStarts不为null,就说明有启动该service的请求还没处理。当后面处理完之后,会将存储的信息从r.pendingStarts移动到r.deliveredStarts中。这两个成员都是ArrayList<StartItem>类型的数组。
*/
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
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 this is not coming from a foreground caller, then we may want
// to delay the start if there are already other background services
// that are starting. This is to avoid process start spam when lots
// of applications are all handling things like connectivity broadcasts.
// We only do this for cached processes, because otherwise an application
// can have assumptions about calling startService() for a service to run
// in its own process, and for that process to not be killed before the
// service is started. This is especially the case for receivers, which
// may start a service in onReceive() to do some additional work and have
// initialized some global state as part of that.
if (DEBUG_DELAYED_SERVICE) Slog.v(TAG_SERVICE, "Potential start delay of "
+ r + " in " + proc);
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Not delaying: " + r);
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
// currently running other services or receivers.
addToStarting = true;
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"Not delaying, but counting as bg: " + r);
} else if (DEBUG_DELAYED_STARTS) {
StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.curProcState)
.append(' ').append(proc.adjType);
String reason = proc.makeAdjReason();
if (reason != null) {
sb.append(' ');
sb.append(reason);
}
sb.append("): ");
sb.append(r.toString());
Slog.v(TAG_SERVICE, sb.toString());
}
} else if (DEBUG_DELAYED_STARTS) {
if (callerFg || fgRequired) {
Slog.v(TAG_SERVICE, "Not potential delay (callerFg=" + callerFg + " uid="
+ callingUid + " pid=" + callingPid + " fgRequired=" + fgRequired + "): " + r);
} else if (r.app != null) {
Slog.v(TAG_SERVICE, "Not potential delay (cur app=" + r.app + "): " + r);
} else {
Slog.v(TAG_SERVICE,
"Not potential delay (user " + r.userId + " not started): " + r);
}
}
//后面分析startServiceInnerLocked
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
retrieveServiceLocked()的作用就是检查和创建ServiceRecord,过程如下:
frameworks/base/services/core/java/com/android/server/am/ActivityService.java
retrieveServiceLocked:
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
ServiceRecord r = null;
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
+ " type=" + resolvedType + " callingUid=" + callingUid);
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
ServiceMap smap = getServiceMapLocked(userId); ---> userId 区分用户
final ComponentName comp = service.getComponent();
if (comp != null) {
r = smap.mServicesByName.get(comp);
if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
}
if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by intent: " + r);
}
if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
&& !callingPackage.equals(r.packageName)) {
// If an external service is running within its own package, other packages
// should not bind to that instance.
r = null;
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Whoops, can't use existing external service");
}
if (r == null) {
try {
// TODO: come back and remove this assumption to triage all services
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId, callingUid);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
": not found");
return null;
}
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
if (isBindExternal) {
if (!sInfo.exported) {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
" is not exported");
}
if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
" is not an isolatedProcess");
}
// Run the service under the calling package's application.
ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
if (aInfo == null) {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " +
"could not resolve client package " + callingPackage);
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
sInfo.applicationInfo.packageName = aInfo.packageName;
sInfo.applicationInfo.uid = aInfo.uid;
name = new ComponentName(aInfo.packageName, name.getClassName());
service.setComponent(name);
} else {
throw new SecurityException("BIND_EXTERNAL_SERVICE required for " +
name);
}
} else if (isBindExternal) {
throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
" is not an externalService");
}
if (userId > 0) {
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)
&& mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
userId = 0;
smap = getServiceMapLocked(0);
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
r = smap.mServicesByName.get(name);
if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE,
"Retrieved via pm by intent: " + r);
if (r == null && createIfNeeded) {
final Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
final ServiceRestarter res = new ServiceRestarter();
final BatteryStatsImpl.Uid.Pkg.Serv ss;
final BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
ss = stats.getServiceStatsLocked(
sInfo.applicationInfo.uid, sInfo.packageName,
sInfo.name);
}
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
res.setService(r);
smap.mServicesByName.put(name, r);
smap.mServicesByIntent.put(filter, r);
// Make sure this component isn't in the pending list.
for (int i=mPendingServices.size()-1; i>=0; i--) {
final ServiceRecord pr = mPendingServices.get(i);
if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
&& pr.name.equals(name)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Remove pending: " + pr);
mPendingServices.remove(i);
}
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Retrieve created new service: " + r);
}
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
}
if (r != null) {
if (mAm.checkComponentPermission(r.permission,
callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
if (!r.exported) {
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " that is not exported from uid " + r.appInfo.uid);
return new ServiceLookupResult(null, "not exported from uid "
+ r.appInfo.uid);
}
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requires " + r.permission);
return new ServiceLookupResult(null, r.permission);
} else if (r.permission != null && callingPackage != null) {
final int opCode = AppOpsManager.permissionToOpCode(r.permission);
if (opCode != AppOpsManager.OP_NONE && mAm.mAppOpsService.noteOperation(
opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requires appop " + AppOpsManager.opToName(opCode));
return null;
}
}
if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
resolvedType, r.appInfo)) {
return null;
}
return new ServiceLookupResult(r, null); ---> 函数retrieveServiceLocked 的返回值是ServiceRecord的封装
}
return null;
}
getServiceMap()拿到一个ServiceMap,然后从中检查是否存在该service的ServiceRecord.
Android 系统是支持多用户的,所以系统把一个用户下面运行的service,都方到了ServiceMap结构中,可以通过用户ID拿到这个结构:
class ServiceMap extends Handler {
final int mUserId;
final ArrayMap<ComponentName, ServiceRecord> mServicesByName
= new ArrayMap<ComponentName, ServiceRecord>();
final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent
= new ArrayMap<Intent.FilterComparison, ServiceRecord>();
final ArrayList<ServiceRecord> mDelayedStartList
= new ArrayList<ServiceRecord>();
final ArrayList<ServiceRecord> mStartingBackground
= new ArrayList<ServiceRecord>();
.............
}
其中mServicesByName这个ArrayMap是以service的组件名为key的,而mServicesByIntent是以启动这个service的intent为key的。只要是运行着的service至少在这两者置一中进行了记录,所以可以通过这两个map快速查找service是否已经运行。运行的话,返回其ServiceRecord.
如果这两个map中都没有,那就创建一个ServiceRecord,并添加到这两个map中。
retrieveServiceLocked()返回的ServiceLookupResult类:
private final class ServiceLookupResult {
final ServiceRecord record;
final String permission;
ServiceLookupResult(ServiceRecord _record, String _permission) {
record = _record;
permission = _permission;
}
}
可以看到是对ServiceRecord的简单二次封装,其中permission是用来启动这个service时需要的权限。比如有的app中的service,在AndroidManifest.xml还配置了启动他的权限,那么这个权限就记录在这里。
frameworks/base/services/core/java/com/android/server/am/ActivityService.java
startServiceInnerLocked:
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;
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 (DEBUG_DELAYED_SERVICE) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
} else if (DEBUG_DELAYED_STARTS) {
Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
}
if (first) {
smap.rescheduleDelayedStartsLocked();
}
} else if (callerFg || r.fgRequired) {
smap.ensureNotStartingBackgroundLocked(r);
}
return r.name;
}
frameworks/base/services/core/java/com/android/server/am/ActivityService.java
bringUpServiceLocked:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
//Slog.i(TAG, "Bring up service:");
//r.dump(" ");
if (r.app != null && r.app.thread != null) {
//情况1
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && mRestartingServices.contains(r)) {
// If waiting for a restart, then do nothing.
return null;
}
if (DEBUG_SERVICE) {
Slog.v(TAG_SERVICE, "Bringing up " + r + " " + r.intent + " fg=" + r.fgRequired);
}
// We are now bringing the service up, so no longer in the
// restarting state.
if (mRestartingServices.remove(r)) {
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);
getServiceMapLocked(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);
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
String hostingType = "service";
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 {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
///情况2
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;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingType = "webview_service";
}
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (app == null && !permissionsReviewRequired) {
///情况3
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (r.fgRequired) {
if (DEBUG_FOREGROUND_SERVICE) {
Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
+ " for fg-service launch");
}
mAm.tempWhitelistUidLocked(r.appInfo.uid,
SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
}
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;
}
bringUpServiceLocked一共分成下面三种情况:
1-service已经启动了,也就是说前面找到的ServiceRecord是从ServiceMap中获得,并没有创建 ServiceRecord。而且已经与ProcessRecord关联,即r.app不为null。这种情况下就很简单了,调用 sendServiceArgsLocked()就可以了,这最终会导致app中service.onStartCommand()方法被执行。
2-如果service要求寄宿的进程已经存在,而且也没有和前面找到的service的ServiceRecord关联那么调用realStartServiceLocked(),这最终会依次调用到app中service.onCreate()和onStartCommand()这两个service的生命周期方法。
3-如果service要求寄宿的进程还没被创建,那么就要通过AMS.startProcessLocked()创建一个进程
第一种情况:
图片.png
第三种情况:
暂时跳过创建App进程的情况,后面会单独分析App进程的创建过程。这里我们只要知道AMS会根据app的组件需求,例如某个组件设置了android:processName指定了另外一个进程名字,而这个进程有不存在,那么AMS会向zygote进程发出创建进程的请求,zygote创建进程之后,首先执行的代码是ActivityThread.main()方法即可。
第二种情况:
假设service要求寄宿的进程已经创建好了, 只是没有进行对应起来
图片.png
在realStartServiceLocked()方法中会跨进程调用service寄宿的进程的handleCreateService()方法。在该方法中先通过getPackageInfoNoCheck()得到要启动的service的代码所在的apk在进程中的代表:LoadedApk对象。这个对象中记录了加载该apk的classloader,然后利用loadclass,装载要启动的service的类,并通过newInstance()创建了一个service对象。
紧接着为service组件创建上下文context,然后通过makeApplication()方法拿到其所在进程的application对象,然后调用service.attch()和service.OnCreate()方法:
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
service.attach()将ServiceRecord在service进程中的代理binder保存在了service.mToken中,并且作为key保存在ActivityThread.mServices中,value是service
service.attach()方法执行之后,才会执行service的第一个生命周期方法onCreate().
由前面的时序图可知,realStartServiceLocked()中先跨进程调用service所在进程的scheduleCreateService()方法,该方法发送了一个消息CREATE_SERVICE之后便会返回这是一个异步处理的过程。--------->对那个onCreate
然后调用realStartServiceLocked()又调用sendServiceArgsLocked()方法,该方法在发送一个SERVICE_ARGS消息。-------->onStartCommand
这两个异步消息均通过service所在进程的handler发送, 都在service所在的主线程中的looper中被处理,而且线处理CREATE_SERVICE,后处理SERVICE_ARGS消息。也就是先调用service.onCreate(),后执行service.onStartCommand()方法。
但实际上service中最先执行的是service.attach()方法。
CREATE_SERVICE和SERVICE_ARGS 这两个消息都实在进程的主线程也就是ui线程中执行的,所以onCreate()和onStartCommand()有太耗时的操作时,要在开启一个线程来成执行。
网友评论