某学姐

Android Female Developer, Technology Fan, Reader.

startService过程

2020-03-28 | Comments

基于Android 10.0的源码剖析, 站在Luoshengyang/Innost/Gityuan肩膀上.

本文分析startService过程.

0.文件结构

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java

frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/java/android/app/Service.java

1.时序图

TODO

2.ContextImpl.startService

[ -> frameworks/base/core/java/android/app/ContextImpl.java ]

@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    // requireForeground=false表示调用startService启动非前台服务, 区别于startForegroundService
    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;
}

注意:
startService和startForegroundService差别是入参requireForeground的值,其他代码逻辑完全复用.

3.ActivityManagerService.startService

[ -> frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java ]

@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, 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;
        try {
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}

4.ActiveServices

[ -> frameworks/base/services/core/java/com/android/server/am/ActiveServices.java ]

4.1 startServiceLocked

ComponentName startServiceLocked(IApplicationThread caller, Intent service,
		String resolvedType, int callingPid, int callingUid, boolean fgRequired, 
		String callingPackage, final int userId)
        throws TransactionTooLargeException {
	// fgRequired为false, 表示startService
	// allowBackgroundActivityStarts为false, 表示不允许后台Activity启动Service
	return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, 
		    fgRequired, callingPackage, userId, false);
}

继续看该方法实现:

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, boolean fgRequired, String callingPackage,
        final int userId, boolean allowBackgroundActivityStarts)
        throws TransactionTooLargeException {
    final boolean callerFg;
    if (caller != null) {
        // 从mLruProcesses列表中找出指定进程
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
    } else {
        callerFg = true;
    }
 
    // 各种权限检查,并从ServiceMap中根据ComponentName查找ServiceRecord,并封装成ServiceLookupResult
    // 参考【第4.2节】
    ServiceLookupResult res = retrieveServiceLocked(service, null, resolvedType,
		    callingPackage, callingPid, callingUid, userId, true, callerFg, false, false);
 
    // 获取ServiceRecord
    ServiceRecord r = res.record;
 
    // If we're starting indirectly (e.g. from PendingIntent), figure out whether
    // we're launching into an app in a background state.  This keys off of the same
    // idleness state tracking as e.g. O+ background service start policy.
    // 是否后台启动, Android 8.0+有后台启动限制
    final boolean bgLaunch = !mAm.isUidActiveLocked(r.appInfo.uid);
 
    // If the app has strict background restrictions, we treat any bg service
    // start analogously to the legacy-app forced-restrictions case, regardless
    // of its target SDK version.
    // 如果后台启动Service,且app有后台启动限制,则forcedStandby设置为true
    boolean forcedStandby = false;
    if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
        forcedStandby = true;
    }
 
    // If this is a direct-to-foreground start, make sure it is allowed as per the app op.
    // 如果是startForegroundService启动前台服务,检查前台启动操作权限是否允许
    boolean forceSilentAbort = false;
    if (fgRequired) {
        final int mode = mAm.mAppOpsService.checkOperation(
                AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
        switch (mode) {
            case AppOpsManager.MODE_ALLOWED:
            case AppOpsManager.MODE_DEFAULT:
                // All okay.
                break;
            case AppOpsManager.MODE_IGNORED:
                // Not allowed, fall back to normal start service, failing siliently
                // if background check restricts that.
                fgRequired = false;
                forceSilentAbort = true;
                break;
        }
    }
 
    // If this isn't a direct-to-foreground start, check our ability to kick off an
    // arbitrary service
    // 如果是后台启动或者启动非前台服务,检查是否允许后台启动,如果不能的话返回null
    if (forcedStandby || (!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, forcedStandby);
        if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
            if (allowed == ActivityManager.APP_START_MODE_DELAYED || forceSilentAbort) {
                // In this case we are silently disabling the app, to disrupt as
                // little as possible existing apps.
                return null;
            }
            if (forcedStandby) {
                // This is an O+ app, but we might be here because the user has placed
                // it under strict background restrictions.  Don't punish the app if it's
                // trying to do the right thing but we're denying it for that reason.
                if (fgRequired) {
                    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.mProcessList.getUidRecordLocked(r.appInfo.uid);
            return new ComponentName("?", "app is in background uid " + uidRec);
        }
    }
 
    // At this point we've applied allowed-to-start policy based on whether this was
    // an ordinary startService() or a startForegroundService().  Now, only require that
    // the app follow through on the startForegroundService() -> startForeground()
    // contract if it actually targets O+.
    // Android 8.0以下启动前台服务不需要调用startForegroundService(), 即fgRequired为false
    if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
        fgRequired = false;
    }
 
    NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
            callingUid, r.packageName, service, service.getFlags(), null, r.userId);
 
    // 权限检查permission review
    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启动参数, pendingStarts中添加启动项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));
 
    if (fgRequired) {
        // 如果是Android 8.0+调用的startForegroundService()启动前台服务的话, 更新ServiceState
        // We are now effectively running a foreground service.
        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, true);
    }
 
    // 获取ServiceMap. 参考【第4.3节】
    final ServiceMap smap = getServiceMapLocked(r.userId);
    boolean addToStarting = false;
    // 如果是调用startService且Service还没启动,且mStartedUsers列表包含userId
    // 则更新addToStarting状态位为true
    if (!callerFg && !fgRequired && r.app == null && mAm.mUserController.hasStartedUserState(r.userId)) {
        // 从进程列表中获取启动Service所在的进程
        ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
        if (proc == null || proc.getCurProcState() > 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.
            // 如果delayed为true,延迟启动
            if (r.delayed) {
                // This service is already scheduled for a delayed start; just leave
                // it still waiting.
                return r.name;
            }
            // 如果后台启动服务数超过mMaxStartingBackground,则延迟启动
            if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                // Something else is starting, delay!
                smap.mDelayedStartList.add(r);
                r.delayed = true;
                return r.name;
            }
            // addToStarting设置为true
            addToStarting = true;
        } else if (proc.getCurProcState() >= 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;
        }
    }
 
    // Called when the service is started with allowBackgroundActivityStarts set.
    if (allowBackgroundActivityStarts) {
        r.whitelistBgActivityStartsOnServiceStart();
    }
 
	// 启动服务. 参考【第4.4节】
    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;
}

4.2 retrieveServiceLocked

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
    userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
            ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE, "service", callingPackage);
 
    // 根据userId获取ServiceMap. 参考【第4.3节】
    ServiceMap smap = getServiceMapLocked(userId);
 
    // 获取Component
    final ComponentName comp;
    if (instanceName == null) {
        comp = service.getComponent();
    } else {
        final ComponentName realComp = service.getComponent();
        comp = new ComponentName(realComp.getPackageName(), realComp.getClassName() + ":" + instanceName);
    }
    // 获取ServiceRecord
    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)) {
        // If an external service is running within its own package, other packages should not bind to that instance.
        r = null;
    }
 
    if (r == null) {
        try {
            int flags = ActivityManagerService.STOCK_PM_FLAGS | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
            if (allowInstant) {
                flags |= PackageManager.MATCH_INSTANT;
            }
            // 获取ResolveInfo
            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;
            // 检查调起方和被调起方, 不同uid下的不同package能否建立联系. 默认情况下只要uid之一是SYSTEM_UID,都是允许建立练习的
            if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid,name.getPackageName(), sInfo.applicationInfo.uid)) {
                String msg = "association not allowed between packages " + callingPackage + " and " + name.getPackageName();
                // Service查找失败, 返回null
                return new ServiceLookupResult(null, msg);
            }
 
            // Store the defining packageName and uid, as they might be changed in
            // the ApplicationInfo for external services (which run with the package name
            // and uid of the caller).
            // 这段代码检查是否允许Service运行在调用方的package和uid中
            String definingPackageName = sInfo.applicationInfo.packageName;
            int definingUid = sInfo.applicationInfo.uid;
            if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
                if (isBindExternal) {
                    // 各种检查:exported和flags & ServiceInfo.FLAG_ISOLATED_PROCESS
                    ...
                    // Run the service under the calling package's application.
                    ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
                            callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
                    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());
                    className = new ComponentName(aInfo.packageName,
                            instanceName == null ? className.getClassName()
                                : (className.getClassName() + ":" + instanceName));
                    service.setComponent(name);
                } else {
                    throw new SecurityException("BIND_EXTERNAL_SERVICE required for " + name);
                }
            }
 
            if (userId > 0) {
                // Checks to see if the caller is in the same app as the singleton component, or the component is in a special app.
                // 检查调用方和被调用方是否在同一个app中, 或者被调用方为SYSTEM_UID或PHONE_UID
                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);
            }
            // 从map中查找
            r = smap.mServicesByInstanceName.get(name);
            if (r == null && createIfNeeded) {
                final Intent.FilterComparison filter = new Intent.FilterComparison(service.cloneFilter());
                final ServiceRestarter res = new ServiceRestarter();
                ...
                // 创建ServiceRecord,并添加到Map中
                r = new ServiceRecord(mAm, ss, className, name, definingPackageName, definingUid, filter, sInfo, callingFromFg, res);
                res.setService(r);
                smap.mServicesByInstanceName.put(name, r);
                smap.mServicesByIntent.put(filter, r);
 
                // 从pending列表移除该ServiceRecord
                for (int i=mPendingServices.size()-1; i>=0; i--) {
                    final ServiceRecord pr = mPendingServices.get(i);
                    if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid && pr.instanceName.equals(name)) {
                        mPendingServices.remove(i);
                    }
                }
            }
        } catch (RemoteException ex) {
            // pm is in same process, this will never happen.
        }
    }
    if (r != null) {
        // 各种检查: 包括防火墙,权限等
        ...
        return new ServiceLookupResult(r, null);
    }
    return null;
}

4.3 getServiceMapLocked

private ServiceMap getServiceMapLocked(int callingUser) {
    ServiceMap smap = mServiceMap.get(callingUser);
    if (smap == null) {
        smap = new ServiceMap(mAm.mHandler.getLooper(), callingUser);
        mServiceMap.put(callingUser, smap);
    }
    return smap;
}

4.4 startServiceInnerLocked

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
        boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
	// 更新ServiceState状态为started
    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();
    }
    // 拉起服务. 参考【第4.5节】
    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;
}

4.5 bringUpServiceLocked

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
        boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {
    if (r.app != null && r.app.thread != null) {
        // 如果Service已经创建,则发送启动服务消息
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }
 
    if (!whileRestarting && mRestartingServices.contains(r)) {
        // If waiting for a restart, then do nothing.
        return null;
    }
 
    // 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) {
        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)) {
        bringDownServiceLocked(r);
        return msg;
    }
 
    // Service is now being launched, its package can't be stopped.
    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) { // 非isolated进程
        // 从进程列表获取进程
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (app != null && app.thread != null) {
            app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
            // 真正启动服务. 参考【第4.6节】
            realStartServiceLocked(r, app, execInFg);
            return null;
 
            // If a dead object exception was thrown -- fall through to restart the application.
        }
    } else { // isolated进程
        // 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())) {
            hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
        }
        if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
            hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName, r.definingUid);
        }
    }
 
    // 如果进程为空,则启动进程并将ServiceRecord添加到服务队列中等待执行
    if (app == null && !permissionsReviewRequired) {
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, hostingRecord, 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");
    }
 
    // mPendingServices列表中添加服务
    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) {
            stopServiceLocked(r);
        }
    }
 
    return null;
}

4.6 realStartServiceLocked

private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
    // 设置进程
    r.setProcess(app);
    r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
 
    // services列表中添加服务
    final boolean newService = app.services.add(r);
    // 更新ServiceRecord create阶段各属性. 参考【第4.8节】
    bumpServiceExecutingLocked(r, execInFg, "create");
    // 更新lru进程信息
    mAm.updateLruProcessLocked(app, false, null);
    // 更新进程中前台服务状态等信息
    updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
    // 更新oomAdj
    mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
 
    boolean created = false;
    synchronized (r.stats.getBatteryStats()) {
        r.stats.startLaunchedLocked();
    }
    // Updates a package last used time.
    mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
    // 强制更新进程状态为PROCESS_STATE_SERVICE
    app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
    // 创建服务. 参考【5.1节】
    app.thread.scheduleCreateService(r, r.serviceInfo,
           mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
           app.getReportedProcState());
    r.postNotification();
    created = true;
 
    if (r.whitelistManager) {
        app.whitelistManager = true;
    }
 
	// 下面这段代码是bindService相关逻辑,此处只分析startService
    requestServiceBindingsLocked(r, execInFg);
    updateServiceClientActivitiesLocked(app, null, true);
    if (newService && created) {
        app.addBoundClientUidsOfNewService(r);
    }
 
    // If the service is in the started state, and there are no
    // pending arguments, then fake up one so its onStartCommand() will be called.
    // 如果pendingStarts列表为空,则将该服务对应的StartItem添加到该列表中
    if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), null, null, 0));
    }
 
    // 发送启动服务消息. 参考【第4.7节】
    sendServiceArgsLocked(r, execInFg, true);
 
    if (r.delayed) {
        getServiceMapLocked(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) {
            stopServiceLocked(r);
        }
    }
}

realStartServiceLocked主要做的事情:
(1) ApplicationThread.scheduleCreateService: 创建Service,并调用onCreate方法
(2) sendServiceArgsLocked: 启动Service,通过ApplicationThread.scheduleServiceArgs最终调用到onStartCommand

4.7 sendServiceArgsLocked

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) {
        // 从pendingStarts列表移除并取出StartItem
        ServiceRecord.StartItem si = r.pendingStarts.remove(0);
 
        // 当intent=null且pendingStarts列表存在多个待启动的Service时,直接跳过
        if (si.intent == null && N > 1) {
            continue;
        }
 
        // 更新deliver信息
        si.deliveredTime = SystemClock.uptimeMillis();
        r.deliveredStarts.add(si);
        si.deliveryCount++;
        if (si.neededGrants != null) {
            mAm.mUgmInternal.grantUriPermissionUncheckedFromIntent(si.neededGrants, si.getUriPermissionsLocked());
        }
        mAm.grantEphemeralAccessLocked(r.userId, si.intent, UserHandle.getAppId(r.appInfo.uid), UserHandle.getAppId(si.callingId));
        // 更新ServiceRecord start阶段各属性. 参考【第4.8节】
        bumpServiceExecutingLocked(r, execInFg, "start");
        // 更新oomAdj
        if (!oomAdjusted) {
            oomAdjusted = true;
            mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
        }
        if (r.fgRequired && !r.fgWaiting) {
            if (!r.isForeground) {
                // 如果启动前台服务,在调用了startForegroundService()后若当前还没有调用startForeground()
                // 则要检查startForeground()是否在规定时间内调用,超时时间为10s
                // 如果超时未调用则stopService,同时抛出ANR异常
                scheduleServiceForegroundTransitionTimeoutLocked(r);
            } else { // 如果已经调用了startForeground(), 则重置状态
                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列表中添加服务启动参数
        args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
    }
 
    ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
    // 设置列表最大数为4
    slice.setInlineCountLimit(4);
    Exception caughtException = null;
    try {
        // 启动Service.onStartCommand. 参考【第5.2节】
        r.app.thread.scheduleServiceArgs(r, slice);
    } catch (TransactionTooLargeException e) {
        caughtException = e;
    } catch (RemoteException e) {
        caughtException = e;
    } catch (Exception e) {
        caughtException = e;
    }
 
    // 异常时,做一些数据清理工作
    if (caughtException != null) {
        // Keep nesting count correct
        final boolean inDestroying = mDestroyingServices.contains(r);
        for (int i = 0; i < args.size(); i++) {
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
        }
        if (caughtException instanceof TransactionTooLargeException) {
            throw (TransactionTooLargeException)caughtException;
        }
    }
}

4.8 bumpServiceExecutingLocked

private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
    // Services within the system server won't start until SystemServer
    // does Looper.loop(), so we shouldn't try to start/bind to them too early in the boot
    // process. However, since there's a little point of showing the ANR dialog in that case,
    // let's suppress the timeout until PHASE_THIRD_PARTY_APPS_CAN_START.
 
    // Too early to start/bind service in system_server: Phase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START
    // 在Phase < PHASE_THIRD_PARTY_APPS_CAN_START之前,不检查服务启动超时
    boolean timeoutNeeded = true;
    if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START)
            && (r.app != null) && (r.app.pid == android.os.Process.myPid())) {
        timeoutNeeded = false;
    }
 
    // 设置ServiceRecord各属性
    long now = SystemClock.uptimeMillis();
    if (r.executeNesting == 0) {
        r.executeFg = fg;
        // 设置ServiceState状态为executing
        ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
        }
	    // 添加到executingServices列表
        if (r.app != null) {
            r.app.executingServices.add(r);
            r.app.execServicesFg |= fg;
            if (timeoutNeeded && r.app.executingServices.size() == 1) {
	            // 检查服务执行时间是否超时,超时的话会抛出ANR异常.参考【第7.1节】
                scheduleServiceTimeoutLocked(r.app);
            }
        }
    } else if (r.app != null && fg && !r.app.execServicesFg) {
        r.app.execServicesFg = true;
        if (timeoutNeeded) {
	        // 检查服务执行时间是否超时,超时的话会抛出ANR异常.参考【第7.1节】
            scheduleServiceTimeoutLocked(r.app);
        }
    }
    r.executeFg |= fg;
    r.executeNesting++;
    r.executingStart = now;
}

5.ApplicationThread

[ -> frameworks/base/core/java/android/app/ActivityThread.java ]

5.1 scheduleCreateService

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);
}

5.2 scheduleServiceArgs

// 遍历args列表并依次将每一项参数封装到ServiceArgsData,然后向H中发送消息并调用onStartCommand方法
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);
    }
}

5.3 H - CREATE_SERVICE/SERVICE_ARGS

class H extends Handler {
    ...
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case CREATE_SERVICE:
                handleCreateService((CreateServiceData)msg.obj);
                break;
            case SERVICE_ARGS:
                handleServiceArgs((ServiceArgsData)msg.obj);
                break;
            ...
        }
    }
}

5.4 handleCreateService

private void handleCreateService(CreateServiceData data) {
    // If we are getting ready to gc after going to the background, well we are back active so skip it.
    // 服务创建过程不执行GC操作
    unscheduleGcIdler();
 
    // 反射机制创建Service实例
    LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
    Service service = null;
    java.lang.ClassLoader cl = packageInfo.getClassLoader();
    service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent);
 
    // 创建ApplicationContext
    ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
    context.setOuterContext(service);
 
    // 返回或新建Application
    Application app = packageInfo.makeApplication(false, mInstrumentation);
    // attach服务到进程
    service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService());
    // 调用Service.onCreate
    service.onCreate();
    // 服务添加到mServices列表
    mServices.put(data.token, service);
 
    // 做一些服务创建后的状态更新工作
    ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}

5.5 handleServiceArgs

private void handleServiceArgs(ServiceArgsData data) {
    Service s = mServices.get(data.token);
    if (s != null) {
        if (data.args != null) {
            data.args.setExtrasClassLoader(s.getClassLoader());
            data.args.prepareToEnterProcess();
        }
        int res;
        if (!data.taskRemoved) {
            // 调用onStartCommand
            res = s.onStartCommand(data.args, data.flags, data.startId);
        } else {
            s.onTaskRemoved(data.args);
            res = Service.START_TASK_REMOVED_COMPLETE;
        }
 
        // 等待执行完成
        QueuedWork.waitToFinish();
 
        // 将服务从deliver列表移除,并设置服务stopIfKilled属性, 以及做一些其他列表移除工作
        ActivityManager.getService().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
    }
}

6.ActivityManagerService

[ -> frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java ]

6.1 serviceDoneExecuting

public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
    synchronized(this) {
        mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
    }
}

6.2 ActiveServices.serviceDoneExecutingLocked

[ -> frameworks/base/services/core/java/com/android/server/am/ActiveServices.java ]

这段代码ServiceRecord的stopIfKilled解释:参考【第7.3节】

void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
    boolean inDestroying = mDestroyingServices.contains(r);
    if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
        // 若为启动服务,从deliveredStarts中查找指定服务,并设置服务stopIfKilled属性
        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, false, 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, false, 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, 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, true);
                break;
            }
        }
        if (res == Service.START_STICKY_COMPATIBILITY) {
            r.callStart = false;
        }
    } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
        // destroy服务
        ...
    }
 
    // 做一些Service清理工作,具体实现看下面代码       
    serviceDoneExecutingLocked(r, inDestroying, inDestroying);
}

继续看下面代码:

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) {
    r.executeNesting--;
    if (r.executeNesting <= 0) {
        if (r.app != null) {
            r.app.execServicesFg = false;
            r.app.executingServices.remove(r);
            if (r.app.executingServices.size() == 0) {
                // 如果当前没有正在执行的服务,则移除SERVICE_TIMEOUT_MSG消息
                mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
            } else if (r.executeFg) {
                // Need to re-evaluate whether the app still needs to be in the foreground.
                for (int i=r.app.executingServices.size()-1; i>=0; i--) {
                    if (r.app.executingServices.valueAt(i).executeFg) {
                        r.app.execServicesFg = true;
                        break;
                    }
                }
            }
            if (inDestroying) { // 从mDestroyingServices列表移除服务
                mDestroyingServices.remove(r);
                r.bindings.clear();
            }
            // 更新oomAdj
            mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
        }
        // 重置前台执行标识位为false
        r.executeFg = false;
        if (r.tracker != null) {
            final int memFactor = mAm.mProcessStats.getMemFactorLocked();
            final long now = SystemClock.uptimeMillis();
            // 更新ServiceState状态为非执行中和非前台
            r.tracker.setExecuting(false, memFactor, now);
            r.tracker.setForeground(false, memFactor, now);
            if (finishing) {
                r.tracker.clearCurrentOwner(r, false);
                r.tracker = null;
            }
        }
        if (finishing) {
            // 从services列表移除服务
            if (r.app != null && !r.app.isPersistent()) {
                r.app.services.remove(r);
                r.app.updateBoundClientUids();
                if (r.whitelistManager) {
                    updateWhitelistManagerLocked(r.app);
                }
            }
            // process置空
            r.setProcess(null);
        }
    }
}

6.3 ServiceRecord.findDeliveredStart

[ -> frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java ]

// 根据属性id和taskRemoved从deliveredStarts列表中匹配Service, 并根据remove标识决定要不要从列表移除
public StartItem findDeliveredStart(int id, boolean taskRemoved, boolean remove) {
    final int N = deliveredStarts.size();
    for (int i=0; i<N; i++) {
        StartItem si = deliveredStarts.get(i);
        if (si.id == id && si.taskRemoved == taskRemoved) {
            if (remove) deliveredStarts.remove(i);
            return si;
        }
    }
 
    return null;
}

7.关注点

7.1 Service执行时间限制

前台服务执行时间限制是20秒,后台服务执行时间限制是200秒,否则超时会报ANR异常. 具体代码体现如下:

(1) ActiveServices.scheduleServiceTimeoutLocked

void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    if (proc.executingServices.size() == 0 || proc.thread == null) {
        return;
    }
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    mAm.mHandler.sendMessageDelayed(msg,
            proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}

// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

(2) MainHandler.SERVICE_TIMEOUT_MSG

final class MainHandler extends Handler {
    public MainHandler(Looper looper) {
        super(looper, null, true);
    }
 
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        ...
        case SERVICE_TIMEOUT_MSG: {
            mServices.serviceTimeout((ProcessRecord)msg.obj);
        } break;
        case SERVICE_FOREGROUND_TIMEOUT_MSG: {
            mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
        } break;
        ...
    }
}

(3) ActiveServices.serviceTimeout

void serviceTimeout(ProcessRecord proc) {
    String anrMessage = null;
    synchronized(mAm) {
        if (proc.isDebugging()) {
            // The app's being debugged, ignore timeout.
            return;
        }
        if (proc.executingServices.size() == 0 || proc.thread == null) {
            return;
        }
        final long now = SystemClock.uptimeMillis();
        final long maxTime =  now -
                (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
        ServiceRecord timeout = null;
        long nextTime = 0;
        for (int i=proc.executingServices.size()-1; i>=0; i--) {
            ServiceRecord sr = proc.executingServices.valueAt(i);
            if (sr.executingStart < maxTime) {
                timeout = sr;
                break;
            }
            if (sr.executingStart > nextTime) {
                nextTime = sr.executingStart;
            }
        }
        if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new FastPrintWriter(sw, false, 1024);
            pw.println(timeout);
            timeout.dump(pw, "    ");
            pw.close();
            mLastAnrDump = sw.toString();
            mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
            mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
            anrMessage = "executing service " + timeout.shortInstanceName;
        } else {
            Message msg = mAm.mHandler.obtainMessage(
                    ActivityManagerService.SERVICE_TIMEOUT_MSG);
            msg.obj = proc;
            mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
                    ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
        }
    }

    if (anrMessage != null) {
        proc.appNotResponding(null, null, null, null, false, anrMessage);
    }
}

7.2 startService和startForegroundService

https://developer.android.com/about/versions/oreo/android-8.0-changes

(1) Android 8.0之前一般通过startService启动后台服务, 当系统内存紧张情况下后台Service可能会被杀死.
如果希望Service能够长时间运行而不被杀死, 可以在通过startService启动服务后, 在Service的onStartCommand方法中调用startForeground(id, notification)将服务设置为前台服务. 比如一般的音乐播放器都是这种做法.

(2) Android 8.0之后出于资源考虑对Service做了一些限制. 比如不允许后台调用startService, 否则会报错. 启动前台服务方式变成调用startForegroundService, 之后再在Service的onStartCommand方法中调用startForeground(id, notification)将服务设置为前台服务.

(3) startService和startForegroundService共有一套代码实现, 都是调用startServiceCommon, 差别就是入参requireForeground前者为false后者为true.

// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, false, mUser);
}
 
@Override
public ComponentName startForegroundService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, true, mUser);
}

(4) Android 8.0之后启动前台服务, 会检查调用startForegroundService方法后, 是否在规定时间内调用了startForeground. 这个超时时间是10秒, 如果超时未调用则会stopService,同时抛出ANR异常. 具体代码体现如下:

4.1 ActiveServices.scheduleServiceForegroundTransitionTimeoutLocked

[ -> frameworks/base/services/core/java/com/android/server/am/ActiveServices.java ]

void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
    ...
    Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
    msg.obj = r;
    r.fgWaiting = true;
    mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT);
}

4.2 MainHandler.SERVICE_FOREGROUND_TIMEOUT_MSG

[ -> frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java ]

final class MainHandler extends Handler {
    public MainHandler(Looper looper) {
        super(looper, null, true);
    }
 
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        ...
        case SERVICE_TIMEOUT_MSG: {
            mServices.serviceTimeout((ProcessRecord)msg.obj);
        } break;
        case SERVICE_FOREGROUND_TIMEOUT_MSG: {
            mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
        } break;
        ...
    }
}

4.3 ActiveServices.serviceForegroundTimeout

[ -> frameworks/base/services/core/java/com/android/server/am/ActiveServices.java ]

void serviceForegroundTimeout(ServiceRecord r) {
    ProcessRecord app;
    synchronized (mAm) {
        if (!r.fgRequired || r.destroying) {
            return;
        }
 
        app = r.app;
        if (app != null && app.isDebugging()) {
            // The app's being debugged; let it ride
            return;
        }
 
        // startForeground()超时,stopService
        r.fgWaiting = false;
        stopServiceLocked(r);
    }
 
    // ANR调用
    if (app != null) {
        app.appNotResponding(null, null, null, null, false,
                "Context.startForegroundService() did not then call Service.startForeground(): " + r);
    }
}

7.3 onStartCommand返回值

运行于主线程

[ -> frameworks/base/core/java/android/app/Service.java ]

public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
    onStart(intent, startId);
    return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}

(1) 入参:
intent: 通过startService传进来的意图. 如果Service重启时为null
flags: Additional data about this start request
startId: A unique integer representing this specific request to start

(2) 返回值:
描述了Service被杀后,应该怎么继续启动Service.
具体体现在源码里,会影响ServiceRecord的stopIfKilled属性.

// 掩码
public static final int START_CONTINUATION_MASK = 0xf;

// 进程被杀后,不保证一定调用onStartCommand方法
public static final int START_STICKY_COMPATIBILITY = 0;

// Service启动后若所在进程被杀,则服务保留started状态但intent不保留
// 等进程启动后会自动重建Service实例并调用onStartCommand, 且此时intent为null
// 一般适用于音乐播放器等后台长时间运行场景
public static final int START_STICKY = 1;

// Service启动后若所在进程被杀,则不会自动重建Service, 需要外部主动调用startService才会新建Service实例
// 适用场景:适用于当存在内存压力时允许所在进程被杀死,且有机制主动调用startService拉起服务的场景.
// 如通过Alarm机制每隔N分钟启动一次服务这种场景.
public static final int START_NOT_STICKY = 2;

// Service启动后若所在进程被杀,则等进程启动后Service会被重建且intent会被继续转发
// 除非手动调用stopService或intent为null
public static final int START_REDELIVER_INTENT = 3;
本文原文发自 某学姐, 转载请保留出处, 谢谢.

Comments