从系统看startService的生命周期

基础知识

完整的客户端生命周期:onCreate() → onStartCommand() → stopService → onDestroy()
如果存在多个client启动同一个service, 只需一个client便可以stop该服务

ServiceRecord的一些属性

    boolean startRequested; // 是否是start方式启动,首次在startServiceInnerLocked中赋值
    boolean fgRequired;     // 是否是前台service,在startServiceInnerLocked中赋值
    long lastActivity;      // service的上次活跃时间,在startServiceInnerLocked或bindServiceLocked中赋值
    boolean delayedStop;    //首次启动或绑定赋值为false,stopServiceLocked中如果delayed则赋值为true
   // start() arguments which been delivered.
    final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
   // start() arguments that haven't yet been delivered.
   // startServiceInnerLocked 中会添加,即sendServiceArgsLocked之前添加
    final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
    final Runnable restarter; // used to schedule retries of starting the service
    boolean delayed;        // are we waiting to start this service in the background?

ServiceMap介绍

继承自Handler,每个用户空间都有对应的ServiceMap对象

        final int mUserId; //对应用户空间的id
        // 通过ComponentName保存的service map
        final ArrayMap<ComponentName, ServiceRecord> mServicesByInstanceName = new ArrayMap<>(); 
        // 通过intent保存的service map
        final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new ArrayMap<>();
        final ArrayList<ServiceRecord> mDelayedStartList = new ArrayList<>();

ActiveServices的一些属性

    private ArrayMap<ServiceRecord, ArrayList<Runnable>> mPendingBringups = new ArrayMap<>();
     final ArrayList<ServiceRecord> mPendingServices = new ArrayList<>();
    final ArrayList<ServiceRecord> mRestartingServices = new ArrayList<>();

startService的流程

app端流程

app端调用startService方法最终会调用ContextImpl的startServiceCommon

// requireForeground表示是否启动前台service
    private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            // binder到system server端执行
            ComponentName cn = ActivityManager.getService().startService(
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                    getOpPackageName(), getAttributionTag(), user.getIdentifier());
            if (cn != null) {
            // 根据system server端返回的特殊packageName抛出不同的异常
                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 ServiceStartNotAllowedException.newInstance(requireForeground,
                            "Not allowed to start service " + service + ": " + cn.getClassName());
                }
            }
            return cn;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

在这里插入图片描述

8-10 是进程不存在时才执行,且中间省略了进程创建的流程
12-16 Service的onCreate流程
11-17 是Service不存在时才执行,即service存在app端只用执行onStartCommand方法
18-23 Service的onStartCommand流程

system server端流程

AMS.startService:
    @Override
    public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, boolean requireForeground, String callingPackage,
            String callingFeatureId, 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");
        }

        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res;
            try {
            // system server端service相关的流程都交给ActiveServices类处理
                res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, callingFeatureId, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
            return res;
        }
    }
ActiveServices.startServiceLocked
  1. 参数解释:
  • caller: 发起startService进程对应的IApplicationThread对象
  • service:要启动的service的intent
  • callingPid:调用方进程id
  • callingUid:调用方uid
  • fgRequired:要启动的service是否是前台
  • callingPackage:调用方包名
  • allowBackgroundActivityStarts: 这里为false
  • backgroundActivityStartsToken:这里为null
  • userId:当前用户id
  1. 流程
  • 获取caller是否处于前台,赋值callerFg
  • retrieveServiceLocked 检索得到Service实例
  • 一些前台或后台启动的权限校验
  • 非前台caller&非前台service ,procState在PROCESS_STATE_SERVICE之上或进程不存在,则设置addToStarting为true,startServiceInnerLocked 方法中会用到这个变量
  • 非前台caller&非前台service,procState在PROCESS_STATE_RECEIVER之上或进程不存在,如果mStartingBackground 列表大小超过mMaxStartingBackground,则当前service添加到mDelayedStartList列表,当前service延迟启动,mMaxStartingBackground值若没有通过属性设置,低内存设备为1,否则为8
  • 调用startServiceInnerLocked
  1. 返回null
  • 没有查到要启动的service
  • userId不存在
  • mAllowStartForeground
  • APP_START_MODE_DELAYED || forceSilentAbort
  • 不在电池优化白名单的前台service(service app在后台)
  1. 返回特殊包名
  • 调用方和被调用方不允许建立连接,ServiceLookupResult中ServiceRecord为null,返回包名为"!"的componentName
    "Service lookup failed: "+ "association not allowed between packages " + callingPackage + " and " + name.getPackageName();
  • 不允许后台启动,返回包名为"?", "app is in background uid " + uidRec
    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired,
            String callingPackage, @Nullable String callingFeatureId, final int userId,
            boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
            throws TransactionTooLargeException {

        final boolean callerFg;
         // app端startService调用过来的caller都不为null
        if (caller != null) {
            final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller);
            // 通过IApplicationThread对象获取system server端进程实例,进程不存在则抛出安全异常
            if (callerApp == null) {
                throw new SecurityException(
                        "Unable to find app for caller " + caller
                        + " (pid=" + callingPid
                        + ") when starting service " + service);
            }
            // 获取caller是否在前台
            callerFg = callerApp.mState.getSetSchedGroup() != ProcessList.SCHED_GROUP_BACKGROUND;
        } else {
        // 通过PendingIntent的INTENT_SENDER_FOREGROUND_SERVICE启动时,也判定caller为前台
            callerFg = true;
        }
       // 拿到要启动的service的信息,通过pms查询缓存起来,权限校验
        ServiceLookupResult res =
            retrieveServiceLocked(service, null, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false, false);
         // 没有查到要启动的service,直接返回null
        if (res == null) {
            return null;
        }
        // 没有对应的service record,返回包名为"!"的componentName
        if (res.record == null) {
            return new ComponentName("!", res.permission != null
                    ? res.permission : "private to package");
        }
        // 拿到system server端代表service的实例
        ServiceRecord r = res.record;
        // 前台service的限制
        setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId,
                allowBackgroundActivityStarts);
        // userId不存在则直接返回null
        if (!mAm.mUserController.exists(r.userId)) {
            Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
            return null;
        }

        // 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.
        // 判断要启动的service所在app是否处于非活跃状态,如果进程的procState < 8,则在后台超过1min则会进入idle状态。
        final boolean bgLaunch = !mAm.isUidActiveLOSP(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.
        boolean forcedStandby = false;
        // 如果service所在app处于后台状态且该app不在电池优化白名单(系统app默认在),将forcedStandby赋值为true
        if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
            forcedStandby = true;
        }
       // S上新增代码
        if (fgRequired) {
            logFgsBackgroundStart(r);
            if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
                String msg = "startForegroundService() not allowed due to "
                        + "mAllowStartForeground false: service "
                        + r.shortInstanceName;
                Slog.w(TAG, msg);
                showFgsBgRestrictedNotificationLocked(r);
                logFGSStateChangeLocked(r,
                        FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED,
                        0);
                if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, callingUid)) {
                    throw new ForegroundServiceStartNotAllowedException(msg);
                }
                return null;
            }
        }

        // If this is a direct-to-foreground start, make sure it is allowed as per the app op.
        // ops权限校验

        // If this isn't a direct-to-foreground start, check our ability to kick off an
        // arbitrary service
        // 1. 要启动的不是前台service
        // 2.service对应的app不活跃且不在电池优化白名单
        // 则需要进行后台启动限制校验
        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.
            // 获取service所在app是否允许启动后台service
            final int allowed = mAm.getAppStartModeLOSP(r.appInfo.uid, r.packageName,
                   r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
            // android o+后台启动都会打印这个log
                Slog.w(TAG, "Background start not allowed: service "
                        + service + " to " + r.shortInstanceName
                        + " from pid=" + callingPid + " uid=" + callingUid
                        + " pkg=" + callingPackage + " startFg?=" + fgRequired);
                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.
                    // 1. service所在app处于后台,2. service为前台service 3. app不在电池优化白名单
                    // 返回null
                    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.
                // 不允许后台启动,返回包名为"?"的component
                UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(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+.
        if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
            fgRequired = false;
        }

        // The package could be frozen (meaning it's doing surgery), defer the actual
        // start until the package is unfrozen.
        // 延迟service的启动和绑定,直到package解冻。S上新增的逻辑
        if (deferServiceBringupIfFrozenLocked(r, service, callingPackage, callingFeatureId,
                callingUid, callingPid, fgRequired, callerFg, userId, allowBackgroundActivityStarts,
                backgroundActivityStartsToken, false, null)) {
            return null;
        }

        // 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.

        // XXX This is not dealing with fgRequired!
        if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage, callingFeatureId,
                callingUid, service, callerFg, userId, false, null)) {
            return null;
        }

        return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
                allowBackgroundActivityStarts, backgroundActivityStartsToken);
    }
ActiveServices.retrieveServiceLocked

首先通过intent或component尝试从service map中获取实例,不存在则创建新的service实例并put到service map中。

  • 检索 service,存在则获取,不存在则创建
  • startServiceInnerLocked
  • 如果addToStarting 为true,添加Service到mStartingBackground列表,并设置service的startingBgTimeout 时间为15s后
  1. 返回null的情况
  • 校验包可见性失败,打印Unable to start service " + service + " U=" + userId + “: not found”
  • 没有缓存service且从pms中查询不到,“Unable to start service " + service + " U=” + userId +": not found"
  1. 返回的ServiceLookupResult中ServiceRecord为null:
  • 检查调用方和被调用方能否建立联系,不能则返回的ServiceLoockupResult中service为null
  • service未向外暴露,exported属性为false
  • 相关权限校验未过
    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,
                /* allowAll= */false, getAllowMode(service, callingPackage),
                /* name= */ "service", callingPackage);
       // 获取对应用户空间的service map
        ServiceMap smap = getServiceMapLocked(userId);
        final ComponentName comp;
        if (instanceName == null) {
                // 通过intent获取componentName
            comp = service.getComponent();
        } else {
            final ComponentName realComp = service.getComponent();
            if (realComp == null) {
                throw new IllegalArgumentException("Can't use custom instance name '" + instanceName
                        + "' without expicit component in Intent");
            }
            // instanceName不为空,重组ComponetName
            comp = new ComponentName(realComp.getPackageName(),
                    realComp.getClassName() + ":" + instanceName);
        }
        // ComponentName不为null,先通过component查询是否有对应的service
        if (comp != null) {
            r = smap.mServicesByInstanceName.get(comp);
        }
        // isBindExternal 表示必须通过外部绑定,这里为false
        // 通过component查询不到,则通过intent去查询
        if (r == null && !isBindExternal && instanceName == null) {
            Intent.FilterComparison filter = new Intent.FilterComparison(service);
            r = smap.mServicesByIntent.get(filter);
        }
        if (r != null) {
            // Compared to resolveService below, the ServiceRecord here is retrieved from
            // ServiceMap so the package visibility doesn't apply to it. We need to filter it.
            // 校验缓存的service的包可见性,S上新增
            if (mAm.getPackageManagerInternal().filterAppAccess(r.packageName, callingUid,
                    userId)) {
                Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId
                        + ": not found");
                return null;
            }
            // 如果设置了FLAG_EXTERNAL_SERVICE且是外部调用,不允许复用缓存的service
            if ((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;
                }
                // 从pms中查询
                ResolveInfo rInfo = mAm.getPackageManagerInternal().resolveService(service,
                        resolvedType, flags, userId, callingUid);
                ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null;
                // 查询不到,返回null,打印相关log
                if (sInfo == null) {
                    Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
                          ": not found");
                    return null;
                }
               
                if (instanceName != null
                        && (sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
                    throw new IllegalArgumentException("Can't use instance name '" + instanceName
                            + "' with non-isolated service '" + sInfo.name + "'");
                }
                // 封装componentName
                ComponentName className = new ComponentName(
                        sInfo.applicationInfo.packageName, sInfo.name);
                ComponentName name = comp != null ? comp : className;
                // 检查调用方和被调用方能否建立联系,不能则返回的ServiceLoockupResult中service为null
                if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid,
                        name.getPackageName(), sInfo.applicationInfo.uid)) {
                    String msg = "association not allowed between packages "
                            + callingPackage + " and " + name.getPackageName();
                    Slog.w(TAG, "Service lookup failed: " + msg);
                    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).
                String definingPackageName = sInfo.applicationInfo.packageName;
                int definingUid = sInfo.applicationInfo.uid;
                // FLAG_EXTERNAL_SERVICE 相关校验
                .........
                if (userId > 0) {
                // 非主用户空间,要启动的service是单例
                    if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
                            sInfo.name, sInfo.flags)
                            && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
                        userId = 0;
                        smap = getServiceMapLocked(0);
                        // Bypass INTERACT_ACROSS_USERS permission check
                        final long token = Binder.clearCallingIdentity();
                        try {
                            ResolveInfo rInfoForUserId0 =
                                    mAm.getPackageManagerInternal().resolveService(service,
                                            resolvedType, flags, userId, callingUid);
                            if (rInfoForUserId0 == null) {
                                Slog.w(TAG_SERVICE,
                                        "Unable to resolve service " + service + " U=" + userId
                                                + ": not found");
                                return null;
                            }
                            // 重新获取snfo
                            sInfo = rInfoForUserId0.serviceInfo;
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }
                    sInfo = new ServiceInfo(sInfo);
                    sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
                }
                // 通过Componet再获取一次Service
                r = smap.mServicesByInstanceName.get(name);
                // start或bind时createIfNeede均为true
                if (r == null && createIfNeeded) {
                    final Intent.FilterComparison filter
                            = new Intent.FilterComparison(service.cloneFilter());
                    final ServiceRestarter res = new ServiceRestarter();
                    // 第一次启动创建Service
                    r = new ServiceRecord(mAm, className, name, definingPackageName,
                            definingUid, filter, sInfo, callingFromFg, res);
                    res.setService(r);
                    // 将当前service实例通过intent和component put到service map中
                    smap.mServicesByInstanceName.put(name, r);
                    smap.mServicesByIntent.put(filter, r);

                    // Make sure this component isn't in the pending list.
                    // 因为正在启动service,所以将当前service信息从pending列表中移除
                    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);
                        }
                    }
                    for (int i = mPendingBringups.size() - 1; i >= 0; i--) {
                        final ServiceRecord pr = mPendingBringups.keyAt(i);
                        if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
                                && pr.instanceName.equals(name)) {
                            mPendingBringups.removeAt(i);
                        }
                    }
                }
            } catch (RemoteException ex) {
                // pm is in same process, this will never happen.
            }
        }
        if (r != null) {
            r.mRecentCallingPackage = callingPackage;
            r.mRecentCallingUid = callingUid;
            try {
                r.mRecentCallerApplicationInfo =
                        mAm.mContext.getPackageManager().getApplicationInfoAsUser(callingPackage,
                                0, UserHandle.getUserId(callingUid));
            } catch (PackageManager.NameNotFoundException e) {
            }
            // 一些各种权限校验
            if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName,
                    r.appInfo.uid)) {
                String msg = "association not allowed between packages "
                        + callingPackage + " and " + r.packageName;
                Slog.w(TAG, "Service lookup failed: " + msg);
                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) {
                    Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName
                            + " 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.shortInstanceName
                        + " from pid=" + callingPid
                        + ", uid=" + callingUid
                        + " requires " + r.permission);
                return new ServiceLookupResult(null, r.permission);
            } else if (Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission)
                    && callingUid != Process.SYSTEM_UID) {
                // Hotword detection must run in its own sandbox, and we don't even trust
                // its enclosing application to bind to it - only the system.
                // TODO(b/185746653) remove this special case and generalize
                Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName
                        + " from pid=" + callingPid
                        + ", uid=" + callingUid
                        + " requiring permission " + r.permission
                        + " can only be bound to from the system.");
                return new ServiceLookupResult(null, "can only be bound to "
                        + "by the system.");
            } else if (r.permission != null && callingPackage != null) {
                final int opCode = AppOpsManager.permissionToOpCode(r.permission);
                if (opCode != AppOpsManager.OP_NONE && mAm.getAppOpsManager().checkOpNoThrow(
                        opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
                    Slog.w(TAG, "Appop Denial: Accessing service " + r.shortInstanceName
                            + " from pid=" + callingPid
                            + ", uid=" + callingUid
                            + " requires appop " + AppOpsManager.opToName(opCode));
                    return null;
                }
            }
            return new ServiceLookupResult(r, null);
        }
        return null;
    }
ActiveServices.startServiceInnerLocked
    private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
            int callingUid, int callingPid, boolean fgRequired, boolean callerFg,
            boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
            throws TransactionTooLargeException {
        NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
                service, callingUid, r.packageName, r.userId);
          //取消service重启相关的调度
        if (unscheduleServiceRestartLocked(r, callingUid, false)) {
        }
        // 给相关属性赋值
        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;
        // 调用者处于后台,启动后台service,且service对应的进程未赋值或不存在
        if (!callerFg && !fgRequired && r.app == null
                && mAm.mUserController.hasStartedUserState(r.userId)) {
            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid);
            // service对应进程不存在或procState > 11
            if (proc == null || proc.mState.getCurProcState() > PROCESS_STATE_RECEIVER) {
                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;
                }
                addToStarting = true;
            } else if (proc.mState.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
 
                addToStarting = true;
            } 
        } 
        if (allowBackgroundActivityStarts) {
            r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken);
        }
        // 调用重载方法
        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
        return cmp;
    }

ActiveServices.startServiceInnerLocked

返回packageName为"!!"情况,bringUpServiceLocked返回不为null

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
       
        r.callStart = false;

        final int uid = r.appInfo.uid;
        final String packageName = r.name.getPackageName();
        final String serviceName = r.name.getClassName();
        // 真正拉起service的地方
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg,
                false /* whileRestarting */,
                false /* permissionsReviewRequired */,
                false /* packageFrozen */,
                true /* enqueueOomAdj */);
        /* Will be a no-op if nothing pending */
        mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
        if (error != null) {
            return new ComponentName("!!", error);
        }
       // start方式后台启动
        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;
    }
ActiveServices.bringUpServiceLocked
  • 若Service已经存在,则直接通过sendServiceArgsLocked 让客户端Service回调onStartCommand方法
  • 从restart list中移除当前service; 取消service的delay ;设置package的stop状态为false
  • 进程存在则直接调用realStartServiceLocked去继续下面的操作
  • 进程不存在,创建进程,并把service添加到mPendingServices,等创建进程时再start
    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
            boolean enqueueOomAdj)
            throws TransactionTooLargeException {
            //service的app已经被赋值,说明被启动过,thread不为空代表进程存在
            // 直接post app端执行onStartCommand逻辑
            // 没有错误信息,返回null
        if (r.app != null && r.app.getThread() != null) {
            sendServiceArgsLocked(r, execInFg, false);
            return null;
        }
       // Service正在重启,直接返回
        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.
        // 当前正在拉起service,从重启列表中移除当前service
        if (mRestartingServices.remove(r)) {
            clearRestartingIfNeededLocked(r);
        }
       // 正在启动,移除delay相关信息
        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.
        // user 状态有问题,返回错误信息
        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, enqueueOomAdj);
            return msg;
        }
        // 正在启动service,package状态不能为stopped
        // 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;
        // 进程启动会用到,表明启动进程的原因
        HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
        ProcessRecord app;
       // 不是孤岛service
        if (!isolated) {
        // 获取service所在进程实例
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
            // service所在进程存在,直接执行app端service的onCreate前期处理
            if (app != null) {
                final IApplicationThread thread = app.getThread();
                final int pid = app.getPid();
                final UidRecord uidRecord = app.getUidRecord();
                if (thread != null) {
                    try {
                        app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode,
                                mAm.mProcessStats);
                        realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
                                enqueueOomAdj);
                        return null;
                    } catch (TransactionTooLargeException e) {
                        throw e;
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
                    }

                    // If a dead object exception was thrown -- fall through to
                    // restart the application.
                }
            }
        } 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);
            }
        }

        // Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.
        // 进程不存在,先去拉起进程
        if (app == null && !permissionsReviewRequired && !packageFrozen) {
            // TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service
            //  was initiated from a notification tap or not.
            // app短期crash多次,返回null
            if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                        hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated)) == 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, enqueueOomAdj);
                return msg;
            }
            if (isolated) {
                r.isolatedProc = app;
            }
        }

        if (r.fgRequired) {
            mAm.tempAllowlistUidLocked(r.appInfo.uid,
                    SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH,
                    "fg-service-launch",
                    TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
                    r.mRecentCallingUid);
        }
        // service放入pending列表,等进程启动后处理
        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, enqueueOomAdj);
            }
        }

        return null;
    }
ActiveServices.realStartServiceLocked
  • 真正启动Service的地方,拉起app的service实例,bindservice也会调到这个方法
  • 给service实例设置app,restartTime,lastActivity等
  • 更新oomadj,reason为OOM_ADJ_REASON_START_SERVICE
  • 告知app create service,执行Service的onCreate方法,并post"create"超时消息
  • 告知app start service,执行Service的onStartCommand方法,并post “start”超时消息
    private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
            IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
            boolean enqueueOomAdj) throws RemoteException {
        if (thread == null) {
            throw new RemoteException();
        }
        // 给service设置进程,代表当前servce执行了onCreate方法
        r.setProcess(app, thread, pid, uidRecord);
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
       // 获取当前进程的所有service信息
        final ProcessServiceRecord psr = app.mServices;
        // 将当前service添加到ProcessServiceRecord中
        final boolean newService = psr.startService(r);
        // 超时逻辑
        bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
        // 更新ams的lru list
        mAm.updateLruProcessLocked(app, false, null);
        updateServiceForegroundLocked(psr, /* oomAdj= */ false);
        // Force an immediate oomAdjUpdate, so the client app could be in the correct process state
        // before doing any service related transactions
        // 更新进程优先级
        mAm.enqueueOomAdjTargetLocked(app);
        mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);

        boolean created = false;
        try {
     
            final int uid = r.appInfo.uid;
            final String packageName = r.name.getPackageName();
            final String serviceName = r.name.getClassName();
            mAm.mBatteryStatsService.noteServiceStartLaunch(uid, packageName, serviceName);
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
           // post app端去执行create service流程
            thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.mState.getReportedProcState());
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app, "Died when creating service");
            throw e;
        } finally {
            if (!created) {
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying, false);

                // Cleanup.
                if (newService) {
                    psr.stopService(r);
                    r.setProcess(null, null, 0, null);
                }

                // Retry.
                if (!inDestroying) {
                    scheduleServiceRestartLocked(r, false);
                }
            }
        }

        if (r.allowlistManager) {
            psr.mAllowlistManager = true;
        }

        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(psr, null, true);

        if (newService && created) {
            psr.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.
        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));
        }
       // post app端去执行onStartCommand流程
        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, enqueueOomAdj);
            }
        }
    }
ActiveServices.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) {
            ServiceRecord.StartItem si = r.pendingStarts.remove(0);
       
            if (si.intent == null && N > 1) {
                // If somehow we got a dummy null intent in the middle,
                // then skip it.  DO NOT skip a null intent when it is
                // the only one in the list -- this is to support the
                // onStartCommand(null) case.
                continue;
            }
            si.deliveredTime = SystemClock.uptimeMillis();
            r.deliveredStarts.add(si);
            si.deliveryCount++;
            if (si.neededGrants != null) {
                mAm.mUgmInternal.grantUriPermissionUncheckedFromIntent(si.neededGrants,
                        si.getUriPermissionsLocked());
            }
            mAm.grantImplicitAccess(r.userId, si.intent, si.callingId,
                    UserHandle.getAppId(r.appInfo.uid)
            );
            bumpServiceExecutingLocked(r, execInFg, "start", null /* oomAdjReason */);
            if (r.fgRequired && !r.fgWaiting) {
                if (!r.isForeground) {
                    if (DEBUG_BACKGROUND_CHECK) {
                        Slog.i(TAG, "Launched service must call startForeground() within timeout: " + r);
                    }
                    scheduleServiceForegroundTransitionTimeoutLocked(r);
                } else {
                    if (DEBUG_BACKGROUND_CHECK) {
                        Slog.i(TAG, "Service already foreground; no new timeout: " + r);
                    }
                    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));
        }

        if (!oomAdjusted) {
            mAm.enqueueOomAdjTargetLocked(r.app);
            mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
        }
        ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
        slice.setInlineCountLimit(4);
        Exception caughtException = null;
        try {
            r.app.getThread().scheduleServiceArgs(r, slice);
        } catch (TransactionTooLargeException e) {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large for " + args.size()
                    + " args, first: " + args.get(0).args);
            Slog.w(TAG, "Failed delivering service starts", e);
            caughtException = e;
        } catch (RemoteException e) {
            // Remote process gone...  we'll let the normal cleanup take care of this.
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
            Slog.w(TAG, "Failed delivering service starts", e);
            caughtException = e;
        } catch (Exception e) {
            Slog.w(TAG, "Unexpected exception", e);
            caughtException = e;
        }

        if (caughtException != null) {
            // Keep nesting count correct
            final boolean inDestroying = mDestroyingServices.contains(r);
            for (int i = 0, size = args.size(); i < size; i++) {
                serviceDoneExecutingLocked(r, inDestroying, inDestroying, true);
            }
            /* Will be a no-op if nothing pending */
            mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
            if (caughtException instanceof TransactionTooLargeException) {
                throw (TransactionTooLargeException)caughtException;
            }
        }
    }

三、stopService的流程

如果存在多个client启动同一个service, 只需一个client便可以stop该服务
1、Service外部stop
在这里插入图片描述
stopServiceLocked
如果service是delay的,则设置service的delayedStop 为true,在Service被拉起的时候stop
2、service 内部stop
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值