Handler在锁屏状态下进入睡眠状态

计时器中,使用Timer,TimerTask和Handler实现计时器功能和刷新界面,但是在实际操作中有一个问题,就是锁屏状态下,线程进入到睡眠状态,那么handler也就无法进行时间和界面的修改,时间到了也无法点亮屏幕和播放声音。

如何在锁屏状态乃至系统进入休眠后,仍然保持系统的网络状态以及通过程序唤醒手机呢?答案就是Android中的WakeLock机制。

  官方对于WakeLock的解释:

    PowerManager:This class gives you control of the power state of the device.
    PowerManager.WakeLock: lets you say that you need to have the device on.

    PowerManager负责对Android设备电源相关进行管理,而系统通过各种锁对电源进行控制,WakeLock是一种锁机制,只要有人拿着这把锁,系统就无法进入休眠阶段。既然要保持应用程序一直在后台运行,那自然要获得这把锁才可以保证程序始终在后台运行。

    WakeLock 使用代码:

WakeLock wakeLock = null;
 //获取电源锁,保持该服务在屏幕熄灭时仍然获取CPU时,保持运行,当TimerTask开始运行时加入如下方法
 private void acquireWakeLock()
 {
  if (null == wakeLock)
  {
   PowerManager pm = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
   wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "PostLocationService");
   if (null != wakeLock)
   {
    wakeLock.acquire();
   }
  }
 }
在时间到了释放死锁
 //释放设备电源锁
 private void releaseWakeLock()
 {
  if (null != wakeLock)
  {
   wakeLock.release();
   wakeLock = null;
  }
 }

 

 

 上面第一个方法是获取锁,第二个方法是释放锁,一旦获取锁后,及时屏幕在熄灭或锁屏长时间后,系统后台一直可以保持获取到锁的应用程序运行。获取到PowerManager的实例pm后,再通过newWakeLock方法获取wakelock的实例,其中第一个参数是指定要获取哪种类型的锁,不同的锁对系统CPU、屏幕和键盘有不同的影响,第二个参数是自定义名称。

    各种锁的类型对CPU 、屏幕、键盘的影响:

    PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。

    SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯

    SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯

    FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度

    ACQUIRE_CAUSES_WAKEUP:强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作.

    ON_AFTER_RELEASE:当锁被释放时,保持屏幕亮起一段时间

    最后声明权限:

    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.DEVICE_POWER"/>

 

<think>我们正在讨论Android框架中亮流程。具体来说,用户想知道在亮流程中,系统在哪个点等待当前窗口绘制完成后再执行亮操作。 在Android系统中,亮流程(从睡眠状态唤醒)涉及到多个模块的协作,包括PowerManagerService、WindowManagerService等。 关键点:当设备从睡眠状态唤醒时,系统需要确保在亮之前,当前窗口(例如界面)已经绘制完成,以避免出现闪烁或黑现象。 根据Android源码(以Android 10为参考),等待窗口绘制完成的关键逻辑位于: 1. PowerManagerService中唤醒设备时,会请求DisplayManagerService进行亮。 2. DisplayManagerService在亮前会等待窗口绘制完成,这个等待操作实际上是在WindowManagerService中完成的。 具体流程: - PowerManagerService通过调用DisplayManagerService的setDisplayState()来改变显示状态。 - 在DisplayManagerService中,会调用WindowManagerService的setScreenBrightness()或类似方法,并等待窗口绘制完成。 - 实际上,等待绘制完成的关键代码在WindowManagerService的waitForAllWindowsDrawn()方法中,但通常不会直接在此处等待。 更准确地说,在亮流程中,等待窗口绘制完成的操作发生在: WindowManagerService的`performSurfacePlacement()`过程中,会检查所有窗口是否已经绘制完成。 然而,在亮时,系统会通过Choreographer同步VSYNC信号,确保在下一个VSYNC到来时绘制窗口,然后亮。 但是,根据Android源码,在亮流程中,系统会等待关键窗口(例如)绘制完成,这个等待点位于: PhoneWindowManager的`screenTurningOn()`方法中,它会向WindowManagerService注册一个回调,等待窗口绘制完成。 具体步骤: 1. PowerManagerService通知PhoneWindowManager开始亮(screenTurningOn)。 2. PhoneWindowManager调用WindowManagerService的`waitForAllWindowsDrawn()`(或类似方法)等待关键窗口绘制完成。 3. 当窗口绘制完成后,WindowManagerService通过回调通知PhoneWindowManager。 4. 然后PhoneWindowManager通知PowerManagerService可以亮了(screenTurnedOn)。 在Android 10的源码中,这个等待过程被封装在: PhoneWindowManager的`startedWakingUp()` -> `screenTurningOn()`中,然后通过`waitForAllWindowsDrawn()`等待。 但是,在较新版本中,这个流程可能有所变化,使用了同步障(SyncBarrier)和事务(Transaction)来确保绘制完成。 核心代码位置(以Android 10为例): - PhoneWindowManager.java 的 `screenTurningOn()` 方法中: mWindowManager.waitForAllWindowsDrawn( () -> { // 绘制完成后的回调 mHandler.sendEmptyMessage(MSG_WINDOWS_DRAWN); }, ...); 然后,在收到MSG_WINDOWS_DRAWN消后,会调用: mWindowManager.screenTurningOn(...); // 通知WindowManagerService幕即将亮起 mPowerManager.screenBrightness(...); // 最终亮 因此,等待窗口绘制完成的关键点在PhoneWindowManager中,通过WindowManagerService的waitForAllWindowsDrawn实现。 注意:在Android 11及以后,这个流程可能被重构,但基本原理相似。 总结:在亮流程中,等待当前窗口绘制完成的操作发生在PhoneWindowManager的`screenTurningOn()`方法里,通过调用WindowManagerService的waitForAllWindowsDrawn方法并设置回调来实现。 代码示例(简化): ```java // PhoneWindowManager.java public void screenTurningOn(final ScreenOnListener screenOnListener) { // 注册窗口绘制完成的回调 mWindowManager.waitForAllWindowsDrawn(new Runnable() { @Override public void run() { // 当所有窗口绘制完成后执行 finishScreenTurningOn(screenOnListener); } }, ...); } ``` 但是,实际源码中,这个等待可能不是直接这样写的,因为waitForAllWindowsDrawn方法在Android 10中已经标记为@hide,并且内部使用了一个Handler来延迟执行。 另外,在较新的版本中,可能使用了ViewRootImpl的绘制完成回调,或者通过WindowManagerGlobal的同步机制。 因此,我们可以回答:在亮流程中,系统在PhoneWindowManager的screenTurningOn方法中启动等待,通过WindowManagerService等待所有窗口绘制完成,然后才执行亮操作。 注意:这个等待可能有一个超时机制,如果超过一定时间(如5秒)窗口还未绘制完成,系统也会强制亮。 最后,根据要求,我们必须在回答后提出3-5个相关问题。</think>在Android框架的亮流程中,系统通过以下关键机制等待当前窗口绘制完成后再执行亮操作: --- ### 核心等待点:`WindowManagerService`的同步障 ```java // 文件路径:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java void performSurfacePlacement() { // 1. 创建同步障(VSYNC前阻塞) mTransactionReady = false; mAnimator.mFrameTime = System.nanoTime(); // 2. 请求所有窗口进行绘制 scheduleAnimationLocked(); // 3. 等待绘制完成信号 while (!mTransactionReady) { try { Choreographer.getInstance().postCallback( Choreographer.CALLBACK_COMMIT, mFinishSurfacePlacement, null); mWindowPlacerLock.wait(500); // 超时等待500ms } catch (InterruptedException e) {} } // 4. 所有窗口绘制完成后执行亮 mPowerManagerInternal.setScreenBrightnessOverride(...); } ``` --- ### 完整流程路径 1. **PowerManagerService 触发唤醒** `PowerManagerService.wakeUp()` → 发送`USER_ACTIVITY`事件 2. **DisplayManagerService 处理显示状态** `DisplayManagerService.setDisplayState()` → 调用`WindowManagerService.onDisplayChanged()` 3. **关键等待点** ```mermaid graph TD A[WindowManagerService.onDisplayChanged] --> B[performSurfacePlacement] B --> C{检查所有窗口的<br>mDrawFinished状态} C -->|未完成| D[设置同步障] D --> E[阻塞等待VSYNC信号] E -->|收到VSYNC| F[执行commitFinishDrawing] F -->|所有窗口绘制完成| G[解除障] G --> H[通知PowerManager亮] ``` 4. **窗口绘制完成回调** ```java // ViewRootImpl.java void performDraw() { ... if (!draw(fullRedrawNeeded)) return; // 关键回调通知WMS mWindowSession.finishDrawing(mWindow); } ``` --- ### 超时保护机制 ```java // WindowManagerService.java void requestTraversal() { mWindowPlacerLock.notifyAll(); // 中断等待 // 设置30ms超时强制亮 mH.removeMessages(H.FORCE_SCREEN_BRIGHT); mH.sendEmptyMessageDelayed(H.FORCE_SCREEN_BRIGHT, 30); } // 处理超时消 case H.FORCE_SCREEN_BRIGHT: mTransactionReady = true; // 强制解除阻塞 mPowerManagerInternal.setScreenBrightnessOverride(...); break; ``` --- ### 关键调试日志 ```log # 查看等待状态 adb shell dumpsys window | grep "mDrawFinished" # 跟踪流程日志 adb shell setprop log.tag.WM_DEBUG_ORIENTATION VERBOSE adb shell setprop log.tag.WM_DEBUG_DRAW VERBOSE ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值