Android 8.0 手机亮灭屏

本文主要跟踪分析Android系统中按Power键唤醒和熄灭屏幕的逻辑。介绍了PowerManagerService、DisplayPowerController等相关类,分析了Power事件上报流程,包括按键处理、亮屏和灭屏操作的代码逻辑,还阐述了状态判断、亮度计算及屏幕绘制等后续处理过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要跟踪分析通过按松power键来唤醒,熄灭屏幕的逻辑。下面是一些相关类的介绍

PowerManagerService.java:简称PMS,负责Andorid系统中电源管理方面的工作。作为系统核心服务之一,主要处理系统中与power相关的计算,然后决策系统该如何反应。同时PowerManagerService与其他服务及HAL层等都有交互关系,协调power如何与系统其他模块的交互,比如没有用户活动时屏幕变暗等。

DisplayPowerController.java:简称DPC管理Display设备的电源状态。仅在PowerManagerService中实例化了一个对象,它算是PowerManagerService的一部分,只不过是独立出来了而已。主要处理和距离传感器,

灯光传感器,以及包括关屏在内的一些动画,通过异步回调的方式来通知PowerManagerService某些事情发生了变化。

DisplayPowerState.java:简称DPS,在本质上类似于View,只不过用来描述一个display的属性,当这些属性发生变化时,可以通过一个序列化的命令,让这些和display电源状态的属性一起产生变化。

这个类的对象只能被DispalyPowerController的Looper持有。而这个Looper应该就是PowerManagerService中新建的一个HandlerThread中的Looper。和PowerManager相关的,

包括DisplayPowerState和DisplayPowerController相关的消息处理应该都可以通过这个HandlerThread进行运转的

Notifier.java:将power状态的重要变化,通过广播发送出去,并且参与了与AMS,WMS,IMP的交互。

ColorFade.java:负责屏幕由关到开,由开到关的一些GL动画,由DPC进行控制。

AutomaticBrightnessController.java:主要处理光传感器,将底层上传的参数进行处理计算,将计算的新的亮度值传给DPC。

RampAnimator.java:处理屏幕亮度渐变动画。

  1. 代码流程分析
    1. Power事件上报跟踪

正常我们按下power键后,出触发Kernel关于该事件的中断。然后inputReader通过EventHub获取该事件,并做出事件处理,之后由inputdispatch进行事件分发。

因为power事件是key事件,会调用interceptKeyBeforeQueueing进行处理,通过如果流程

InputDispatcher.cpp

  ->com_android_server_input_InputManagerService.cpp

          ->InputManagerService.java

                   ->InputMonitor.java

                           ->WindowManagerPolicy.java

                                    ->PhoneWindowManager.java

      1. PhoneWindowManager.java

最终由PhoneWindowManager.java的interceptKeyBeforeQueueing方法对该次事件进行处理,对power键以及屏幕状态进行判断,来决定亮屏还是灭屏等操作。当需要亮屏时,会调用PowerMangerService中的wakeup函数进行处理。

主要代码如下:

首先定义以下几个布尔值,主要是按键属性和屏幕状态

//是否亮屏状态,代码是否可以与用户交互

final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;

//按键事件是否为down事件

final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;

//事件是否被取消

final boolean canceled = event.isCanceled();

//按键的keycode,不同按键 keycode不同,一般power 116

final int keyCode = event.getKeyCode();

//是否是输入事件

final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;

//锁屏界面状态

final boolean keyguardActive = (mKeyguardDelegate == null ? false :(interactive ?isKeyguardShowingAndNotOccluded() :mKeyguardDelegate.isShowing()));

//flags有wake标记,或者按键(isWakeKey函数)为KEYCODE_BACK, KEYCODE_MENU, KEYCODE_WAKEUP, KEYCODE_PAIRING, KEYCODE_STEM_1, KEYCODE_STEM_2, KEYCODE_STEM_3设置isWakeKey为true

boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 || event.isWakeKey();

 

 

if (isValidGlobalKey(keyCode)//有效的全局按键 (KEYCODE_POWER:KEYCODE_WAKEUP:KeyEvent.KEYCODE_SLEEP:),

          && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {//在com.android.internal.R.xml.global_keys 有定义

  if (isWakeKey) {

          wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");唤醒屏幕

  }

  return result;

}

 

接下来是对特殊按键的处理,这里只关注power键

 switch (keyCode) {

   case KeyEvent.KEYCODE_POWER: {

          result &= ~ACTION_PASS_TO_USER;

          isWakeKey = false; // wake-up will be handled separately

          if (down) {

                   interceptPowerKeyDown(event, interactive);//处理power按下

          } else {

                   interceptPowerKeyUp(event, interactive, canceled);//处理power松开

          }

          break;

  }

 

power down 键的处理

private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {

  // 获取wakelock,报错CPU唤醒状态

  if (!mPowerKeyWakeLock.isHeld()) {

          mPowerKeyWakeLock.acquire();

  }

 

  // 取消多次按下超时监测

  if (mPowerKeyPressCounter != 0) {

          mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);

  }

 

  // Detect user pressing the power button in panic when an application has

  // taken over the whole screen.

boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,

                   SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),

                   isNavBarEmpty(mLastSystemUiFlags));

  if (panic) {

          mHandler.post(mHiddenNavPanic);

  }

 

  // Latch power key state to detect screenshot chord.

  if (interactive && !mScreenshotChordPowerKeyTriggered

                   && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {

          mScreenshotChordPowerKeyTriggered = true;

          mScreenshotChordPowerKeyTime = event.getDownTime();

          interceptScreenshotChord();//屏幕截屏

          interceptDisableTouchModeChord();  //添加口袋模式

  }

 

  // 当power键按下,停止电话响铃或者结束通话

  TelecomManager telecomManager = getTelecommService();

  boolean hungUp = false;

  if (telecomManager != null) {

          if (telecomManager.isRinging()) {

                   停止响铃

                   telecomManager.silenceRinger();

          } else if ((mIncallPowerBehavior

                           & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0

                           && telecomManager.isInCall() && interactive) {

                   Setting数据库读取设置,如果开了挂断电话

                   hungUp = telecomManager.endCall();

          }

  }

 

  SprdGestureLauncherService gestureService = LocalServices.getService(

                   SprdGestureLauncherService.class);

  boolean gesturedServiceIntercepted = false;

  if (gestureService != null) {

          gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive,

                           mTmpBoolean);

          if (mTmpBoolean.value && mGoingToSleep) {

                   mCameraGestureTriggeredDuringGoingToSleep = true;

          }

  }

 

  // If the power key has still not yet been handled, then detect short

  // 如果power键还没有被处理,判断是短按,多按,长按等场景并做出对应处理

  mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered

                   || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;

  if (!mPowerKeyHandled) {

          if (interactive) {

                   //如果屏幕是亮的,长按动作处理对应的长按动作

                   if (hasLongPressOnPowerBehavior()) {

                           Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);

                           msg.setAsynchronous(true);

                           mHandler.sendMessageDelayed(msg,

                                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

                   }

          } else {//屏幕休眠的状态,唤醒屏幕

                   wakeUpFromPowerKey(event.getDownTime());

 

                   if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) {

                           Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);

                           msg.setAsynchronous(true);

                           mHandler.sendMessageDelayed(msg,//如果长按动作继续执行长按操作

                                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

                           mBeganFromNonInteractive = true;

                   } else {

                           final int maxCount = getMaxMultiPressPowerCount();

 

                           if (maxCount <= 1) {

                                    mPowerKeyHandled = true;

                           } else {

                                    mBeganFromNonInteractive = true;

......

power up 键的处理

private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {

  final boolean handled = canceled || mPowerKeyHandled; //power键是否被处理了

  mScreenshotChordPowerKeyTriggered = false;

  cancelPendingScreenshotChordAction();

  cancelPendingPowerKeyAction();

 

  if (!handled) {

          // power press 加1

          mPowerKeyPressCounter += 1;

        

          final int maxCount = getMaxMultiPressPowerCount();//多按的次数

          final long eventTime = event.getDownTime();//press power 时间

          if (mPowerKeyPressCounter < maxCount) {

                   // 这种情况可能是一个多次按键事件,等待一会做确认处理

                   Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,

                                    interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);

                   msg.setAsynchronous(true);

                   mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());

                   return;

          }

 

          // 没有其他action,继续处理power按下事件

          powerPress(eventTime, interactive, mPowerKeyPressCounter);

  }

 

  // Done.  Reset our state.

  finishPowerKeyPress();//power按键处理结束

}

private void finishPowerKeyPress() {

  mBeganFromNonInteractive = false;

  mPowerKeyPressCounter = 0;

  if (mPowerKeyWakeLock.isHeld()) {

          mPowerKeyWakeLock.release();//释放wakelock

  }

}

下面继续跟踪powerPress函数

private void powerPress(long eventTime, boolean interactive, int count) {

  if (mScreenOnEarly && !mScreenOnFully) {

          Slog.i(TAG, "Suppressed redundant power key press while "

                           + "already in the process of turning the screen on.");

          return;

  }

 

  if (count == 2) {//按两次power事件

          powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);

  } else if (count == 3) {//按三次power事件

          powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);

  } else if (interactive && !mBeganFromNonInteractive) {//屏幕如果亮着而且mBeganFromNonInteractive为false会执行下面操作

          switch (mShortPressOnPowerBehavior) {//根据配置om.android.internal.R.integer.config_shortPressOnPowerBehavior 决定对应值 此处为1

                   case SHORT_PRESS_POWER_NOTHING:

                           break;

                   case SHORT_PRESS_POWER_GO_TO_SLEEP:

                           mPowerManager.goToSleep(eventTime,

                                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);//执行灭屏操作

                           break;

                   ......

}

 

我们继续跟踪亮屏操作,从power down事件处理可知,调用wakeUpFromPowerKey点亮屏幕

private void wakeUpFromPowerKey(long eventTime) {

  Slog.d(TAG, "wake Up From Power Key"); // 此处会打印这句log,可作为分析问题是注意点

  wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");//调用wakeup继续执行亮屏操作,注意调用mPowerManager.wakeUp操作

}

      1. PowerManager.wakeUp

下面我们看下PowerManager.wakeUp的相关处理

public void wakeUp(long time) {

  try {

          mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());//调用到PWM.wakeUpInternal->PWM.wakeUpNoUpdateLocked

  } catch (RemoteException e) {

          throw e.rethrowFromSystemServer();

  }

}

 

当power接收到亮灭屏调用后,会先进行设置手机wakefullness状态. 之后发送亮灭屏广播通知其他应用手机处于亮屏还是灭屏状态。

private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,

          String opPackageName, int opUid) {

  //mWakefulness标识系统当前状态共有四种定义:

  WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeUp()调用唤醒。

  WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态。

  WAKEFULNESS_DREAMING:表示系统当前正处于互动屏保的状态。

  WAKEFULNESS_DOZING:表示系统正处于“doze”状态

  if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE

                   || !mBootCompleted || !mSystemReady) {//按键时间在睡下去之前,屏幕是正常状态,没有完成开机流程,系统没有准备完成,这四种情况不继续执行唤醒流程

          return false;

  }

 

  try {//系统不是点亮状态,打出相关log

          switch (mWakefulness) {

                   case WAKEFULNESS_ASLEEP:

                   case WAKEFULNESS_DREAMING:

                   case WAKEFULNESS_DOZING:

                           Slog.i(TAG, "Waking up from dozing due to"+opPackageName+" "+reason+" (uid " + reasonUid +")...");

                           break;

          }

 

          mLastWakeTime = eventTime;//更新wake时间

          setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);//更新mWakefulness,并调用Notifier.onWakefulnessChangeStarted发送亮屏广播 

          mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);//调用Notifier通知battery处理 

          userActivityNoUpdateLocked(eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);//更新最后一次用户事件的时间

  } finally {

  }

  return true;

}

 

      1. Notifier.java

然后主要就是在Notifier.java中与AMS,window,input进行交互,通知各模块手机状态发生了改变,根据屏幕状态各自进行处理, 最后发送亮灭屏广播, 通知相关的模块.

private void setWakefulnessLocked(int wakefulness, int reason) {

  if (mWakefulness != wakefulness) {

          mWakefulness = wakefulness;//更新mWakefulness变量

          mWakefulnessChanging = true;

          mDirty |= DIRTY_WAKEFULNESS;

          mNotifier.onWakefulnessChangeStarted(wakefulness, reason);//调用Notify的函数onWakefulnessChangeStarted 发广播通知

  }

}

public void onWakefulnessChangeStarted(final int wakefulness, int reason) {

    //获取交互模式变量,亮屏为true, 灭屏为false

  final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);

 

  通知AMS wakefulness状态的变化

  mHandler.post(new Runnable() {

          @Override

          public void run() {

                   mActivityManagerInternal.onWakefulnessChanged(wakefulness);

          }

  });

 

  //interactive 变化时才会执行里面的逻辑

  if (mInteractive != interactive) {

          // Finish up late behaviors if needed.

          if (mInteractiveChanging) {

                   handleLateInteractiveChange();

          }

 

          //在input中记录现在的屏幕状态

          mInputManagerInternal.setInteractive(interactive);

          mInputMethodManagerInternal.setInteractive(interactive);

 

          //唤醒battery状态

          try {

                   mBatteryStats.noteInteractive(interactive);

          } catch (RemoteException ex) { }

 

          // Handle early behaviors.

          mInteractive = interactive;

          mInteractiveChangeReason = reason;

          mInteractiveChanging = true;

          handleEarlyInteractiveChange();//处理交互模式改变

  }

}

 

private void handleEarlyInteractiveChange() {

  synchronized (mLock) {

          if (mInteractive) {//mInteractive 为true代表要执行亮屏逻辑

                   // Waking up...

                   mHandler.post(new Runnable() {

                           @Override

                           public void run() {

                                    // Note a SCREEN tron event is logged in PowerManagerService.

                                    mPolicy.startedWakingUp();//调用PhoneWindowManager 方法开始亮屏流程

                           }

                   });

 

                   // 更新亮屏广播

                   mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;

                   mPendingWakeUpBroadcast = true;

                   updatePendingBroadcastLocked();//mSuspendBlocker.acquire();持有partial 锁

          } else {//mInteractive 为false代表要执行灭屏逻辑

                   final int why = translateOffReason(mInteractiveChangeReason);

                   mHandler.post(new Runnable() {

                           @Override

                           public void run() {

                                    mPolicy.startedGoingToSleep(why);//调用PhoneWindowManager 方法开始灭屏流程

                           }

                   });

          }

  }

}

 

      1. 广播更新的流程

调用updatePendingBroadcastLocked函数发出handle msg 消息

Message msg = mHandler.obtainMessage(MSG_BROADCAST);

msg.setAsynchronous(true);

mHandler.sendMessage(msg);

然后handle收到后执行sendNextBroadcast函数

case MSG_BROADCAST:

  sendNextBroadcast();

  break;

private void sendNextBroadcast() {

  final int powerState;

  //mBroadcastedInteractiveState 这个变量记录当前的系统亮灭屏情况

  synchronized (mLock) {

          if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {

                   // 当前状态位置更新为唤醒状态

                   mPendingWakeUpBroadcast = false;

                   mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;

          } else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {

                   // 当前是唤醒状态,更新为灭屏状态

                   if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast

                                    || mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {

                           mPendingGoToSleepBroadcast = false;

                           mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;

                   } else {

                           finishPendingBroadcastLocked();//释放partial 锁

                           return;

                   }

          } else {

                   // 当前是灭屏状态,更新为唤醒状态

                   if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast

                                    || mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {

                           mPendingWakeUpBroadcast = false;

                           mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;

                   } else {

                           finishPendingBroadcastLocked();

                           return;

                   }

          }

          //记录下当前系统时间为广播开始时间

          mBroadcastStartTime = SystemClock.uptimeMillis();

          powerState = mBroadcastedInteractiveState;

  }

 

EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);//打出event log

 

  if (powerState == INTERACTIVE_STATE_AWAKE) {//根据powerState的值决定发亮屏还是灭屏广播

          sendWakeUpBroadcast();

  } else {

          sendGoToSleepBroadcast();

  }

}

广播都是前台广播,然后其他模块收到广播后作出对应处理

mScreenOnIntent.addFlags(

  Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND

  | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);

mScreenOffIntent.addFlags(

  Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND

  | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);

Notify 收到这个广播后会,继续调用sendNextBroadcast,因为mPendingWakeUpBroadcast值变化,会调用finishPendingBroadcastLocked();释放partial 锁

private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {

  @Override

  public void onReceive(Context context, Intent intent) {

     EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,

                           SystemClock.uptimeMillis() - mBroadcastStartTime, 1);

          sendNextBroadcast();

  }

};

总结:当power接收到亮灭屏调用后,会先进行设置手机wakefullness状态,之后发送亮灭屏广播通知其他模块手机处于亮屏还是灭屏状态。并且在发送广播过程中power也与AMS,window,input进行交互,通知各模块手机状态发生了改变,根据屏幕状态各自进行处理。其中发送亮灭屏广播的主要实现在Notifier.java中。

当wakefulness状态发生改变,AMS收到通知。如果亮屏操作,AMS就会通过函数comeOutOfSleepIfNeedLocked调用到ActivityStackSupervisor中,将sleep超时消息移除,最后将在栈顶的activity显示出来。

power是通过WindowManagerPolicy与PhoneWindowManager进行交互,当屏幕在唤醒时需要通知window进行更新手势监听,更新方向监听,更新锁屏超时时间。最后通知keyguard屏幕点亮了,进行刷新锁屏界面时间,之后通过回调接口,回调回PhoneWindowManager的onShown函数,通知window keyguard准备完成。

当亮屏时通过InputManagerService将当前屏幕状态传入JNI中进行记录,当再次发生power键事件可以方便确认该事件是需要亮屏还是灭屏。

 

    1. Power状态的更新和处理

当广播处理完毕后就会调用PMS的内部函数updatePowerStateLocked来更新全局电源状态。其实在PMS中很多函数都只是对一些必须的属性进行赋值,大部分最终都会调用到updatePowerStateLocked函数中进行功能执行,其中更新电源状态主要依据就是变量mDirty。mDirty就是用来记录power state的变化的标记位,这样的状态变化在系统中一共定义了12个,每一个状态对应一个固定的数字,都是2的倍数。这样,若有多个状态一块变化,进行按位取或这样结果既是唯一的,又能准确标记出各个状态的变化。在updatePowerStateLocked中主要做了如下事情:

  • 首先判断手机是否处于充电状态,如果标记位DIRTY_BATTERY_STATE发生改变时就证明电池状态发生了改变,然后通过对比判断(通过电池前后变化与充电状态的变化),确认手机是否处于充电状态。如果手机处于充电状态会将表示充电的标记位记入mDirty中。当有USB插拔时我们也可以通过配置信息来决定是否需要点亮屏幕。并且是否在充电或者充电方式发生改变,系统都会认为发生了一次用户事件进行更新最后用户操作时间,以此来重新计算屏幕超时时间。

private void updateIsPoweredLocked(int dirty) {

  if ((dirty & DIRTY_BATTERY_STATE) != 0) {

          final boolean wasPowered = mIsPowered;//是否在充电 

          final int oldPlugType = mPlugType;//充电类型 

          final boolean oldLevelLow = mBatteryLevelLow;//低电模式

          mIsPowered = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);

          mPlugType = mBatteryManagerInternal.getPlugType();

          mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();

          mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow();

          if (wasPowered != mIsPowered || oldPlugType != mPlugType) {

                   mDirty |= DIRTY_IS_POWERED;//如果充电中设置mDirty

                   /* < Bug#696466 optimization for sceenoff */

                   if (wasPowered != mIsPowered)

                           SystemProperties.set("sys.sprd.power.ispowered", (mIsPowered? "1": "0"));//设置属性sys.sprd.power.ispowered

                   /* Bug#696466 optimization for sceenoff > */

                   //无线充电

                   final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(

                                    mIsPowered, mPlugType, mBatteryLevel);

                   final long now = SystemClock.uptimeMillis();

                   if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,

                                    dockedOnWirelessCharger)) {//插拔USB是否要点亮屏幕

                           wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,

                                            mContext.getOpPackageName(), Process.SYSTEM_UID);

                   }

                   userActivityNoUpdateLocked(//插拔USB算一次用户事件,重新设置最后一次用户事件的时间点

                                    now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);

                   // Tell the notifier whether wireless charging has started so that

                   // it can provide feedback to the user.

                   if (dockedOnWirelessCharger) {

                           mNotifier.onWirelessChargingStarted();

                   }

          }

          if (wasPowered != mIsPowered || oldLevelLow != mBatteryLevelLow) {//低电模式

                   if (oldLevelLow != mBatteryLevelLow && !mBatteryLevelLow) {

                           mAutoLowPowerModeSnoozing = false;

                   }

                   updateLowPowerModeLocked();//更新低电模式

          }

  }

}

  • 更新wakefulness

for (;;) {

  int dirtyPhase1 = mDirty;

  dirtyPhase2 |= dirtyPhase1;

  mDirty = 0;

  updateWakeLockSummaryLocked(dirtyPhase1);

  updateUserActivitySummaryLocked(now, dirtyPhase1);

  if (!updateWakefulnessLocked(dirtyPhase1)) {

          break;

  }

}

updateWakeLockSummaryLocked函数将wakeLock的类型用mWakeLockSummary进行记录,最后与Wakefulness状态结合重新算出新的mWakeLockSummary值,再判断是否需要睡眠时会使用。

之后updateUserActivitySummaryLocked就会更新屏幕超时时间,根据最后一次的用户事件与屏幕超时时间与dim持续时间来计算屏幕超时的时间,然后与现在的时间进行对比,来决定屏幕要继续高亮,还是要变为dim状态。

PowerManagerHandler接收屏幕超时的消息, 并且调用handleUserActivityTimeout进行处理, 该函数之后就在Handler线程中运行

 

private final class PowerManagerHandler extends Handler { 

    public PowerManagerHandler(Looper looper) { 

        super(looper, null, true /*async*/); 

    } 

 

    @Override 

    public void handleMessage(Message msg) { 

        switch (msg.what) { 

            case MSG_USER_ACTIVITY_TIMEOUT: 

                handleUserActivityTimeout();    //处理用户超时事件 

                break; 

            case MSG_SANDMAN: 

                handleSandman(); 

                break; 

            case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT: 

                handleScreenBrightnessBoostTimeout(); 

                break; 

        } 

    } 

 

private void handleUserActivityTimeout() { // runs on handler thread 

    synchronized (mLock) { 

        if (DEBUG_SPEW) { 

            Slog.d(TAG, "handleUserActivityTimeout"); 

        } 

 

        mDirty |= DIRTY_USER_ACTIVITY;  //设置有用户活动的mDirty值 

        updatePowerStateLocked();   //更新电源状态, 最后去判断是否要睡眠 

    } 

 

根据前面流程图可以看出更新wakefulness过程是通过一个死循环来执行的,只有调用函数updateWakefulnessLocked返回false时才会跳出循环。在循环中对wakeLockSummary进行更新,并且更新自动灭屏时间后,进行判断系统是否该睡眠了,是否可以跳出循环。

在updateWakefulnessLocked中主要根据是否存在wakeLock,用户活动进行判断设备是否需要进入睡眠状态。从函数isBeingKeptAwakeLocked可以看出当device拿着一个wake lock,有用户事件,有距离传感器等都不会灭屏进行睡眠状态。如果需要睡眠就会往下面调用,最后跳出循环。

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

        if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {   //mWakefulness为AWAKE, 并且到了睡觉时间, 就去睡觉 

            if (DEBUG_SPEW) { 

                Slog.d(TAG, "updateWakefulnessLocked: Bed time...");    

            } 

            final long time = SystemClock.uptimeMillis(); 

            if (shouldNapAtBedTimeLocked()) {  

                changed = napNoUpdateLocked(time, Process.SYSTEM_UID);  //睡觉前先小憩一会 

            } else { 

                changed = goToSleepNoUpdateLocked(time, 

                        PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);  //直接睡觉 

            } 

        } 

    } 

    return changed; 

[java] view plain copy

private boolean isItBedTimeYetLocked() {// 对所有该唤醒的情况取反, 就是该休眠了 

    return mBootCompleted && !isBeingKeptAwakeLocked();   

private boolean isBeingKeptAwakeLocked() { 

    return mStayOn  //设置了stay on 

            || mProximityPositive  //距离传感器返回一个positive结果,保持唤醒 

            || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0  //当有wake lock时保持唤醒 

            || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT 

                    | USER_ACTIVITY_SCREEN_DIM)) != 0   //有user activity时保持唤醒 

            || mScreenBrightnessBoostInProgress; 

[java] view plain copy

     mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver, 

            Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 

            mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0, 

            UserHandle.USER_CURRENT) != 0);     //从settings数据库获取对应值 

    mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver, 

            Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, 

            mDreamsActivatedOnDockByDefaultConfig ? 1 : 0, 

            UserHandle.USER_CURRENT) != 0); 

 

 private boolean shouldNapAtBedTimeLocked() {  //当返回true, 设备自动nap 

    return mDreamsActivateOnSleepSetting 

            || (mDreamsActivateOnDockSetting 

                    && mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED); 

[java] view plain copy

private boolean napNoUpdateLocked(long eventTime, int uid) { 

    if (DEBUG_SPEW) { 

        Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid); 

    } 

 

    if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE 

            || !mBootCompleted || !mSystemReady) { 

        return false; 

    } 

 

    Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap"); 

    try { 

        Slog.i(TAG, "Nap time (uid " + uid +")..."); 

 

        mSandmanSummoned = true; 

        setWakefulnessLocked(WAKEFULNESS_DREAMING, 0);  //设置WAKEFULNESS_DREAMING 

    } finally { 

        Trace.traceEnd(Trace.TRACE_TAG_POWER); 

    } 

    return true; 

调用goToSleepNoUpdateLocked进行睡眠, 当按power键灭屏是也会调用该函数.

 

[java] view plain copy

private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) { 

    if (DEBUG_SPEW) { 

        Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime 

                + ", reason=" + reason + ", flags=" + flags + ", uid=" + uid); 

    } 

 

    if (eventTime < mLastWakeTime 

            || mWakefulness == WAKEFULNESS_ASLEEP 

            || mWakefulness == WAKEFULNESS_DOZING 

            || !mBootCompleted || !mSystemReady) { 

        return false;   //判断设备是否应该睡眠 

    } 

 

    Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep"); 

    try { 

        switch (reason) {   //输出灭屏的原因 

            case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN: 

                Slog.i(TAG, "Going to sleep due to device administration policy " 

                        + "(uid " + uid +")..."); 

                break; 

            case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT: 

                Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")..."); 

                break; 

            case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH: 

                Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")..."); 

                break; 

            case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:  

                Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")..."); 

                break; 

            case PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON: 

                Slog.i(TAG, "Going to sleep due to sleep button (uid " + uid +")..."); 

                break; 

            case PowerManager.GO_TO_SLEEP_REASON_HDMI: 

                Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")..."); 

                break; 

            default: 

                Slog.i(TAG, "Going to sleep by application request (uid " + uid +")..."); 

                reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION; 

                break; 

        } 

 

        mLastSleepTime = eventTime; 

        mSandmanSummoned = true; 

        setWakefulnessLocked(WAKEFULNESS_DOZING, reason); 

 

        // Report the number of wake locks that will be cleared by going to sleep. 

        int numWakeLocksCleared = 0; 

        final int numWakeLocks = mWakeLocks.size();   

        for (int i = 0; i < numWakeLocks; i++) {  //遍历所有的wakeLocks, 将FULL, BRIGHT, DIM Locks,计入numWakeLocksCleared中 

            final WakeLock wakeLock = mWakeLocks.get(i); 

            switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) { 

                case PowerManager.FULL_WAKE_LOCK: 

                case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: 

                case PowerManager.SCREEN_DIM_WAKE_LOCK: 

                    numWakeLocksCleared += 1; 

                    break; 

            } 

        } 

        EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared); 

 

        // Skip dozing if requested. 

        if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) { 

            reallyGoToSleepNoUpdateLocked(eventTime, uid); //如果没有doze流程,直接设置WAKEFULNESS_ASLEEP 

        } 

    } finally { 

        Trace.traceEnd(Trace.TRACE_TAG_POWER); 

    } 

    return true;   //返回true 

当第一个for循环中将所有的状态都设置好了, 并且此时也没有重要的mDirty发生变化, 在下一次循环中mDirty的值为0, updateWakefulnessLocked返回false,就会跳出循环.

当跳出循环之后在函数updateDisplayPowerStateLocked中进行获取需要请求的设备电源状态是亮还是灭或者dim,判断是否开启了自动调节亮度开关,是否使用了距离传感器,并经过一系列的计算获取亮度值等,最终都记录到DisplayPowerRequest中,经过DMS传入DPC中,进行处理。

在PowerManagerService中对各种状态进行判断后,将其数值封装进DisplayPowerRequest中传入DisplayPowerController中进一步处理。在亮屏过程中DisplayPowerController会根据传过来的数值来设置新的电源状态为亮屏,然后调用DisplayPowerState来对状态进行设置。由于此时ColorFade level(就是在手机屏幕的一层surface,当level为0是为一层黑帧,level为1.0时为透明)的值为0,表示屏幕还没有绘制好,所以此时需要block screen直到window界面绘制完成。当需要亮屏时调用PhoneWindowManager的screenTurningOn函数,通知window屏幕就要点亮了。然后调用WMS中函数waitForAllWindowsDrawn函数等待将所有需要绘制的window绘制完成后回调回来,超时时间为1000ms。在WMS中获取需要绘制的window将其加入mWaitingForDrawn中等待绘制,通过检查mWaitingForDrawn是否为空来判断,window是否绘制完成。此时screenTurningOn函数就执行完了,剩下的就是等待windows绘制完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值