Doze 学习记录

2024-04-10 22:36
文章标签 学习 记录 doze

本文主要是介绍Doze 学习记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一. 退出doze:

  1. 收到BluetoothDevice.ACTION_ACL_CONNECTED 时:

   LAW.BR.5.1/LINUX/android/frameworks/base/apex/jobscheduler/service/java/com/android/server/deviceidle/BluetoothConstraint.java

      final BroadcastReceiver mReceiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
              if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(intent.getAction())) {
                  mLocalService.exitIdle("bluetooth");
              } else {
                  updateAndReportActiveLocked();
              }
          }
      };

2. 在notification 中 点击或者直接回复动作时:

LAW.BR.5.1/LINUX/android/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java

          public void onNotificationClick(int callingUid, int callingPid, String key,
                  NotificationVisibility nv) {

              exitIdle();

public void onNotificationDirectReplied(String key) {

exitIdle();

3. 通过耳机启动语音识别时:

LAW.BR.5.1/LINUX/android/vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java

boolean startVoiceRecognitionByHeadset(BluetoothDevice fromDevice) {

...

deviceIdleController.exitIdle("voice-command");

...

4. 在DeviceIdleController.java 中

 LAW.BR.5.1/LINUX/android/frameworks/base/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java

(1) 当充电时:

      private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
          @Override public void onReceive(Context context, Intent intent) {
              switch (intent.getAction()) {

                  case Intent.ACTION_BATTERY_CHANGED: {
                      boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
                      boolean plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
                      synchronized (DeviceIdleController.this) {

                         //有电池并且在充电
                          updateChargingLocked(present && plugged);
                      }
                  } break;
      };

      void updateChargingLocked(boolean charging) {
          if (DEBUG) Slog.i(TAG, "updateChargingLocked: charging=" + charging);
          if (!charging && mCharging) {
              mCharging = false;
              if (!mForceIdle) {
                  becomeInactiveIfAppropriateLocked();
              }
          } else if (charging) {
              mCharging = charging;
              if (!mForceIdle) {
                  mActiveReason = ACTIVE_REASON_CHARGING;
                  becomeActiveLocked("charging", Process.myUid());
              }
          }
      }

二.  触发更新交互状态:

    1. 监听亮灭屏事件触发:

                  filter = new IntentFilter();
                  filter.addAction(Intent.ACTION_SCREEN_OFF);
                  filter.addAction(Intent.ACTION_SCREEN_ON);
                  getContext().registerReceiver(mInteractivityReceiver, filter);

      private final BroadcastReceiver mInteractivityReceiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
              synchronized (DeviceIdleController.this) {
                  updateInteractivityLocked();
              }
          }
      };

2 . updateInteractivityLocked 函数解析:

      void updateInteractivityLocked() {
          // The interactivity state from the power manager tells us whether the display is
          // in a state that we need to keep things running so they will update at a normal
          // frequency.

         //若没有任何交互.

         //需要加日志,不能立刻灭屏,就会没有任何交互.
          boolean screenOn = mPowerManager.isInteractive();
          if (DEBUG) Slog.d(TAG, "updateInteractivityLocked: screenOn=" + screenOn);
          if (!screenOn && mScreenOn) {
              mScreenOn = false;

             /若不是强制强制idle
              if (!mForceIdle) {
                  becomeInactiveIfAppropriateLocked();
              }
          } else if (screenOn) {
              mScreenOn = true;

             //若不是强制进入idle并且(有屏幕锁或者等待解锁)
              if (!mForceIdle && (!mScreenLocked || !mConstants.WAIT_FOR_UNLOCK)) {
                  mActiveReason = ACTIVE_REASON_SCREEN;

                 //变成激活状态
                  becomeActiveLocked("screen", Process.myUid());
              }
          }
      } 

3 . 检测到运动:

      @Override
      public void onAnyMotionResult(int result) {
          if (DEBUG) Slog.d(TAG, "onAnyMotionResult(" + result + ")");
          if (result != AnyMotionDetector.RESULT_UNKNOWN) {
              synchronized (this) {

                 //取消sensing 的timeout 处理
                  cancelSensingTimeoutAlarmLocked();
              }
          }
          if ((result == AnyMotionDetector.RESULT_MOVED) ||
              (result == AnyMotionDetector.RESULT_UNKNOWN)) {
              synchronized (this) {

                 //检测到正在运动,则处理handleMotionDetectedLocked
                  handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, "non_stationary");
              }
          } else if (result == AnyMotionDetector.RESULT_STATIONARY) {

             // 检测到不运动
              if (mState == STATE_SENSING) {
                  // If we are currently sensing, it is time to move to locating.
                  synchronized (this) {
                      mNotMoving = true;
                      stepIdleStateLocked("s:stationary");
                  }
              } else if (mState == STATE_LOCATING) {
                  // If we are currently locating, note that we are not moving and step
                  // if we have located the position.
                  synchronized (this) {
                      mNotMoving = true;
                      if (mLocated) {
                          stepIdleStateLocked("s:stationary");
                      }
                  }
              }
          }
      }

三. 快速进入doze:

   1. 在省电模式下,是快速进入doze

                  mLocalPowerManager.registerLowPowerModeObserver(ServiceType.QUICK_DOZE,
                          state -> {
                              synchronized (DeviceIdleController.this) {
                                  updateQuickDozeFlagLocked(state.batterySaverEnabled);
                              }
                          });
                  updateQuickDozeFlagLocked(
                          mLocalPowerManager.getLowPowerState(
                                  ServiceType.QUICK_DOZE).batterySaverEnabled);

 2.  updateQuickDozeFlagLocked 函数:

      /** Updates the quick doze flag and enters deep doze if appropriate. */
      @VisibleForTesting
      void updateQuickDozeFlagLocked(boolean enabled) {
          if (DEBUG) Slog.i(TAG, "updateQuickDozeFlagLocked: enabled=" + enabled);
          mQuickDozeActivated = enabled;

         //空闲时激活快速瞌睡, 当处于STATE_IDLE 和 STATE_IDLE_MAINTENANCE状态.
          mQuickDozeActivatedWhileIdling =
                  mQuickDozeActivated && (mState == STATE_IDLE || mState == STATE_IDLE_MAINTENANCE);
          if (enabled) {
              // If Quick Doze is enabled, see if we should go straight into it.

             //如果启用了快速打瞌睡,看看我们是否应该直接进入它。
              becomeInactiveIfAppropriateLocked();
          }
          // Going from Deep Doze to Light Idle (if quick doze becomes disabled) is tricky and
          // probably not worth the overhead, so leave in deep doze if that's the case until the
          // next natural time to come out of it.

          //从深度打瞌睡到轻度空闲(如果快速打瞌睡被禁用)是很棘手的,并且可能不值得花费这些开销,所以如果是这种情况,请保持深度打瞌睡,直到下一个自然时间醒来。
      }

 四. AnyMotionDetector.java 解析:

LAW.BR.5.1/LINUX/android/frameworks/base/apex/jobscheduler/service/java/com/android/server/AnyMotionDetector.java

1. public void checkForAnyMotion: 获取加速度数据,直到我们确定 AnyMotion 状态。

      public void checkForAnyMotion() {
          if (DEBUG) {
              Slog.d(TAG, "checkForAnyMotion(). mState = " + mState);
          }

         // 当状态不是 STATE_ACTIVE
          if (mState != STATE_ACTIVE) {
              synchronized (mLock) {
                  mState = STATE_ACTIVE;
                  if (DEBUG) {
                      Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_ACTIVE.");
                  }
                  mCurrentGravityVector = null;
                  mPreviousGravityVector = null;

                  //获取wakeLock锁
                  mWakeLock.acquire();

                 //设置timeout 时间
                  Message wakelockTimeoutMsg = Message.obtain(mHandler, mWakelockTimeout);
                  mHandler.sendMessageDelayed(wakelockTimeoutMsg, WAKELOCK_TIMEOUT_MILLIS);
                  mWakelockTimeoutIsActive = true;
                  startOrientationMeasurementLocked();
              }
          }
      }

2. startOrientationMeasurementLocked 函数:

      private void startOrientationMeasurementLocked() {
          if (DEBUG) Slog.d(TAG, "startOrientationMeasurementLocked: mMeasurementInProgress=" +
              mMeasurementInProgress + ", (mAccelSensor != null)=" + (mAccelSensor != null));
          if (!mMeasurementInProgress && mAccelSensor != null) {

             //每隔40秒采样一次.
              if (mSensorManager.registerListener(mListener, mAccelSensor,
                      SAMPLING_INTERVAL_MILLIS * 1000)) {
                  mMeasurementInProgress = true;
                  mRunningStats.reset();
              }

             //设置timeout
              Message measurementTimeoutMsg = Message.obtain(mHandler, mMeasurementTimeout);
              mHandler.sendMessageDelayed(measurementTimeoutMsg, ACCELEROMETER_DATA_TIMEOUT_MILLIS);
              mMeasurementTimeoutIsActive = true;
          }
      }

3.  mMeasurementTimeout 变量

      private final Runnable mMeasurementTimeout = new Runnable() {
          @Override
          public void run() {
              int status = RESULT_UNKNOWN;
              synchronized (mLock) {
                  if (mMeasurementTimeoutIsActive == true) {
                      mMeasurementTimeoutIsActive = false;
                      if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " +
                            "data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " +
                            "orientation measurement.");

                      //停止方向检测
                      status = stopOrientationMeasurementLocked();
                      if (status != RESULT_UNKNOWN) {
                          mHandler.removeCallbacks(mWakelockTimeout);
                          mWakelockTimeoutIsActive = false;

                          //将结果返回给监听者
                          mCallback.onAnyMotionResult(status);
                      }
                  }
              }
          }
      }; 

4. mWakelockTimeout 变量:

      /** The maximum duration we will hold a wakelock to determine stationary status. */

     //设置timeout 为30秒
      private static final long WAKELOCK_TIMEOUT_MILLIS = 30000;

      private final Runnable mWakelockTimeout = new Runnable() {
          @Override
          public void run() {
              synchronized (mLock) {
                  if (mWakelockTimeoutIsActive == true) {
                      mWakelockTimeoutIsActive = false;
                      stop();
                  }
              }
          }
      };

5.  解析stop函数:

      public void stop() {
          synchronized (mLock) {
              if (mState == STATE_ACTIVE) {
                  mState = STATE_INACTIVE;
                  if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE.");
              }
              mHandler.removeCallbacks(mMeasurementTimeout);
              mHandler.removeCallbacks(mSensorRestart);
              mMeasurementTimeoutIsActive = false;
              mSensorRestartIsActive = false;
              if (mMeasurementInProgress) {
                  mMeasurementInProgress = false;

                  //反注册监听
                  mSensorManager.unregisterListener(mListener);
              }
              mCurrentGravityVector = null;
              mPreviousGravityVector = null;
              if (mWakeLock.isHeld()) {

                  //移除callback
                  mHandler.removeCallbacks(mWakelockTimeout);
                  mWakelockTimeoutIsActive = false;

                  //release wake lock
                  mWakeLock.release();
              }
          }
      }

6. getStationaryStatus 函数: 更新mStatus状态

      /*
       * Updates mStatus to the current AnyMotion status.
       */
      public int getStationaryStatus() {
          if ((mPreviousGravityVector == null) || (mCurrentGravityVector == null)) {

              //当上一个Gravity 或者当前的Gravity为null时,返回RESULT_UNKNOWN
              return RESULT_UNKNOWN;
          }
          Vector3 previousGravityVectorNormalized = mPreviousGravityVector.normalized();
          Vector3 currentGravityVectorNormalized = mCurrentGravityVector.normalized();
          float angle = previousGravityVectorNormalized.angleBetween(currentGravityVectorNormalized);
          if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle
                  + " energy = " + mRunningStats.getEnergy());
          if ((angle < mThresholdAngle) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) {

             //angle 和 Energy 都在阈值之内,则返回 RESULT_STATIONARY
              return RESULT_STATIONARY;
          } else if (Float.isNaN(angle)) {
            /**
             * Floating point rounding errors have caused the angle calcuation's dot product to
             * exceed 1.0. In such case, we report RESULT_MOVED to prevent devices from rapidly
             * retrying this measurement.
             */

             //当前面angle 是一个非数,则返回RESULT_MOVED
              return RESULT_MOVED;
          }
          long diffTime = mCurrentGravityVector.timeMillisSinceBoot -
                  mPreviousGravityVector.timeMillisSinceBoot;
          if (diffTime > STALE_MEASUREMENT_TIMEOUT_MILLIS) {
              if (DEBUG) Slog.d(TAG, "getStationaryStatus: mPreviousGravityVector is too stale at " +
                      diffTime + " ms ago. Returning RESULT_UNKNOWN.");

              //当超过阈值,则返回RESULT_UNKNOWN
              return RESULT_UNKNOWN;
          }
          return RESULT_MOVED;
      }

五.  DeviceIdleController.java 中onAnyMotionResult 解析:

      @Override
      public void onAnyMotionResult(int result) {
          if (DEBUG) Slog.d(TAG, "onAnyMotionResult(" + result + ")");
          if (result != AnyMotionDetector.RESULT_UNKNOWN) {
              synchronized (this) {

                  //取消设置传感器的timeout的alarm
                  cancelSensingTimeoutAlarmLocked();
              }
          }
          if ((result == AnyMotionDetector.RESULT_MOVED) ||
              (result == AnyMotionDetector.RESULT_UNKNOWN)) {

             //若是运行或者未知类型,则变成活跃状态. 
              synchronized (this) {
                  handleMotionDetectedLocked(mConstants.INACTIVE_TIMEOUT, "non_stationary");
              }
          } else if (result == AnyMotionDetector.RESULT_STATIONARY) {

             //针对RESULT_STATIONARY 状态
              if (mState == STATE_SENSING) {
                  // If we are currently sensing, it is time to move to locating.
                  synchronized (this) {
                      mNotMoving = true;

                      //若此时处于sensing 状态,则进入idle 状态
                      stepIdleStateLocked("s:stationary");
                  }
              } else if (mState == STATE_LOCATING) {
                  // If we are currently locating, note that we are not moving and step
                  // if we have located the position.
                  synchronized (this) {
                      mNotMoving = true;
                      if (mLocated) {

                         //若处于定位状态,则进入idle 状态.
                          stepIdleStateLocked("s:stationary");
                      }
                  }
              }
          }
      }

2 .handleMotionDetectedLocked 函数:

    处理运动检测

      void handleMotionDetectedLocked(long timeout, String type) {
          if (mStationaryListeners.size() > 0) {

              //若有mStationaryListeners的监听.

             //更新Stationary的状态.分发onDeviceStationaryChanged 事件,说明有更新
              postStationaryStatusUpdated();

             //设置timeout 时间
              scheduleMotionTimeoutAlarmLocked();
              // We need to re-register the motion listener, but we don't want the sensors to be
              // constantly active or to churn the CPU by registering too early, register after some
              // delay.

             //延迟注册运行Motion 监听
              scheduleMotionRegistrationAlarmLocked();
          }
          if (mQuickDozeActivated && !mQuickDozeActivatedWhileIdling) {
              // Don't exit idle due to motion if quick doze is enabled.
              // However, if the device started idling due to the normal progression (going through
              // all the states) and then had quick doze activated, come out briefly on motion so the
              // user can get slightly fresher content.

             //若是开启快速进入doze 开关和 没有激活mQuickDozeActivatedWhileIdling,表示没有在STATE_IDLE 和 STATE_IDLE_MAINTENANCE 状态. 则直接退出.
              return;
          }

        // 若mStationaryListeners 没有记录,则直接暂停motion检测
          maybeStopMonitoringMotionLocked();
          // The device is not yet active, so we want to go back to the pending idle
          // state to wait again for no motion.  Note that we only monitor for motion
          // after moving out of the inactive state, so no need to worry about that.
          final boolean becomeInactive = mState != STATE_ACTIVE
                  || mLightState == LIGHT_STATE_OVERRIDE;
          // We only want to change the IDLE state if it's OVERRIDE.
          becomeActiveLocked(type, Process.myUid(), timeout, mLightState == LIGHT_STATE_OVERRIDE);

         //若deep状态不是STATE_ACTIVE 或者light 状态是LIGHT_STATE_OVERRIDE ,则可以进入inativie状态
          if (becomeInactive) {
              becomeInactiveIfAppropriateLocked();
          }
      }

五. 变量:

1.  设置pending idle timeout的缩放因数: 默认值2,也是2的倍数.

        /**
         * Scaling factor to apply to current pending idle timeout each time we cycle through
         * that state.
         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
         * @see #KEY_IDLE_PENDING_FACTOR
         */
        public float IDLE_PENDING_FACTOR;

2. 设置idle timeout 的缩放因数.默认值是2,也是2的倍数.

        /**
         * Scaling factor to apply to current idle timeout each time we cycle through that state.
          * @see Settings.Global#DEVICE_IDLE_CONSTANTS
         * @see #KEY_IDLE_FACTOR
         */
        public float IDLE_FACTOR;

方案: 

1. 快速进入doze.

跳过location,sennsing 

        switch (mState) {
            case STATE_INACTIVE:
                // We have now been inactive long enough, it is time to start looking
                // for motion and sleep some more while doing so.
                startMonitoringMotionLocked();
                long delay = mConstants.IDLE_AFTER_INACTIVE_TIMEOUT;
                if (shouldUseIdleTimeoutFactorLocked()) {
                    delay = (long) (mPreIdleFactor * delay);
                }
                scheduleAlarmLocked(delay, false);

                moveToStateLocked(mConstants.isSmallBatteryDevice() ? STATE_QUICK_DOZE_DELAY : STATE_IDLE_PENDING, reason);
 

2. 是否需要location 和 sensing .

3. 当灭屏时,快速进入doze.

4. 配置亚索时间为true.

private static final boolean COMPRESS_TIME = false;

  MAX_IDLE_TIMEOUT 设置为6小时.

  MAX_IDLE_TIMEOUT = mParser.getDurationMillis(KEY_MAX_IDLE_TIMEOUT,
                        !COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L);

5. 需要将ro.config.small_battery 设置为true.

6. 调节设置time 的缩放因数为4.

7. 取消gps和network定位. 和监听motion 传感器。

1.打开doze 模式(此平台默认是关闭的)。
2. 将light doze 关闭,仅仅保留deep doze。
3. 缩短进入doze 流程。
4. 缩短doze的等待时间.
5. 忽略Sensor, location, network 的唤醒策略。

这篇关于Doze 学习记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/892341

相关文章

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

Python UV安装、升级、卸载详细步骤记录

《PythonUV安装、升级、卸载详细步骤记录》:本文主要介绍PythonUV安装、升级、卸载的详细步骤,uv是Astral推出的下一代Python包与项目管理器,主打单一可执行文件、极致性能... 目录安装检查升级设置自动补全卸载UV 命令总结 官方文档详见:https://docs.astral.sh/

统一返回JsonResult踩坑的记录

《统一返回JsonResult踩坑的记录》:本文主要介绍统一返回JsonResult踩坑的记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录统一返回jsonResult踩坑定义了一个统一返回类在使用时,JsonResult没有get/set方法时响应总结统一返回

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

java对接海康摄像头的完整步骤记录

《java对接海康摄像头的完整步骤记录》在Java中调用海康威视摄像头通常需要使用海康威视提供的SDK,下面这篇文章主要给大家介绍了关于java对接海康摄像头的完整步骤,文中通过代码介绍的非常详细,需... 目录一、开发环境准备二、实现Java调用设备接口(一)加载动态链接库(二)结构体、接口重定义1.类型

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

apache的commons-pool2原理与使用实践记录

《apache的commons-pool2原理与使用实践记录》ApacheCommonsPool2是一个高效的对象池化框架,通过复用昂贵资源(如数据库连接、线程、网络连接)优化系统性能,这篇文章主... 目录一、核心原理与组件二、使用步骤详解(以数据库连接池为例)三、高级配置与优化四、典型应用场景五、注意事

SpringBoot实现文件记录日志及日志文件自动归档和压缩

《SpringBoot实现文件记录日志及日志文件自动归档和压缩》Logback是Java日志框架,通过Logger收集日志并经Appender输出至控制台、文件等,SpringBoot配置logbac... 目录1、什么是Logback2、SpringBoot实现文件记录日志,日志文件自动归档和压缩2.1、