概述
前台与后台服务区别
(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类
表示一个运行中的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 |
记录通过bindService绑定到该intent的信息 |
| ProcessRecord app | 所属应用进程信息 |
| Notification foregroundNoti | 前台Service对应的前台通知 |
ActiveServices类
ActiveServices是负责管理和调度应用程序的Service的一个关键类。通过 ActiveServices 的管理,系统能够高效地运行和管理应用程序中的服务,提供良好的用户体验和系统性能。
| 相关属性 | 说明 |
|---|---|
| SparseArray |
保存所有userId对应的ServiceMap |
| ArrayMap<IBinder, ArrayList |
当前已建立链接的Service,以IBinder为Key |
| ArrayList |
收到启动请求,即将启动的Service |
| ArrayList |
Service崩溃后,等待重启的Service列表 |
| ArrayList |
即将被销毁的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 |
未知 |
| ArrayList |
未知 |
| 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是否相同的内部类。