手机常亮屏不自动灭屏

一. 基础知识介绍

  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);

}

}

相关推荐
coder_pig15 分钟前
🤡 公司Android老项目升级踩坑小记
android·flutter·gradle
死就死在补习班1 小时前
Android系统源码分析Input - InputReader读取事件
android
死就死在补习班1 小时前
Android系统源码分析Input - InputChannel通信
android
死就死在补习班1 小时前
Android系统源码分析Input - 设备添加流程
android
死就死在补习班1 小时前
Android系统源码分析Input - 启动流程
android
tom4i2 小时前
Launcher3 to Launchpad 01 布局修改
android
雨白2 小时前
OkHttpClient 核心配置详解
android·okhttp
淡淡的香烟2 小时前
Android auncher3实现简单的负一屏功能
android
RabbitYao3 小时前
Android 项目 通过 AndroidStringsTool 更新多语言词条
android·python
RabbitYao3 小时前
使用 Gemini 及 Python 更新 Android 多语言 Excel 文件
android·python