基于Android9.0(API Level: 28)源码分析。
涉及代码:
/frameworks/base/services/core/java/com/android/server/dreams/DreamManagerService.java
/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
/frameworks/base/services/core/java/com/android/server/dreams/DreamController.java
/frameworks/base/core/java/android/service/dreams/DreamService.java
/packages/apps/DeskClock/src/com/android/deskclock/Screensaver.java // 系统默认屏保service
Android屏保是什么?
可能我们从屏保画面来看会认为屏保是一个activity,但是实际上屏保画面显示是通过service显示的。屏保启动时会bind屏保service(DreamService),然后在service上创建PhoneWindow显示在画面上。具体可以用实机验证。当屏保显示时,通过adb去dumpsys window看看屏保是不是activity。
Android屏保启动方式
一、主动启动屏保。
IDreamManager mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DreamService.DREAM_SERVICE));
/** @hide */
interface IDreamManager {
void dream(); // 启动屏保
void awaken(); // 唤醒屏幕,即关闭屏保
void setDreamComponents(in ComponentName[] componentNames); // 设置屏保组件 service
ComponentName[] getDreamComponents();
ComponentName getDefaultDreamComponent();
void testDream(in ComponentName componentName);
boolean isDreaming();
void finishSelf(in IBinder token, boolean immediate);
void startDozing(in IBinder token, int screenState, int screenBrightness);
void stopDozing(in IBinder token);
}
我们如果不设置自定义屏保,则系统会使用默认屏保。
实际处理屏保的逻辑在DreamManagerService中,当调用IDreamManager的dream()接口时会走到DreamManagerService类中。
获取屏保接口涉及bind调用,对应的service在系统启动时就已经注册过了,具体注册过程:
从上述时序图2.2中会发现我们通过bind获取的mDreamManager 实际上是BinderService。我们调用dream函数时,屏保启动过程:
mDreamManager.dream()
——>PowerManagerService.nap()
——>PowerManagerService.updatePowerStateLocked()
——>PowerManagerService.canDreamLocked(){判断是否要启动屏保,其中会去读取config.xml文件,确认屏保是否支持、屏保是否打开}
——>LocalService.startDream(boolean){DreamManagerService的内部类}
——>DreamController.startDream()
——>binderService{绑定DreamService,系统屏保/自定义屏保都继承该service}
二、系统电源状态变化时启动,比如充电时、低电量等。
电源变化时PowManagerService中的updatePowerStateLocked函数会被调用,对应上述时序图中的5.1.1.1.1。
Android屏保画面
一、系统默认屏保
系统默认屏保是Screensaver,该类继承DreamService。
二、自定义屏保
- 首先创建一个service继承DreamService,在onAttachToWindow函数中设置自定义layout。
- 然后调用setDreamComponents(in ComponentName[] componentNames);接口将该service作为ComponentName对象参数传入。
- 调用dream()启动屏保。
Android屏保开关
在PowManagerService中的updatePowerStateLocked函数会调用canDreamLocked来判断是否应该启动屏保,该函数中会读取配置文件:
/frameworks/base/core/res/res/values/config.xml
<bool name="config_dreamsSupported">true</bool> // 是否支持屏保,如果设置false,则屏保功能无法打开。
<bool name="config_dreamsEnabledByDefault">true</bool> // 屏保开关,如果设置false,可以通过设定项主动打开。