AOD相关机制

AOD的概念:

                   AOD,即A(lways) O(n) D(isplay)是android一种低功耗的显示模式的一种应用,他能保证屏幕某块区域一直亮,该应用开启时绘制的频率会低于正常的频率。由于AOD现实的不是和正常的亮屏之后显示的一样,只                   会显示非黑色的部分,而且频率低于正常的频率 ,所以即使一直在显示功耗也比较低。

       AOD进程的流程: 

           AOD是一个应用,主要是通过DreamManagerService来切换DOZE、DOZE_SUSPEND实现AOD的进入、退出和显示。 如图一 transitionTo开始进入到setDozeScreenState结束,而DreamService也就是DreamServiceManager的               代理,后面就开始到了DreamServiceManager里面来做了。

     DreamManager和DreamManagerService

         在DreamManager里面是通过updateDoze 从而调用到PowerManagerService里面的mSandman.startDozing方法来和DreamManagerService通讯的,此处调用逻辑简单看下源码就知道。

         在DreamManagerService中,我们以进入DOZE状态为例,分析下调用流程。在进入DOZE的时候最重要的方法是

            

private void startDozingInternal(IBinder token, int screenState,
225            int screenBrightness) {
226        if (DEBUG) {
227            Slog.d(TAG, "Dream requested to start dozing: " + token
228                    + ", screenState=" + screenState
229                    + ", screenBrightness=" + screenBrightness);
230        }
231
232        synchronized (mLock) {
233            if (mCurrentDreamToken == token && mCurrentDreamCanDoze) {
234                mCurrentDreamDozeScreenState = screenState;
235                mCurrentDreamDozeScreenBrightness = screenBrightness;
236                mPowerManagerInternal.setDozeOverrideFromDreamManager(
237                        screenState, screenBrightness);//设置亮度
238                if (!mCurrentDreamIsDozing) {
239                    mCurrentDreamIsDozing = true;
240                    mDozeWakeLock.acquire();//申请一个DozeWakeLock的锁
241                }
242            }
243        }
244    }

这个方法中其实最重要的就是设置一个亮度,申请一个锁。
    先说亮度:这个亮度screenBrightness最终将通过PowerManagerService的mDozeScreenBrightnessOverrideFromDreamManager封装成一个request,给PowerManagerService和DisplayManagerServices交互的类DisplayPowerController
然后在recordBrightnessChange方法中通过binder直接给surface底层,从而把这个亮度给设置进去。
    前面说过状态的切换最重要的是申请一个DozeWakeLock锁,这个锁定义如下:
   mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
    这个锁对应的类型未   public static final int DOZE_WAKE_LOCK = OsProtoEnums.DOZE_WAKE_LOCK; // 0x00000040
   也就是说申请了0x00000040的锁,熟悉PowerManagerServices的同学都知道,这个锁最终会和用户行为一起合成一个drity,在getDesiredScreenPolicyLocked方法里计算出一个最终的policy给DisplayPowerController,
最终在DisplayPowerState里面将状态设置成为对应的状态(在这里要注意的是brightness原生流程中也是在DisplayPowerState里面去设置的,但是因为我们将传统的亮度和doze的亮度两个节点在底层分开了,所以doze的亮度是通过
recordBrightnessChange,利用binder直接和底层通信,将亮度设置进去的,具体的J1/J2 AOD节点移植方案)。
    我们看可以看下getDesiredScreenPolicyLocked里面DOZE在是如何影响影响policy的
2    int getDesiredScreenPolicyLocked() {
2703       。。。。。。
2707        if (mWakefulness == WAKEFULNESS_DOZING) {
2708            if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
2709                return DisplayPowerRequest.POLICY_DOZE;//policy的状态为doze
2710            }
2711           。。。。
2737
2738        return DisplayPowerRequest.POLICY_DIM;
2739    }

  如果当前状态为WAKEFULNESS_DOZINGmWakeLockSummary里面有WAKE_LOCK_DOZE时当前policy就是DOZE

private static final int WAKE_LOCK_DOZE = 1 << 6;
前面DOZE_WAKE_LOCK是十进制的64,WAKE_LOCK_DOZE换成10进制也是64,换句话说进入DOZE状态的途径之一就是申请DOZE_WAKE_LOCK锁。
既然是途径之一还有什么方法可以进入DOZE状态能,通过源码我们发现,如果当前是本来就是POLICY_DOZE且有WAKE_LOCK_DRAW锁,这个时候回将dozeScreenState变成DOZE状态
private boolean updateDisplayPowerStateLocked(int dirty) {
2592       。。。。。。
2626            if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
2627                mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
2628                if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0
2629                        && !mDrawWakeLockOverrideFromSidekick) {
2630                    if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
2631                        mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;//display为doze状态
2632                    }
2633                    if (mDisplayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
2634                        mDisplayPowerRequest.dozeScreenState = Display.STATE_ON;
2635                    }
2636                }
2637        。。。。。。。。。。。。
2665        return mDisplayReady && !oldDisplayReady;
2666    }

要通过dozeScreenState来进入DOZE,在源码中还有一种情况就是dozeScreenStateSTATE_UNKNOWN状态,这个时候会用dozeScreenState的状态,但这种情况进入DOZE的会比较少。
 private void updatePowerState() {
780        。。。。。
831            case DisplayPowerRequest.POLICY_DOZE:
832                if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
833                    state = mPowerRequest.dozeScreenState;
834                } else {
835                    state = Display.STATE_DOZE;
836                }
837                if (!mAllowAutoBrightnessWhileDozingConfig) {
838                    brightness = mPowerRequest.dozeScreenBrightness;
839                    mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE);
840                }
841                break;
               。。。。。。
842         }
    那如何切成DOZE_SUSPEND的呢,对应用(如指纹)会使用AOD暴露给他们的接口fireAodState,调到AOD的流程里,而AOD那边也是通过setDozeScreenState方法切成DOZE_SUSPEND同时应用(如指纹)释放DOZE_WAKE_LOCK锁的时候,CPU会
挂起,再通过DreamManagerService将mDozeScreenBrightnessOverrideFromDreamManager然后进入DOZE_SUSPEND状态,这里就不贴代码了,对应的log如下,

01-17 21:47:17.348 29499 29514 D PowerManagerService: acquireWakeLockInternal: lock=158204803, flags=0x80, tag="gxzw", ws=null, uid=1000, pid=29873  // 申请
01-17 21:47:17.356 29499 29809 I LocalDisplayAdapter: setDisplayState(id=0, state=DOZE)  // DOZE_SUSPEND -> DOZE
01-17 21:47:17.665 29499 30650 D PowerManagerService: releaseWakeLockInternal: lock=158204803 [gxzw], flags=0x10000  // 释放
01-17 21:47:17.672 29499 29809 I LocalDisplayAdapter: setDisplayState(id=0, state=DOZE_SUSPEND)  // DOZE -> DOZE_SUSPEND
01-17 21:47:18.882 29499 29514 D PowerManagerService: acquireWakeLockInternal: lock=206718903, flags=0x80, tag="Window:AOD", ws=WorkSource{1000 com.miui.aod}, uid=1000, pid=29499
01-17 21:47:18.899 29499 29809 I LocalDisplayAdapter: setDisplayState(id=0, state=DOZE)
01-17 21:47:19.019 29499 29499 D PowerManagerService: releaseWakeLockInternal: lock=206718903 [Window:AOD], flags=0x10000
01-17 21:47:19.023 29499 29809 I LocalDisplayAdapter: setDisplayState(id=0, state=DOZE_SUSPEND)
01-17 21:47:22.412 29499 30650 D PowerManagerService: acquireWakeLockInternal: lock=258767652, flags=0x80, tag="Window:gxzw_anim", ws=WorkSource{1000 com.android.systemui}, uid=1000, pid=29499
01-17 21:47:22.416 29499 29809 I LocalDisplayAdapter: setDisplayState(id=0, state=DOZE)
01-17 21:47:22.423 29499 30103 D PowerManagerService: acquireWakeLockInternal: lock=158204803, flags=0x80, tag="gxzw", ws=null, uid=1000, pid=29873
01-17 21:47:22.749 29499 29809 I LocalDisplayAdapter: setDisplayState(id=0, state=DOZE_SUSPEND)

 

      关于DOZE,DOZE_SUSPEND的切换还有另外一种情况就是在LocalDisplayAdapter.java中,如果两次发下来的都是DOZE_SUSPEND,这个时候会在requestDisplayStateLocked方法里面切成DOZE,这也是很多时候把指纹等一些应用关掉之后,没有任何进程在上层切换,也会来回切的原因,这是Google原生的逻辑,最好还是别在这里动刀,这样设计的目的估计也是因为下两次联系的DOZE_SUSPEND的可能性非常小,下了两次就肯定是要做其他的事情(如修改亮度),这个时候就不能在DOZE_SUSPEND下修改了。

分析方法

在AOD的分析过程中,更多的是底层发现问题,fw层定位问题,给出解决方案,上层修改问题。
总的来说就是找到根本原因,上层能改就尽量上层改。
对于问题首先要确定上层的状态指令已经下到fw层,也就是先确定有类似的08-15 23:54:38.412 3482 3482 W DozeScreenState: applyScreenState: setDozeScreenState 4,如果没有则可以先让AOD排查下逻辑是否正常;
如果有指令下发,则需要排查是否底层和上层应用的一些状态没有对上。
还有一种情况就是有一些机制Google和底层并没有打成一致的协议,如底层要求DOZE_SUSPEND下不去绘制,但Google并没有任何机制去保证,对于某些屏也没有做限制.
当然更多的还是具体问题具体分析,这里也只能按照往常分析fw问题的方式,先确定下到底是哪里的问题(即有没有对应的log),不同的问题还要根据不同团队的能力给出不同的解决方案。

 

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
AOD-Net中的pix注意力机制是一种用于增强图像细节的技术。它通过对图像的每个像素应用注意力权重来突出重要的细节。下面是一个示例代码,演示了如何在AOD-Net中使用pix注意力机制: ```python import torch import torch.nn as nn class PixAttention(nn.Module): def __init__(self, in_channels): super(PixAttention, self).__init__() self.conv = nn.Conv2d(in_channels, 1, kernel_size=1) self.sigmoid = nn.Sigmoid() def forward(self, x): attention = self.conv(x) attention = self.sigmoid(attention) return attention class AODNet(nn.Module): def __init__(self): super(AODNet, self).__init__() # 定义其他网络层... self.attention = PixAttention(in_channels=64) def forward(self, x): # 前向传播过程... attention_map = self.attention(x) enhanced_x = x * attention_map # 返回增强后的图像 return enhanced_x # 创建AOD-Net模型实例 model = AODNet() # 将输入图像传递给模型进行处理 input_image = torch.randn(1, 3, 256, 256) # 假设输入图像大小为256x256 output_image = model(input_image) # 打印输出图像的形状 print(output_image.shape) ``` 在上述代码中,`PixAttention`是一个自定义的注意力模块,它通过一个卷积层和一个Sigmoid激活函数来生成注意力权重。`AODNet`是整个AOD-Net模型,其中包含了其他网络层和注意力模块。在前向传播过程中,输入图像经过注意力模块后,与注意力权重相乘,从而得到增强后的图像。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值