startService启动过程-Android12

Posted xhBruce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了startService启动过程-Android12相关的知识,希望对你有一定的参考价值。

startService启动过程-android12

android12-release


时序图

1. startService启动简要流程

查看上图,startService启动简要流程如下,主要关注ActiveServices.java:启动前台服务、Service超时检查、APP进程未启动情况

Activity.startService -> ContextImpl.startService -> ContextImpl.startServiceCommon -> AMS.startService -> ActiveServices.startServiceLocked -> ActiveServices.startServiceInnerLocked -> ActiveServices.bringUpServiceLocked -> ActiveServices.realStartServiceLocked -> ApplicationThread.scheduleCreateService -> ActivityThread.handleCreateService -> Service.onCreate()

2. 启动前台服务

在 Android 8.0(API 级别 26)及更高版本中,系统会限制应用在后台运行时可以执行的操作。
以 Android 12 或更高版本为目标平台的应用无法在后台运行时启动前台服务,少数特殊情况除外。如果应用尝试在后台运行时启动前台服务,则会引发异常(少数特殊情况除外)。

2.1 Android 8.0:Service 后台定义

  系统可以区分前台和后台应用。 (用于 Service 限制目的的后台定义内存管理使用的定义不同;一个应用按照内存管理的定义可能处于后台,但按照能够启动 Service 的定义又处于前台。)如果满足以下任意条件,应用将被视为处于前台:

  • 具有可见 Activity(不管该 Activity 已启动还是已暂停)。
  • 具有前台 Service。
  • 另一个前台应用已关联到该应用(不管是通过绑定到其中一个 Service,还是通过使用其中一个内容提供程序)。 例如,如果另一个应用绑定到该应用的 Service,那么该应用处于前台:1. IME,2. 壁纸 Service,3. 通知侦听器,4. 语音或文本 Service

如果以上条件均不满足,应用将被视为处于后台。

2.1.1 startForegroundService启动前台服务


  在 Android 8.0 之前,创建前台 Service 的方式通常是先创建一个后台 Service,然后将该 Service 推到前台。 Android 8.0 有一项复杂功能:系统不允许后台应用创建后台 Service。 因此,Android 8.0 引入了一种全新的方法,即 startForegroundService(),以在前台启动新 Service。 在系统创建 Service 后,应用有5秒的时间来调用该 Service 的 startForeground() 方法以显示新 Service 的用户可见通知。 如果应用在此时间限制内未调用 startForeground(),则系统将停止此 Service 并声明此应用为 ANR。

2.2 Android 12 :Service应用无法在后台运行时启动前台服务

  除少数特殊情况外,面向Android 12(API级别31)或更高版本的应用程序在后台运行时无法启动前台服务(startForegroundService()也不允许)。如果应用程序在后台运行时尝试启动前台服务,而前台服务不满足其中一种例外情况,则系统会抛出ForegroundServiceStartNotAllowedException。
  当您的应用在后台运行时,请考虑使用 WorkManager 来计划和启动加急工作。如需完成用户请求的紧急操作,请按照精确的闹钟启动前台服务。

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

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 
    // ... ...
    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;
        
    
    // ... ...
    // 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) 
        if (DEBUG_BACKGROUND_CHECK || DEBUG_FOREGROUND_SERVICE) 
            Slog.i(TAG, "startForegroundService() but host targets "
                    + r.appInfo.targetSdkVersion + " - not requiring startForeground()");
        
        fgRequired = false;
    
    // ... ...
    return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
            allowBackgroundActivityStarts, backgroundActivityStartsToken);

3. Service超时检查

可以查看 ANR service TimeOut 超时判断
ContextImpl.startService -> ContextImpl.startServiceCommon -> AMS.startService -> ActiveServices.startServiceLocked -> ActiveServices.startServiceInnerLocked -> ActiveServices.bringUpServiceLocked -> ActiveServices.realStartServiceLocked -> ActiveServices.bumpServiceExecutingLocked -> ActiveServices.scheduleServiceTimeoutLocked

不同电在于Build.HW_TIMEOUT_MULTIPLIER(ro.hw_timeout_multiplier默认值是1)属性值可以设置SERVICE_TIMEOUT


4. APP进程未启动情况

需要mAm.startProcessLocked()启动进程,和 AMS:startActivity桌面启动应用 启动进程差不多,在ActivityManagerService.attachApplicationLocked最终调用ActiveServices.realStartServiceLocked


以上是关于startService启动过程-Android12的主要内容,如果未能解决你的问题,请参考以下文章

Android 源码分析 StartService 启动

Android 源码分析 StartService 启动

Android 源码分析 StartService 启动

Service学习笔记02-实战 startService 与bindService

Service工作过程

unbindService流程-Android12