zoukankan      html  css  js  c++  java
  • PowerManagerService分析

    https://blog.csdn.net/Gaugamela/article/details/52838654  Android7.0 PowerManagerService(3) 核心函数updatePowerStateLocked的主要流程

    https://mp.weixin.qq.com/s/P3IvBrYt7afEa4XyEd3BQg  PowerManagerService分析(二)

    https://blog.csdn.net/u011311586/article/details/51034313 (原创)android6.0系统 PowerManager深入分析

    Platform: RK3288
    OS: Android 7.1。2
    Kernel: 4.4.143

    一.frameworksaseservicescorejavacomandroidserverpowerPowerManagerService.java

    1.在updatePowerStateLocked()方法中,设置了一个死循环,并且上述分析的两个方法都在死循环中执行,
    为何设计一个死循环与它循环内部的实现有关系。updateWakefulnessLocked(),这个方法是退出循环的关键。
    如果这个方法返回false,则循环结束,如果返回true,则进行下一次循环

        private void updatePowerStateLocked() {
            if (!mSystemReady || mDirty == 0) {
                return;
            }
            if (!Thread.holdsLock(mLock)) {
                Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
            }
    
            Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
            try {
                // Phase 0: Basic state updates.
                updateIsPoweredLocked(mDirty);
                updateStayOnLocked(mDirty);
                updateScreenBrightnessBoostLocked(mDirty);
    
                // Phase 1: Update wakefulness.
                // Loop because the wake lock and user activity computations are influenced
                // by changes in wakefulness.
                final long now = SystemClock.uptimeMillis();
                int dirtyPhase2 = 0;
                for (;;) {
                    int dirtyPhase1 = mDirty;
                    dirtyPhase2 |= dirtyPhase1;
                    mDirty = 0;
    
                    updateWakeLockSummaryLocked(dirtyPhase1);
                    updateUserActivitySummaryLocked(now, dirtyPhase1);
                    if (!updateWakefulnessLocked(dirtyPhase1)) {
                        break;
                    }
                }
    

    2.进入休眠,实现休眠的方法  

    private boolean updateWakefulnessLocked(int dirty) {
        boolean changed = false;
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | 
            DIRTY_BOOT_COMPLETED
            | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | 
            DIRTY_PROXIMITY_POSITIVE
            | DIRTY_DOCK_STATE)) != 0) {
               //当前屏幕保持唤醒&&设备将要退出唤醒状态(睡眠or屏保)
               if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
                   Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
                   final long time = SystemClock.uptimeMillis();
                   //是否在休眠时启用屏保
                   if (shouldNapAtBedTimeLocked()) {
                      //进入屏保,返回true
                      changed = napNoUpdateLocked(time, Process.SYSTEM_UID);
                      } else {
                         //进入睡眠,返回true
                         changed = goToSleepNoUpdateLocked(time,
                         PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, 
                         Process.SYSTEM_UID);
                     }
                 }
           }
        return changed;
    }
    

    3.updateUserActivitySummaryLocked主要根据用户最后的活动来决定当前屏幕的状态。
    举个栗子,休眠的时,先变暗一下(USER_ACTIVITY_SCREEN_DIM 暗屏),再休眠

    在该函数中用mUserActivitySummary变量存储当前屏幕的状态。
    一共有3中基本状态:
    * USER_ACTIVITY_SCREEN_BRIGHT 点亮屏幕
    * USER_ACTIVITY_SCREEN_DIM 屏幕变暗
    * USER_ACTIVITY_SCREEN_DREAM 屏保状态
    从代码可以看出,屏幕变化和userActivity活动有关,它根据最后的userActivity活动的时间决定点亮屏幕、调暗屏幕或熄灭屏幕

    /**
    * Updates the value of mUserActivitySummary to summarize the user requested
    * state of the system such as whether the screen should be bright or dim.
    * Note that user activity is ignored when the system is asleep.
    */
    private void updateUserActivitySummaryLocked(long now, int dirty) {
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
                | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
            mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
     
            long nextTimeout = 0;
            if (mWakefulness == WAKEFULNESS_AWAKE
                    || mWakefulness == WAKEFULNESS_DREAMING
                    || mWakefulness == WAKEFULNESS_DOZING) {
     
                //获取进入休眠状态的时间sleepTimeout
                //getSleepTimeoutLocked中会判断休眠时间和屏幕熄灭时间的关系
                //如果休眠时间sleepTimeout小于屏幕熄灭时间screenOfftime,  
                //则休眠时间被调整为屏幕熄灭时间,因为屏幕亮屏状态下,终端不能进入休眠
                final int sleepTimeout = getSleepTimeoutLocked();
     
                //获取屏幕熄灭的时间
                final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
     
                //获取屏幕变暗的时间
                final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
     
                //当Window Manager判定用户inactive时,将此标志置为true
                final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
     
                //类似于之前的mWakeLockSummary,将当前的用户事件,转化为PMS可以处理的屏幕状态
                mUserActivitySummary = 0;
     
                //在唤醒的状态下,发生过用户事件
                if (mLastUserActivityTime >= mLastWakeTime) {
     
                    //重新计算出屏幕需要变暗的时间
                    nextTimeout = mLastUserActivityTime
                            + screenOffTimeout - screenDimDuration;
                    if (now < nextTimeout) {
                        //如果没有到达需要变暗的时间,那么当前屏幕的状态为USER_ACTIVITY_SCREEN_BRIGHT(亮屏)
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                    } else {
                        //到达变暗的时间,则计算出屏幕熄灭的时间
                        nextTimeout = mLastUserActivityTime + screenOffTimeout;
     
                        if (now < nextTimeout) {
                            //还没到熄灭的时间,则当前屏幕的状态为USER_ACTIVITY_SCREEN_DIM(暗屏)
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }
     
                //注意mUserActivitySummary为0才会进入下面的分支
                //即上面改变mUserActivitySummary的条件不满足时,才会进入这个分支(例如:唤醒状态下,没发生过改变屏幕状态的UserActivity)
                if (mUserActivitySummary == 0
                        //mLastUserActivityTimeNoChangeLights表示用户最后的活动不会改变屏幕当前的状态
                        && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
     
                    //计算下次屏幕熄灭的时间
                    nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
     
                    //还未到达熄屏时间
                    if (now < nextTimeout) {
                        if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_BRIGHT) {
                            //当前屏幕是亮屏,仍然设置为亮屏
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                        } else if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
                            //当前屏幕是变暗,仍然设置为变暗
                            mUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
                        }
                    }
                }
     
                if (mUserActivitySummary == 0) {
                    //若定义了有效的休眠时间
                    if (sleepTimeout >= 0) {
                        //计算用户最后的活动时间
                        final long anyUserActivity = Math.max(mLastUserActivityTime,
                                mLastUserActivityTimeNoChangeLights);
     
                        //只有在唤醒状态下,进行了用户活动,才会重新更新休眠时间 (此时,应该是有过用户活动,但过了息屏时间了)
                        if (anyUserActivity >= mLastWakeTime) {
                            nextTimeout = anyUserActivity + sleepTimeout;
                            if (now < nextTimeout) {
                                //走到这个分支,应该是屏幕已经熄灭,但还未到达休眠状态,先进入dream态
                                mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                            }
                        }
                    } else {
                        //直接进入dream态,后文的updateWakefulnessLocked将判断是否休眠
                        mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                        nextTimeout = -1;
                    }
                }
     
                //如果屏幕未进入dream态,但Window Manager判定用户inactive,则进入下面分支
                if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
                    //如果屏幕未熄灭
                    if ((mUserActivitySummary &
                            (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0) {
                        // Device is being kept awake by recent user activity
                        if (nextTimeout >= now && mOverriddenTimeout == -1) {
                            // Save when the next timeout would have occurred
                            mOverriddenTimeout = nextTimeout;
                        }
                    }
                    //Window Manager的权限很大,如果它判断用户inactive,直接进入dream态
                    mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
                    nextTimeout = -1;
                }
     
                //根据nextTimeOut延迟发送信息,信息被处理后,将重新调用updatePowerStateLocked,于是再次进入到该方法
                //通过不断进入该方法,不断评估是否根据用户动作亮、熄屏等
                if (mUserActivitySummary != 0 && nextTimeout >= 0) {
                    Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtTime(msg, nextTimeout);
                }
            } else {
                mUserActivitySummary = 0;
            }
            ..........
        }
    }
    

    4.isItBedTimeYetLocked()方法,该方法判断当前设备是否将要进入睡眠状态,
    返回值为对isBeKeptAwakeLocke()方法返回值取反,由mStayOn(是否屏幕常亮)、wakelockSummary、
    userActivitySummary、mProximityPositive等决定,只要满足其中之一为ture,则说明无法进入睡眠,
    也就说,要满足进入睡眠,相关属性值都为false。

       private boolean isItBedTimeYetLocked() {
            return mBootCompleted && !isBeingKeptAwakeLocked();
        }
    
    private boolean isBeingKeptAwakeLocked() {return mStayOn//屏幕是否保持常亮
        || mProximityPositive//接近传感器接近屏幕时为true
        //处于awake状态
        || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
        //屏幕处于亮屏或者dim状态
        || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
                | USER_ACTIVITY_SCREEN_DIM)) != 0            
        || mScreenBrightnessBoostInProgress;//处于亮度增强中}  

     5.updateWakeLockSummaryLocked函数根据PMS当前持有的所有WakeLock,得到当前终端整体的信息,保存到mWakeLockSummary变量中 

    /**
    * Updates the value of mWakeLockSummary to summarize the state of all active wake locks.
    * Note that most wake-locks are ignored when the system is asleep.
    */
    private void updateWakeLockSummaryLocked(int dirty) {
        //PMS持有的WakeLock发生变化,或者唤醒状态发生变化时,才重新进行更新mWakeLockSummary
        //例如:调用PMS的acquireWakeLock时,就会将dirty的DIRTY_WAKE_LOCKS位置1
        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
            mWakeLockSummary = 0;
    
            final int numWakeLocks = mWakeLocks.size();
            for (int i = 0; i < numWakeLocks; i++) {
                final WakeLock wakeLock = mWakeLocks.get(i);
    
                //这里只关注WakeLock的level
                //下面的代码其实就是实现每个level WakeLock对应的注释信息
                switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
                    case PowerManager.PARTIAL_WAKE_LOCK:
                        //在分析PMS acquireWakeLock的流程时,已经提到过
                        //在doze模式下,不在白名单内的非系统应用申请PARTIAL_WAKE_LOCK时,将被disabled
                        if (!wakeLock.mDisabled) {
                            // We only respect this if the wake lock is not disabled.
                            mWakeLockSummary |= WAKE_LOCK_CPU;
                        }
                        break;
                    case PowerManager.FULL_WAKE_LOCK:
                        mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
                        break;
                    case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                        mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
                        break;
                    case PowerManager.SCREEN_DIM_WAKE_LOCK:
                        mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
                        break;
                    case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                        mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
                        break;
                    case PowerManager.DOZE_WAKE_LOCK:
                        mWakeLockSummary |= WAKE_LOCK_DOZE;
                        break;
                    case PowerManager.DRAW_WAKE_LOCK:
                        mWakeLockSummary |= WAKE_LOCK_DRAW;
                        break;
                }
            }
    
            // Cancel wake locks that make no sense based on the current state.
            //从下面的代码可以看出,PMS中的mWakefulness变量记录了终端当前的状态
            //下面就是移除在特定状态下,没有意义的WakeLock
            if (mWakefulness != WAKEFULNESS_DOZING) {
                //如果不是Dozing状态,移除相应的wakeLock标志位
                mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
            }
            if (mWakefulness == WAKEFULNESS_ASLEEP
                    || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
                //如果当前为Asleep或者有Doze的wakeLock锁的时候,应该移除掉屏幕亮度相关的wakeLock锁
                mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
                        | WAKE_LOCK_BUTTON_BRIGHT);
                if (mWakefulness == WAKEFULNESS_ASLEEP) {
                    //休眠时,sensor不再需要监听终端是否靠近物体,以触发亮灭屏
                    mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
                }
            }
    
            // Infer implied wake locks where necessary based on the current state.
            //根据当前的状态,及PMS持有的WakeLock,推断出隐含的持锁需求
            //例如:当PMS持有亮屏锁WAKE_LOCK_SCREEN_BRIGHT时,若当前终端为唤醒态
            //那么CPU显然也需要处于唤醒态
            if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
                if (mWakefulness == WAKEFULNESS_AWAKE) {
                    mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
                } else if (mWakefulness == WAKEFULNESS_DREAMING) {
                    mWakeLockSummary |= WAKE_LOCK_CPU;
                }
            }
            if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
                mWakeLockSummary |= WAKE_LOCK_CPU;
            }
            ...................
        }
    }
    

                                                        Android6.0 Wakelock类型

    锁类型

    cpu

    screen

    Keyboard

    电源键影响

        应用情景

                                备注

    PARTIAL_WAKE_LOCK = 0x00000001

    On

    Off

    Off

    不受

    听音乐,后台下载等

    SCREEN_DIM_WAKE_LOCK = 0x00000006

    On

    Dim

    Off

    即将进入灭屏休眠状态时

    这三种类型的锁,在6.0以后版本会逐渐被抛弃使用,改用WindowManager. LayoutParams 的一个参数FLAG_KEEP_SCREEN_ON 来替换上述三种类型的锁,因为它将由平台被准确地管理用户应用程序之间的动作,并且不需要特殊的权限。

    SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a

    On

    Bright

    Off

    看电子书,看视频,操作屏幕没有操作到键盘等

    FULL_WAKE_LOCK = 0x0000001a

    On

    Bright

    On

    来电话,闹钟触发等

    PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020

    Off

    Bright/Off

    Off

    打电话靠近或远离手机时

    需要设备支持距离传感器,不能和ACQUIRE_CAUSES_WAKEUP一起用

    DOZE_WAKE_LOCK = 0x00000040

    Off

    Off

    Off

    低电状态,doze模式下,允许cpu进入suspend状态

    系统支持doze

    DRAW_WAKE_LOCK = 0x00000080

    On

    Off

    Off

    不受

    保持设备唤醒,能正常进行绘图

    windowManager允许应用在dozing状态绘制屏幕

    ACQUIRE_CAUSES_WAKEUP = 0x10000000

    说明:正常情况下,获取wakelock是不会唤醒设备的,加上该标志之后,acquire wakelock也会唤醒设备,该标志常用于闹钟触发,蓝牙链接提醒等场景。

    不能和PARTIAL_WAKE_LOCK 一起用

    ON_AFTER_RELEASE = 0x20000000

    说明:和用户体验有关,当wakelock释放后如果没有该标志,屏幕会立即黑屏,如果有该标志,屏幕会亮一小会然后在黑屏。

    不能和PARTIAL_WAKE_LOCK 一起用

    二.RK3288 android  HDMI 休眠

    diff --git a/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java b/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
    index d38a942..93ff2a1 100755
    --- a/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
    +++ b/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
    @@ -93,6 +93,8 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
     //FOR CEC
     import android.hardware.hdmi.*;
     import android.os.ServiceManager;
    +import java.io.File;
    +import java.util.Scanner;
     
     
     /**
    @@ -1628,6 +1630,25 @@ public final class PowerManagerService extends SystemService
             }
         }
     
    +	private static boolean isHdmiSwitchSet() {
    +
    +		File switchFile = new File("/sys/devices/virtual/switch/hdmi/state");
    +		if (!switchFile.exists()) {
    +			switchFile = new File("/sys/class/switch/hdmi/state");
    +		}
    +		try {
    +			Scanner switchFileScanner = new Scanner(switchFile);
    +			int switchValue = switchFileScanner.nextInt();
    +			switchFileScanner.close();
    +			return switchValue > 0;
    +		} catch (Exception e) {
    +			return false;
    +		}
    +	}
    +
    +
    +
    +
         /**
          * Updates the value of mWakeLockSummary to summarize the state of all active wake locks.
          * Note that most wake-locks are ignored when the system is asleep.
    @@ -1642,7 +1663,13 @@ public final class PowerManagerService extends SystemService
                 final int numWakeLocks = mWakeLocks.size();
                 for (int i = 0; i < numWakeLocks; i++) {
                     final WakeLock wakeLock = mWakeLocks.get(i);
    -                switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
    +				int  xhmFlags;
    +				if(isHdmiSwitchSet()) {
    +				   xhmFlags = 1; 
    +				}else { 			
    +			       xhmFlags = wakeLock.mFlags;
    +				}
    +                switch (xhmFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
                         case PowerManager.PARTIAL_WAKE_LOCK:
                             if (!wakeLock.mDisabled) {
                                 // We only respect this if the wake lock is not disabled.
    

      

  • 相关阅读:
    【每日日报】第五十三天安装My SQL
    【每日日报】第五十一天jsp
    【每日日报】第五十四天
    JDK安装和卸载
    JDK的卸载和安装
    【每日日报】第五十二天
    【每日日报】第五十六天
    基于图书管理系统的查
    Android学习——day5
    每日日报2020.7.26 1905
  • 原文地址:https://www.cnblogs.com/crushgirl/p/13668452.html
Copyright © 2011-2022 走看看