手机常亮屏不自动灭屏

一. 基础知识介绍

  1. WakeLock(休眠锁)

WakeLock用于保持设备的唤醒状态,有些情况下,即时用户不操作App,我们也需要保持屏幕处于唤醒状态,以保证用户体验,比如视频类APP和计步类APP,视频类APP需要屏幕一直保持常量,计步类APP要求熄屏后程序依然保持运行状态。

  1. WakeLock的多种类型:

PARTIAL_WAKE_LOCK:保持CPU正常运转,但屏幕和键盘灯都可能是关闭的。
SCREEN_DIM_WAKE_LOCK:保持CPU正常运转,允许屏幕点亮但可能屏幕被置灰,键盘灯可能是关闭的。
SCREEN_BRIGHT_WAKE_LOCK:保持CPU正常运转,允许屏幕高亮显示,键盘灯可能是关闭的。
FULL_WAKE_LOCK:保持CPU正常运转,保持屏幕高亮显示,键盘灯也保持亮度。
ACQUIRE_CAUSES_WAKEUP:强制屏幕和键盘灯亮起,这种锁针对一些必须通知用户的操作。
ON_AFTER_RELEASE:当WakeLock被释放后,继续保持屏幕和键盘灯亮起一段时间。

二. 遇到不灭屏的解决方法

  1. 方法一

使用adb shell dumpsys >dumpsys.txt

或者在bugreport.zip

或者使用命令: adb shell dumpsys power > power_dump.txt

搜索关键字:Wake Locks: 查看对应的持有对象。

实例分析:

1. 案例一

复现场景:

settings\]settings-\>display-\>screen timeout-设置15秒,15秒后手机不灭屏.(低概率)

(1) 查看dump power的信息:

Wake Locks: size=1 FULL_WAKE_LOCK 'TinnoFactory' ACQUIRE_CAUSES_WAKEUP ACQ=-55m1s400ms (uid=1000 pid=16340)

(2) 发现有持有'TinnoFactory' TAG的 wake lock (FULL_WAKE_LOCK)导致不能灭屏。

(3) 查看代码:

private static final String TAG = "TinnoFactory";

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

Log.i(TAG, "<TinnoFactoryActivity> onCreate");

PowerManager pm =(PowerManager) getSystemService(POWER_SERVICE);

wakeLock= pm.newWakeLock(PowerManager.FULL_WAKE_LOCK| PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);

wakeLock.acquire();

@Override

public void onDestroy() {

Log.d(TAG, "<TinnoFactoryActivity> onDestroy");

// Log.i(TAG, "onDestroy, reset previousMobileDataState");

// setMobileDataState(mPreviousMobileDataState);

// Log.i(TAG, "setMobileData, getMobileDataState = " + getMobileDataState());

if (wakeLock != null) {wakeLock.release();}

super.onDestroy();

}

(4) 这个应用退出来就可以恢复。

2. 案例二

复现场景:

将timeout 时间设置为15秒。在打电话界面停留超过15秒,手机不灭屏。

(1) 查看dump power的信息:

SCREEN_BRIGHT_WAKE_LOCK 'WindowManager ' ON_AFTER_RELEASE ACQ=-1m56s271ms (uid=1000 pid=1344 ws=WorkSource{10172})

(2) 发现有持有'WindowManager ' TAG,是来自uid: 10172, 通过日志发现10172是dialer应用。

(3) 分析'WindowManager' TAG,怎么持有wake lock。

使用倒序的方法找:

  1. TAG 定义:

TAG_WM 定义:

frameworks/base/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java

public class WindowManagerDebugConfig {

...

static final String TAG_WM = "WindowManager";

..

  1. 调用newWakeLock SCREEN_BRIGHT_WAKE_LOCK的地方:

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

private WindowManagerService(Context context, InputManagerService inputManager,

boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,

ActivityTaskManagerService atm, DisplayWindowSettingsProvider

displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,

Supplier<Surface> surfaceFactory,

Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {

...

mHoldingScreenWakeLock = mPowerManager.newWakeLock(

PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);

...

}

3)谁在使用mHoldingScreenWakeLock.

只要newHoldScreen不为null,若调用setHoldScreenLocked,则就会调用acquire函数.

void setHoldScreenLocked(final Session newHoldScreen) {

final boolean hold = newHoldScreen != null;

...

if (hold != state) {

if (hold) {

mHoldingScreenWakeLock.acquire();

mPolicy.keepScreenOnStartedLw();

}

..

  1. 接下来寻找是调用setHoldScreenLocked 函数

发现只有一处,是在RootWindowContainer.java 中。

frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

// "Something has changed! Let's make it correct now."

// TODO: Super long method that should be broken down...

void performSurfacePlacementNoTrace() {

...

mWmService.setHoldScreenLocked(mHoldScreen);

..

  1. 查看是谁给mHoldScreen赋值。

也是只有一处,当设置flag是FLAG_KEEP_SCREEN_ON。

android/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

/**

* @param w WindowState this method is applied to.

* @param obscured True if there is a window on top of this obscuring the display.

* @param syswin System window?

* @return True when the display contains content to show the user. When false, the display

* manager may choose to mirror or blank the display.

*/

boolean handleNotObscuredLocked(WindowState w, boolean obscured, boolean syswin) {

if (w.mHasSurface && canBeSeen) {

if ((attrFlags & FLAG_KEEP_SCREEN_ON) != 0) {

mHoldScreen = w.mSession;

mHoldScreenWindow = w;

}

(4) 在dialer 中查看是谁使用了FLAG_KEEP_SCREEN_ON 。

果真有有相应的代码,进行debug调试既可.

vendor/mediatek/proprietary/packages/apps/Dialer/java/com/android/incallui/InCallPresenter.java

private void applyScreenTimeout() {

if (screenTimeoutEnabled) {

window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

} else {

window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

}

}

相关推荐
xiangpanf2 小时前
Laravel 10.x重磅升级:五大核心特性解析
android
robotx5 小时前
安卓线程相关
android
消失的旧时光-19435 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon6 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon6 小时前
VSYNC 信号完整流程2
android
dalancon6 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户69371750013847 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android8 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才8 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶9 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle