Service-概述

Post on Nov 01, 2022 by Wei Lin

概述

前台与后台服务区别

(1) 显示界面

前台Service会一直有一个运行的通知在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。该通知的生命周期和service一样,无法自动消失。


(2) Android 8.0的限制策略

Android 8.0之后,后台应用不能开启后台Service,但可以开启前台Service。


(3) 开启方式

开启后台service时只需要调用startService(intent)即可。

开启前台Service需要调用startForegroundService(),然后Service在5s内调用startForeground(),否则会发生ANR。


(4) 优先级

前台Service的系统优先级更高、不易被回收;


(5) ANR时间

前台Service的ANR时间为20s。

前台Service的ANR时间为200s。

后台Service的运行限制

Google官方文档对后台Service的运行说明如下:

处于前台时,应用可以自由创建和运行前台与后台 Service。 进入后台时,在一个持续数分钟的时间窗内,应用仍可以创建和使用 Service。在该时间窗结束后,应用将被视为处于空闲状态。此时,系统将停止应用的后台Service,就像应用已经调用 Service 的 Service.stopSelf() 方法一样。

在这些情况下,后台应用将被置于一个临时白名单中并持续数分钟。 位于白名单中时,应用可以无限制地启动 Service,并且其后台 Service 也可以运行。


但其它Android厂商并不一定完全按照以上方法,通常对后台运行根据当前系统情况或自定义进行一些改变。

service标签属性

service-element——developer.android

相关类

相关类介绍

类名 功能
ActivityManagerService Android核心服务,负责四大组件的启动,切换,调度等工作。
ActivityThread 管理应用程序进程的主线程执行相关操作。
ActiveServices 负责管理和调度应用程序的Service的一个关键类。
AppBindRecord 描述一个Service与Client application的关联。
ConnectionRecord 描述了一个bindService的连接。
IntentBindRecord 记录一个Intent与其对应的Service的关系。
Service APP可以使用的类,通过继承它实现自己的Service。
ServiceMap 保存对应userId下的ServiceRecord
ServiceRecord Service在系统中的保存对象

简写:

ActivityManagerService - AMS

ActivityThread - AT

ActiveServices - AS

ServiceRecord类

四大组件之ServiceRecord——gityuan

表示一个运行中的Service。在AS.retrieveServiceLocked()中构建。

相关属性 说明
ComponentName name Service的类名
Intent.FilterComparison intent 原始intent,可用于搜索Service
ServiceInfo serviceInfo Service的相关信息,如权限、flags等
ApplicationInfo appInfo Service所属APP的相关信息
int userId 在该userId下运行
ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings 记录绑定到该Service的intent信息
ArrayMap<IBinder, ArrayList> connections 记录通过bindService绑定到该intent的信息
ProcessRecord app 所属应用进程信息
Notification foregroundNoti 前台Service对应的前台通知

ActiveServices类

​ ActiveServices是负责管理和调度应用程序的Service的一个关键类。通过 ActiveServices 的管理,系统能够高效地运行和管理应用程序中的服务,提供良好的用户体验和系统性能。

相关属性 说明
SparseArray mServiceMap 保存所有userId对应的ServiceMap
ArrayMap<IBinder, ArrayList> mServiceConnections 当前已建立链接的Service,以IBinder为Key
ArrayList mPendingServices 收到启动请求,即将启动的Service
ArrayList mRestartingServices Service崩溃后,等待重启的Service列表
ArrayList mDestroyingServices 即将被销毁的Service列表
待补充  

其主要作用如下。

(1) 服务生命周期管理

​ ActiveServices 负责跟踪和管理应用程序中运行的服务的生命周期。它负责启动、停止和销毁服务,并确保它们按照正确的生命周期顺序执行。


(2) 服务调度和优先级管理

​ ActiveServices 根据服务的优先级和调度规则来决定服务的运行顺序和调度策略。它根据应用程序和系统的需求,动态分配和管理服务的资源。


(3) 后台服务管理

​ ActiveServices 管理后台服务的行为和限制。它确保后台服务在系统资源有限的情况下合理使用资源,并根据优先级和系统策略进行调整和限制。


(4) 绑定服务管理

​ ActiveServices 跟踪和管理应用程序中的绑定服务。它处理绑定服务的连接和断开,并处理客户端与服务之间的通信和交互。


(5) 服务通信和消息处理

​ ActiveServices 提供了服务间的通信机制,用于服务之间的相互调用和消息传递。它充当了服务间的中间件,促进了应用程序组件之间的通信。

ServiceMap类

Base on: Android 13

Branch: android-13.0.0_r30

/**
 * Information about services for a single user.
 */
final class ServiceMap extends Handler {...}

ServiceMap是ActiveServices的一个内部类。其主要作用是保存每个userId下的ServiceRecord(每个userId有一个ServiceMap实例)。并且继承了Handler,可以接收消息并执行相关调度。

相关属性 说明
ArrayMap<ComponentName, ServiceRecord> mServicesByInstanceName 存储系统中运行的Service,Key为服务类名
ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent 存储系统中运行的Service,Key为FilterComparison(与intent相关)
ArrayList mDelayedStartList 未知
ArrayList mStartingBackground 未知
ArrayMap<String, ActiveForegroundApp> mActiveForegroundApps 未知

ConnectionRecord类

绑定一个服务会在客户端传入一个ServiceConnection,ConnectionRecord可以简单理解为AMS中对应客户端的ServiceConnection。ConnectionRecord描述了一个bindService的连接。

在绑定服务时的AS.bindServiceLocked()中创建该对象。

final AppBindRecord binding;    // The application/service binding.
final ActivityServiceConnectionsHolder<ConnectionRecord> activity;  // If non-null, the owning activity.
final IServiceConnection conn;  // The client connection.
final int flags;                // Binding options.
final int clientLabel;          // String resource labeling this client.
final PendingIntent clientIntent; // How to launch the client.
final int clientUid;            // The identity of this connection's client
final String clientProcessName; // The source process of this connection's client
final String clientPackageName; // The source package of this connection's client
public AssociationState.SourceState association; // Association tracking
String stringName;              // Caching of toString.
boolean serviceDead;            // Well is it?
private Object mProcStatsLock;  // Internal lock for accessing AssociationState

dumpsys中的ConnectionRecord记录如下

All Connections:
  ConnectionRecord{e5754c1 u0 CR com.demoapp.servicedemo/.MyService:@d3241a8}

AppBindRecord类

描述一个Service与Client application的关联。

在通过bindService()绑定到Service时于AS.retrieveAppBindingLocked()创建AppBindRecord对象。

final ServiceRecord service;    // The running service.
final IntentBindRecord intent;  // The intent we are bound to.
final ProcessRecord client;     // Who has started/bound the service.

final ArraySet<ConnectionRecord> connections = new ArraySet<>();
                                // All ConnectionRecord for this client.

intent:绑定该Service时传入的intent;

client:表示绑定当前Service的客户端进程;

connections: 记录了某一个客户端进程与当前Service的所有bind连接信息,一个进程中可能会有多个组件绑定同一个Service,所以一个进程会有多个ConnectionRecord信息。

IntentBindRecord类

bindService(intent, mConnection, flag)时的intent参数,IntentBindRecord就是用来记录一个Intent与其对应的Service的关系。

/** The running service. */
final ServiceRecord service;
/** The intent that is bound.*/
final Intent.FilterComparison intent; // 
/** All apps that have bound to this Intent. */
final ArrayMap<ProcessRecord, AppBindRecord> apps
        = new ArrayMap<ProcessRecord, AppBindRecord>();
/** Binder published from service. */
IBinder binder;
/** Set when we have initiated a request for this binder. */
boolean requested;
/** Set when we have received the requested binder. */
boolean received;
/** Set when we still need to tell the service all clients are unbound. */
boolean hasBound;
/** Set when the service's onUnbind() has asked to be told about new clients. */
boolean doRebind;

String stringName;      // caching of toString

apps:可能有多个不同的进程使用同一个intent(指action, data, type, class, categories等全部相同)来bindService(),所以使用ArrayMap<ProcessRecord, AppBindRecord> apps来记录客户端进程与绑定到的Service之间的关系。


关于intent的不同的比较:

public boolean filterEquals(Intent other) {
    if (other == null) {
        return false;
    }
    if (!Objects.equals(this.mAction, other.mAction)) return false;
    if (!Objects.equals(this.mData, other.mData)) return false;
    if (!Objects.equals(this.mType, other.mType)) return false;
    if (!Objects.equals(this.mIdentifier, other.mIdentifier)) return false;
    if (!(this.hasPackageEquivalentComponent() && other.hasPackageEquivalentComponent())
            && !Objects.equals(this.mPackage, other.mPackage)) {
        return false;
    }
    if (!Objects.equals(this.mComponent, other.mComponent)) return false;
    if (!Objects.equals(this.mCategories, other.mCategories)) return false;

    return true;
}

不会比较putExtra()中数据的不同。

注:Intent.FilterComparison是一个用于比较intent是否相同的内部类。