目录
一. 源码分析:
二. 简单整理流程:
三. DisplayPowerController处理
四. 阻塞亮屏
五. 从按下power键到亮屏的流程小结:
六.log 验证:
一. 源码分析:
1.按键上报流程.
(1).从native 层上报事件:
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
//打开log 调试开关
#define LOG_NDEBUG 0
static struct {
...
jmethodID interceptKeyBeforeQueueing;
...
}
int register_android_server_InputManager(JNIEnv* env) {
....
//动态JNI注册
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
"interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
....
}
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
uint32_t& policyFlags) {
ATRACE_CALL();
// Policy:
// - Ignore untrusted events and pass them along.
// - Ask the window manager what to do with normal events and trusted injected events.
// - For normal events wake and brighten the screen if currently off or dim.
bool interactive = mInteractive.load();
if (interactive) {
policyFlags |= POLICY_FLAG_INTERACTIVE;
}
if ((policyFlags & POLICY_FLAG_TRUSTED)) {
nsecs_t when = keyEvent->getEventTime();
JNIEnv* env = jniEnv();
jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
jint wmActions;
if (keyEventObj) {
//通过反射的方法调用java层
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj, policyFlags);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
android_view_KeyEvent_recycle(env, keyEventObj);
env->DeleteLocalRef(keyEventObj);
} else {
ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
wmActions = 0;
}
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
} else {
if (interactive) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}
}
(2). 通过JNI 调用的java 层InputManagerService.java,对应的路径:
android/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Native callback.
//C++ 层调用对应的java 层函数.
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
}
3. mWindowManagerCallbacks对象的java类是:InputManagerCallback.java,对应的路径:
android/frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java
/**
* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device.
*/
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
}4. mService.mPolicy 对应的java类是PhoneWindowManager.java, 对应的路径:
android/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
// TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
//获取keycode
final int keyCode = event.getKeyCode();
//是否down事件
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
//是否是唤醒键
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
|| event.isWakeKey();
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
// Exception: Wake and power key events are forwarded to PowerManager to allow it to
// wake from quiescent mode during boot.
//未启动完成,直接拦截.顺便处理特殊的按键
if (down && (keyCode == KeyEvent.KEYCODE_POWER
|| keyCode == KeyEvent.KEYCODE_TV_POWER)) {
//若是power键,则唤醒
wakeUpFromPowerKey(event.getDownTime());
} else if (down && (isWakeKey || keyCode == KeyEvent.KEYCODE_WAKEUP)
&& isWakeKeyWhenScreenOff(keyCode)) {
wakeUpFromWakeKey(event);
}
return 0;
}
//是否存在FLAG_INTERACTIVE flag
final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
//event是否被cancel.
final boolean canceled = event.isCanceled();
final int displayId = event.getDisplayId();
//是否存在FLAG_INJECTED flag
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
//是否显示锁屏
final boolean keyguardActive = (mKeyguardDelegate != null
&& (interactive ? isKeyguardShowingAndNotOccluded() :
mKeyguardDelegate.isShowing()));
if (DEBUG_INPUT) {
// If screen is off then we treat the case where the keyguard is open but hidden
// the same as if it were open and in front.
// This will prevent any keys other than the power button from waking the screen
// when the keyguard is hidden by another activity.
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+ " interactive=" + interactive + " keyguardActive=" + keyguardActive
+ " policyFlags=" + Integer.toHexString(policyFlags));
}
// Basic policy based on interactive state.
int result;
if (interactive || (isInjected && !isWakeKey)) {
// When the device is interactive or the key is injected pass the
// key to the application.
result = ACTION_PASS_TO_USER;
isWakeKey = false;
if (interactive) {
// If the screen is awake, but the button pressed was the one that woke the device
// then don't pass it to the application
if (keyCode == mPendingWakeKey && !down) {
result = 0;
}
// Reset the pending key
mPendingWakeKey = PENDING_KEY_NULL;
}
} else if (shouldDispatchInputWhenNonInteractive(displayId, keyCode)) {
// If we're currently dozing with the screen on and the keyguard showing, pass the key
// to the application but preserve its wake key status to make sure we still move
// from dozing to fully interactive if we would normally go from off to fully
// interactive.
result = ACTION_PASS_TO_USER;
// Since we're dispatching the input, reset the pending key
mPendingWakeKey = PENDING_KEY_NULL;
} else {
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
result = 0;
if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
isWakeKey = false;
}
// Cache the wake key on down event so we can also avoid sending the up event to the app
if (isWakeKey && down) {
mPendingWakeKey = keyCode;
}
}
// If the key would be handled globally, just return the result, don't worry about special
// key processing.
if (isValidGlobalKey(keyCode)
&& mGlobalKeyManager.shouldHandleGlobalKey(keyCode)) {
// Dispatch if global key defined dispatchWhenNonInteractive.
if (!interactive && isWakeKey && down
&& mGlobalKeyManager.shouldDispatchFromNonInteractive(keyCode)) {
mGlobalKeyManager.setBeganFromNonInteractive();
result = ACTION_PASS_TO_USER;
// Since we're dispatching the input, reset the pending key
mPendingWakeKey = PENDING_KEY_NULL;
}
if (isWakeKey) {
wakeUpFromWakeKey(event);
}
return result;
}
// Alternate TV power to power key for Android TV device.
final HdmiControlManager hdmiControlManager = getHdmiControlManager();
if (keyCode == KeyEvent.KEYCODE_TV_POWER && mHasFeatureLeanback
&& (hdmiControlManager == null || !hdmiControlManager.shouldHandleTvPowerKey())) {
event = KeyEvent.obtain(
event.getDownTime(), event.getEventTime(),
event.getAction(), KeyEvent.KEYCODE_POWER,
event.getRepeatCount(), event.getMetaState(),
event.getDeviceId(), event.getScanCode(),
event.getFlags(), event.getSource(), event.getDisplayId(), null);
return interceptKeyBeforeQueueing(event, policyFlags);
}
// This could prevent some wrong state in multi-displays environment,
// the default display may turned off but interactive is true.
final boolean isDefaultDisplayOn = Display.isOnState(mDefaultDisplay.getState());
final boolean interactiveAndOn = interactive && isDefaultDisplayOn;
if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
//处理手势,譬如:双击power启动camera等等
handleKeyGesture(event, interactiveAndOn);
}
// Enable haptics if down and virtual key without multiple repetitions. If this is a hard
// virtual key such as a navigation bar button, only vibrate if flag is enabled.
final boolean isNavBarVirtKey = ((event.getFlags() & KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0);
boolean useHapticFeedback = down
&& (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
&& (!isNavBarVirtKey || mNavBarVirtualKeyHapticFeedbackEnabled)
&& event.getRepeatCount() == 0;
/// M: Add more log at WMS
if (mWindowManagerDebugger.WMS_DEBUG_ENG || mWindowManagerDebugger.WMS_DEBUG_USER_DEBUG) {
mWindowManagerDebugger.debugInterceptKeyBeforeQueueing(TAG, keyCode, interactive,
keyguardActive, policyFlags, down, canceled, isWakeKey,
result, useHapticFeedback, isInjected);
}
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
if (down) {
mBackKeyHandled = false;
} else {
if (!hasLongPressOnBackBehavior()) {
mBackKeyHandled |= backKeyPress();
}
// Don't pass back press to app if we've already handled it via long press
if (mBackKeyHandled) {
result &= ~ACTION_PASS_TO_USER;
}
}
break;
}
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (down) {
sendSystemKeyToStatusBarAsync(event.getKeyCode());
NotificationManager nm = getNotificationService();
if (nm != null && !mHandleVolumeKeysInWM) {
nm.silenceNotificationSound();
}
TelecomManager telecomManager = getTelecommService();
if (telecomManager != null && !mHandleVolumeKeysInWM) {
// When {@link #mHandleVolumeKeysInWM} is set, volume key events
// should be dispatched to WM.
if (telecomManager.isRinging()) {
// If an incoming call is ringing, either VOLUME key means
// "silence ringer". We handle these keys here, rather than
// in the InCallScreen, to make sure we'll respond to them
// even if the InCallScreen hasn't come to the foreground yet.
// Look for the DOWN event here, to agree with the "fallback"
// behavior in the InCallScreen.
Log.i(TAG, "interceptKeyBeforeQueueing:"
+ " VOLUME key-down while ringing: Silence ringer!");
// Silence the ringer. (It's safe to call this
// even if the ringer has already been silenced.)
telecomManager.silenceRinger();
// And *don't* pass this key thru to the current activity
// (which is probably the InCallScreen.)
result &= ~ACTION_PASS_TO_USER;
break;
}
}
int audioMode = AudioManager.MODE_NORMAL;
try {
audioMode = getAudioService().getMode();
} catch (Exception e) {
Log.e(TAG, "Error getting AudioService in interceptKeyBeforeQueueing.", e);
}
boolean isInCall = (telecomManager != null && telecomManager.isInCall()) ||
audioMode == AudioManager.MODE_IN_COMMUNICATION;
if (isInCall && (result & ACTION_PASS_TO_USER) == 0) {
// If we are in call but we decided not to pass the key to
// the application, just pass it to the session service.
MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
break;
}
}
if (mUseTvRouting || mHandleVolumeKeysInWM) {
// Defer special key handlings to
// {@link interceptKeyBeforeDispatching()}.
result |= ACTION_PASS_TO_USER;
} else if ((result & ACTION_PASS_TO_USER) == 0) {
// If we aren't passing to the user and no one else
// handled it send it to the session manager to
// figure out.
MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
}
break;
}
case KeyEvent.KEYCODE_ENDCALL: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
hungUp = telecomManager.endCall();
}
if (interactive && !hungUp) {
mEndCallKeyHandled = false;
mHandler.postDelayed(mEndCallLongPress,
ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
} else {
mEndCallKeyHandled = true;
}
} else {
if (!mEndCallKeyHandled) {
mHandler.removeCallbacks(mEndCallLongPress);
if (!canceled) {
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
if (goHome()) {
break;
}
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
sleepDefaultDisplay(event.getEventTime(),
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
isWakeKey = false;
}
}
}
}
break;
}
case KeyEvent.KEYCODE_TV_POWER: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down && hdmiControlManager != null) {
hdmiControlManager.toggleAndFollowTvPower();
}
break;
}
case KeyEvent.KEYCODE_POWER: {
//电源键日志记录
EventLogTags.writeInterceptPower(
KeyEvent.actionToString(event.getAction()),
mPowerKeyHandled ? 1 : 0,
mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
//拦截power键按下
interceptPowerKeyDown(event, interactiveAndOn);
} else {
//拦截power键按下
interceptPowerKeyUp(event, canceled);
}
break;
}
case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:
// fall through
case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP:
// fall through
case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:
// fall through
case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT: {
result &= ~ACTION_PASS_TO_USER;
interceptSystemNavigationKey(event);
break;
}
case KeyEvent.KEYCODE_SLEEP: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false;
if (!mPowerManager.isInteractive()) {
useHapticFeedback = false; // suppress feedback if already non-interactive
}
if (down) {
sleepPress();
} else {
sleepRelease(event.getEventTime());
}
break;
}
case KeyEvent.KEYCODE_SOFT_SLEEP: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false;
if (!down) {
mPowerManagerInternal.setUserInactiveOverrideFromWindowManager();
}
break;
}
case KeyEvent.KEYCODE_WAKEUP: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = true;
break;
}
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_MEDIA_STOP:
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
if (MediaSessionLegacyHelper.getHelper(mContext).isGlobalPriorityActive()) {
// If the global session is active pass all media keys to it
// instead of the active window.
result &= ~ACTION_PASS_TO_USER;
}
if ((result & ACTION_PASS_TO_USER) == 0) {
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
// only do it if the showing app doesn't process the key on its own.
// Note that we need to make a copy of the key event here because the
// original key event will be recycled when we return.
mBroadcastWakeLock.acquire();
Message msg = mHandler.obtainMessage(MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK,
new KeyEvent(event));
msg.setAsynchronous(true);
msg.sendToTarget();
}
break;
}
case KeyEvent.KEYCODE_CALL: {
if (down) {
TelecomManager telecomManager = getTelecommService();
if (telecomManager != null) {
if (telecomManager.isRinging()) {
Log.i(TAG, "interceptKeyBeforeQueueing:"
+ " CALL key-down while ringing: Answer the call!");
telecomManager.acceptRingingCall();
// And *don't* pass this key thru to the current activity
// (which is presumably the InCallScreen.)
result &= ~ACTION_PASS_TO_USER;
}
}
}
break;
}
case KeyEvent.KEYCODE_ASSIST: {
//Tinno:add by qipeng.wang for task:VFJAAE-82 begin
if (TinnoFeature.FEATURE_HMD_FW_INTERGRATED) {
boolean notprovision = Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.DEVICE_PROVISIONED,0) == 0;
boolean assistGestureDisabled = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ASSIST_GESTURE_ENABLED, 1) == 0;
if (notprovision || assistGestureDisabled){
break;
}
if (down) {
cancelPossibleAssistInKeyguard();
schedulePossibleAssistInKeyguard(keyguardActive);
}else{
cancelPossibleAssistInKeyguard();
}
}else{
final boolean longPressed = event.getRepeatCount() > 0;
if (down && !longPressed) {
Message msg = mHandler.obtainMessage(MSG_LAUNCH_ASSIST, event.getDeviceId(),
0 /* unused */, event.getEventTime() /* eventTime */);
msg.setAsynchronous(true);
msg.sendToTarget();
}
}
//Tinno:add by qipeng.wang for task:VFJAAE-82 end
result &= ~ACTION_PASS_TO_USER;
break;
}
case KeyEvent.KEYCODE_VOICE_ASSIST: {
if (!down) {
mBroadcastWakeLock.acquire();
Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK);
msg.setAsynchronous(true);
msg.sendToTarget();
}
result &= ~ACTION_PASS_TO_USER;
break;
}
case KeyEvent.KEYCODE_WINDOW: {
if (mShortPressOnWindowBehavior == SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE) {
if (mPictureInPictureVisible) {
// Consumes the key only if picture-in-picture is visible to show
// picture-in-picture control menu. This gives a chance to the foreground
// activity to customize PIP key behavior.
if (!down) {
showPictureInPictureMenu(event);
}
result &= ~ACTION_PASS_TO_USER;
}
}
break;
}
}
// Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())) {
switch (keyCode) {
case KeyEvent.KEYCODE_Z: {
if (down && event.isCtrlPressed() && event.isAltPressed()) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT));
result &= ~ACTION_PASS_TO_USER;
}
break;
}
}
}
if (useHapticFeedback) {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
"Virtual Key - Press");
}
if (isWakeKey) {
wakeUpFromWakeKey(event);
}
if ((result & ACTION_PASS_TO_USER) != 0) {
// If the key event is targeted to a specific display, then the user is interacting with
// that display. Therefore, give focus to the display that the user is interacting with.
if (!mPerDisplayFocusEnabled
&& displayId != INVALID_DISPLAY && displayId != mTopFocusedDisplayId) {
// An event is targeting a non-focused display. Move the display to top so that
// it can become the focused display to interact with the user.
// This should be done asynchronously, once the focus logic is fully moved to input
// from windowmanager. Currently, we need to ensure the setInputWindows completes,
// which would force the focus event to be queued before the current key event.
// TODO(b/70668286): post call to 'moveDisplayToTop' to mHandler instead
Log.i(TAG, "Moving non-focused display " + displayId + " to top "
+ "because a key is targeting it");
mWindowManagerFuncs.moveDisplayToTop(displayId);
}
}
return result;
}处理手势handleKeyGesture函数:
private void handleKeyGesture(KeyEvent event, boolean interactive) {
if (mKeyCombinationManager.interceptKey(event, interactive)) {
// handled by combo keys manager.
mSingleKeyGestureDetector.reset();
return;
}
if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) {
//若是power key, 并且是按下去的.
mPowerKeyHandled = handleCameraGesture(event, interactive);
if (mPowerKeyHandled) {
// handled by camera gesture.
mSingleKeyGestureDetector.reset();
return;
}
}
mSingleKeyGestureDetector.interceptKey(event, interactive);
}
5. handleCameraGesture 函数:
android/frameworks/base/services/core/java/com/android/server/GestureLauncherService.java
/**
* @return true if camera was launched, false otherwise.
*/
@VisibleForTesting
boolean handleCameraGesture(boolean useWakelock, int source) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "GestureLauncher:handleCameraGesture");
try {
//判断setup wizard 是否设置完成。
boolean userSetupComplete = isUserSetupComplete();
if (!userSetupComplete) {
if (DBG) {
Slog.d(TAG, String.format(
"userSetupComplete = %s, ignoring camera gesture.",
userSetupComplete));
}
return false;
}
if (DBG) {
Slog.d(TAG, String.format(
"userSetupComplete = %s, performing camera gesture.",
userSetupComplete));
}
//保持常亮0.5s
if (useWakelock) {
// Make sure we don't sleep too early
mWakeLock.acquire(500L);
}
//和SystemUI 服务可以关联起来。
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
//StatusBarManagerInternal 进行调度
service.onCameraLaunchGestureDetected(source);
return true;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
6. StatusBarManagerInternal service
android/frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
/**
* Construct the service
*/
public StatusBarManagerService(Context context) {
...
LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
.../**
* Private API used by NotificationManagerService.
*/
private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
....
@Override
public void onCameraLaunchGestureDetected(int source) {
if (mBar != null) {
try {
mBar.onCameraLaunchGestureDetected(source);
} catch (RemoteException e) {
}
}
}
....
mBar 是通过registerStatusBar 函数注册得到。
android/frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
// ================================================================================
// Callbacks from the status bar service.
// ================================================================================
// TODO(b/118592525): refactor it as an IStatusBar API.
@Override
public RegisterStatusBarResult registerStatusBar(IStatusBar bar) {
enforceStatusBarService();
Slog.i(TAG, "registerStatusBar bar=" + bar);
mBar = bar;
}
android/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@Override
public void start() {
...
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE)); RegisterStatusBarResult result = null;
try {
result = mBarService.registerStatusBar(mCommandQueue);
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
}
mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mBarService 可以看出来,mBarService就是StatusBarManagerService 对象。
对应的注册:
android/frameworks/base/services/java/com/android/server/SystemServer.java
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
if (!isWatch) {
t.traceBegin("StartStatusBarManagerService");
try {
statusBar = new StatusBarManagerService(context);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
reportWtf("starting StatusBarManagerService", e);
}
t.traceEnd();
}
mBarService.registerStatusBar(mCommandQueue); 就是调用StatusBarManagerService的registerStatusBar 函数. 所以 mBar 就是mCommandQueue。
也就是说启动camera 会调用到,由systemui 处理。
android/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@Override
public void onCameraLaunchGestureDetected(int source) {
synchronized (mLock) {
mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE);
mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget();
}
}
case MSG_CAMERA_LAUNCH_GESTURE:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onCameraLaunchGestureDetected(msg.arg1);
}
break;
6. 处理camera手势:handleCameraGesture 函数
// The camera gesture will be detected by GestureLauncherService.
private boolean handleCameraGesture(KeyEvent event, boolean interactive) {
// camera gesture.
if (mGestureLauncherService == null) {
return false;
}
mCameraGestureTriggered = false;
final MutableBoolean outLaunched = new MutableBoolean(false);
//使用GestureLauncherService拦截power信息处理.
final boolean intercept =
mGestureLauncherService.interceptPowerKeyDown(event, interactive, outLaunched);
if (!outLaunched.value) {
// If GestureLauncherService intercepted the power key, but didn't launch camera app,
// we should still return the intercept result. This prevents the single key gesture
// detector from processing the power key later on.
return intercept;
}
mCameraGestureTriggered = true;
if (mRequestedOrSleepingDefaultDisplay) {
mCameraGestureTriggeredDuringGoingToSleep = true;
}
return true;
}
mGestureLauncherService 对应的java类是:
android/frameworks/base/services/core/java/com/android/server/GestureLauncherService.java
/**
* Attempts to intercept power key down event by detecting certain gesture patterns
*
* @param interactive true if the event's policy contains {@code FLAG_INTERACTIVE}
* @param outLaunched true if some action is taken as part of the key intercept (eg, app launch)
* @return true if the key down event is intercepted
*/
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
MutableBoolean outLaunched) {
if (event.isLongPress()) {
// Long presses are sent as a second key down. If the long press threshold is set lower
// than the double tap of sequence interval thresholds, this could cause false double
// taps or consecutive taps, so we want to ignore the long press event.
//长按会误导双击行为,所以将此忽略掉。
return false;
}
boolean launchCamera = false;
boolean launchEmergencyGesture = false;
boolean intercept = false;
long powerTapInterval;
synchronized (this) {
//计算power键按下的时间间隔
powerTapInterval = event.getEventTime() - mLastPowerDown;
mLastPowerDown = event.getEventTime();
if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) {
//时间隔间太长,则重置状态
// Tap too slow, reset consecutive tap counts.
mPowerButtonConsecutiveTaps = 1;
mPowerButtonSlowConsecutiveTaps = 1;
} else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) {
// Tap too slow for shortcuts
//大于camera 启动的最小值,说明点击太慢了。
mPowerButtonConsecutiveTaps = 1;
mPowerButtonSlowConsecutiveTaps++;
} else {
// Fast consecutive tap
//在此区间,判断为快速点击。
mPowerButtonConsecutiveTaps++;
mPowerButtonSlowConsecutiveTaps++;
}
// Check if we need to launch camera or emergency gesture flows
//首先判断Emergency Gesture
if (mEmergencyGestureEnabled) {
// Commit to intercepting the powerkey event after the second "quick" tap to avoid
// lockscreen changes between launching camera and the emergency gesture flow.
//mPowerButtonConsecutiveTaps 要超过一次。
if (mPowerButtonConsecutiveTaps > 1) {
intercept = interactive;
}
if (mPowerButtonConsecutiveTaps == EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD) {
launchEmergencyGesture = true;
}
}
//其次判断是mCameraDoubleTapPowerEnabled
if (mCameraDoubleTapPowerEnabled
&& powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS
&& mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD) {
launchCamera = true;
intercept = interactive;
}
}
if (mPowerButtonConsecutiveTaps > 1 || mPowerButtonSlowConsecutiveTaps > 1) {
Slog.i(TAG, Long.valueOf(mPowerButtonConsecutiveTaps)
+ " consecutive power button taps detected, "
+ Long.valueOf(mPowerButtonSlowConsecutiveTaps)
+ " consecutive slow power button taps detected");
}
//优先camera 启动。
if (launchCamera) {
Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
+ powerTapInterval + "ms");
//启动camera
launchCamera = handleCameraGesture(false /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
//若启动成功,则打印对应的日志。
if (launchCamera) {
mMetricsLogger.action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
(int) powerTapInterval);
mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
}
} else if (launchEmergencyGesture) {
Slog.i(TAG, "Emergency gesture detected, launching.");
launchEmergencyGesture = handleEmergencyGesture();
mUiEventLogger.log(GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
}
mMetricsLogger.histogram("power_consecutive_short_tap_count",
mPowerButtonSlowConsecutiveTaps);
mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval);
outLaunched.value = launchCamera || launchEmergencyGesture;
// Intercept power key event if the press is part of a gesture (camera, eGesture) and the
// user has completed setup.
//
return intercept && isUserSetupComplete();
}
8. 对应的常量:
/**
* Time in milliseconds in which the power button must be pressed twice so it will be considered
* as a camera launch.
*/
@VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300;
/**
* Interval in milliseconds in which the power button must be depressed in succession to be
* considered part of an extended sequence of taps. Note that this is a looser threshold than
* the camera launch gesture, because the purpose of this threshold is to measure the
* frequency of consecutive taps, for evaluation for future gestures.
*/
@VisibleForTesting static final long POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS = 500;
/**
* Number of taps required to launch camera shortcut.
*/
private static final int CAMERA_POWER_TAP_COUNT_THRESHOLD = 2;
9. 对isUserSetupComplete 函数,进行讲解:
@Override
public boolean isUserSetupComplete() {
//判断setup wizard是否设置完成。
boolean isSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
//是否配置FEATURE_LEANBACK
if (mHasFeatureLeanback) {
isSetupComplete &= isTvUserSetupComplete();
} else if (mHasFeatureAuto) {//是否配置 FEATURE_AUTOMOTIVE
10 handleEmergencyGesture 函数讲解:
android/frameworks/base/services/core/java/com/android/server/GestureLauncherService.java
/**
* @return true if emergency gesture UI was launched, false otherwise.
*/
@VisibleForTesting
boolean handleEmergencyGesture() {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"GestureLauncher:handleEmergencyGesture");
try {
boolean userSetupComplete = isUserSetupComplete();
if (!userSetupComplete) {
if (DBG) {
Slog.d(TAG, String.format(
"userSetupComplete = %s, ignoring emergency gesture.",
userSetupComplete));
}
return false;
}
if (DBG) {
Slog.d(TAG, String.format(
"userSetupComplete = %s, performing emergency gesture.",
userSetupComplete));
}
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
service.onEmergencyActionLaunchGestureDetected();
return true;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
上面流程顺便分析了,点击power 启动camera或者Emergency。
二. 简单整理流程:
1. 双击power 键camera的流程:
com_android_server_input_InputManagerService.cpp:: interceptKeyBeforeQueueing()
-->InputManagerService.java::interceptKeyBeforeQueueing()
-->InputManagerCallback.java::interceptKeyBeforeQueueing()
-->PhoneWindowManager.java::interceptKeyBeforeQueueing()
-->PhoneWindowManager.java::handleKeyGesture()
-->GestureLauncherService.java::handleCameraGesture()
--->StatusBarManagerService.java::onCameraLaunchGestureDetected()
-->CommandQueue.java::onCameraLaunchGestureDetected()
--> vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java::onCameraLaunchGestureDetected(int source)
2. 双击power 键Emergency的流程:
com_android_server_input_InputManagerService.cpp:: interceptKeyBeforeQueueing() -->InputManagerService.java::interceptKeyBeforeQueueing() -->InputManagerCallback.java::interceptKeyBeforeQueueing() -->PhoneWindowManager.java::interceptKeyBeforeQueueing() -->PhoneWindowManager.java::handleKeyGesture()-->GestureLauncherService.java::handleEmergencyGesture()--->CommandQueue.java::onEmergencyActionLaunchGestureDetected() --> vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java::onEmergencyActionLaunchGestureDetected()
3. 亮屏流程:
(1). interceptKeyBeforeQueueing 函数
android/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
// TODO(b/117479243): handle it in InputPolicy
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
...
case KeyEvent.KEYCODE_POWER: {
EventLogTags.writeInterceptPower(
KeyEvent.actionToString(event.getAction()),
mPowerKeyHandled ? 1 : 0,
mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER));
// Any activity on the power button stops the accessibility shortcut
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactiveAndOn);
} else {
interceptPowerKeyUp(event, canceled);
}
break;
}
...
}
(2) interceptPowerKeyDown 函数分析:
android/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
//拦截power键down
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
// Hold a wake lock until the power key is released.
// 获取一个wakelock,防止cpu在此流程期间休眠
if (!mPowerKeyWakeLock.isHeld()) {
mPowerKeyWakeLock.acquire();
}
mWindowManagerFuncs.onPowerKeyDown(interactive);
// Stop ringing or end call if configured to do so when power is pressed.
//对于来电场景下,按下power键的处理
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
//如果配置为在按下电源时停止响铃或结束通话,则停止响铃或结束通话。
telecomManager.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telecomManager.isInCall() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
//若正在打电话,则关掉电话。
hungUp = telecomManager.endCall();
}
}
final boolean handledByPowerManager = mPowerManagerInternal.interceptPowerKeyDown(event);
// Inform the StatusBar; but do not allow it to consume the event.
//通知SystemUI处理
sendSystemKeyToStatusBarAsync(event.getKeyCode());
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
//
mPowerKeyHandled = mPowerKeyHandled || hungUp
|| handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
//此时还没有被处理
if (!mPowerKeyHandled) {
//若不是交互
if (!interactive) {
//使用电源键唤醒。
wakeUpFromPowerKey(event.getDownTime());
}
} else {
// handled by another power key policy.
if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
mSingleKeyGestureDetector.reset();
}
}
}
(3) wakeUpFromPowerKey函数
android/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
private void wakeUpFromPowerKey(long eventTime) {
//唤醒屏幕
if (wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER")) {
// Start HOME with "reason" extra if sleeping for more than mWakeUpToLastStateTimeout
//是否发生HOME intent,默认是不发送。
if (shouldWakeUpWithHomeIntent()) {
startDockOrHome(DEFAULT_DISPLAY, /*fromHomeKey*/ false, /*wakenFromDreams*/ true,
PowerManager.wakeReasonToString(PowerManager.WAKE_REASON_POWER_BUTTON));
}
}
}
(4)wakeUp 函数
private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
String details) {
final boolean theaterModeEnabled = isTheaterModeEnabled();
//唤醒不是TheaterMode,而且此时的theaterMode 是打开的。
if (!wakeInTheaterMode && theaterModeEnabled) {
return false;
}
//若theaterMode,则将此值设置false
if (theaterModeEnabled) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.THEATER_MODE_ON, 0);
}
//最终使用PMS的wakeup的函数
mPowerManager.wakeUp(wakeTime, reason, details);
return true;
}
wakeUp对应的函数:
android/frameworks/base/core/java/android/os/PowerManager.java
/**
* Forces the {@link android.view.Display#DEFAULT_DISPLAY default display} to turn on.
*
* <p>If the {@link android.view.Display#DEFAULT_DISPLAY default display} is turned off it will
* be turned on. Additionally, if the device is asleep it will be awoken. If the {@link
* android.view.Display#DEFAULT_DISPLAY default display} is already on then nothing will happen.
*
* <p>If the device is an Android TV playback device, it will attempt to turn on the
* HDMI-connected TV and become the current active source via the HDMI-CEC One Touch Play
* feature.
*
* <p>
* This is what happens when the power key is pressed to turn on the screen.
* </p><p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
* </p>
*
* @param time The time when the request to wake up was issued, in the
* {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly
* order the wake up request with other power management functions. It should be set
* to the timestamp of the input event that caused the request to wake up.
*
* @param reason The reason for the wake up.
*
* @param details A free form string to explain the specific details behind the wake up for
* debugging purposes.
*
* @see #userActivity
* @see #goToSleep
* @hide
*/
public void wakeUp(long time, @WakeReason int reason, String details) {
try {
mService.wakeUp(time, reason, details, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
(6)mService.wakeUp 对应的函数:
android/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
@Override // Binder call
public void wakeUp(long eventTime, @WakeReason int reason, String details,
String opPackageName) {
if (eventTime > mClock.uptimeMillis()) {
throw new IllegalArgumentException("event time must not be in the future");
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
wakeDisplayGroup(Display.DEFAULT_DISPLAY_GROUP, eventTime, reason, details, uid,
opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
(7) 对reason 常量进行解释:
android/frameworks/base/core/java/android/os/PowerManager.java
/**
* Wake up reason code: Waking for an unknown reason.
* @hide
*/
public static final int WAKE_REASON_UNKNOWN = 0;
/**
* Wake up reason code: Waking up due to power button press.
* @hide
*/
public static final int WAKE_REASON_POWER_BUTTON = 1;
/**
* Wake up reason code: Waking up because an application requested it.
* @hide
*/
public static final int WAKE_REASON_APPLICATION = 2;
/**
* Wake up reason code: Waking up due to being plugged in or docked on a wireless charger.
* @hide
*/
public static final int WAKE_REASON_PLUGGED_IN = 3;
/**
* Wake up reason code: Waking up due to a user performed gesture (e.g. douple tapping on the
* screen).
* @hide
*/
public static final int WAKE_REASON_GESTURE = 4;
/**
* Wake up reason code: Waking up due to the camera being launched.
* @hide
*/
public static final int WAKE_REASON_CAMERA_LAUNCH = 5;
/**
* Wake up reason code: Waking up because a wake key other than power was pressed.
* @hide
*/
public static final int WAKE_REASON_WAKE_KEY = 6;
/**
* Wake up reason code: Waking up because a wake motion was performed.
*
* For example, a trackball that was set to wake the device up was spun.
* @hide
*/
public static final int WAKE_REASON_WAKE_MOTION = 7;
/**
* Wake up reason code: Waking due to HDMI.
* @hide
*/
public static final int WAKE_REASON_HDMI = 8;
/**
* Wake up reason code: Waking due to the lid being opened.
* @hide
*/
public static final int WAKE_REASON_LID = 9;
/**
* Wake up reason code: Waking due to display group being added.
* @hide
*/
public static final int WAKE_REASON_DISPLAY_GROUP_ADDED = 10;
/**
* Wake up reason code: Waking due to display group being powered on.
* @hide
*/
public static final int WAKE_REASON_DISPLAY_GROUP_TURNED_ON = 11;
(8) wakeDisplayGroup
android/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void wakeDisplayGroup(int groupId, long eventTime, @WakeReason int reason,
String details, int uid, String opPackageName, int opUid) {
synchronized (mLock) {
// 判断是否可以进行亮屏,设置Wakefulness以及相关参数,发送亮屏广播
if (wakeDisplayGroupNoUpdateLocked(groupId, eventTime, reason, details, uid,
opPackageName, opUid)) {
// 更新PMS中状态参数,通知DPC处理亮屏操作
updatePowerStateLocked();
}
}
}
(9) wakeDisplayGroupNoUpdateLocked 函数分析:
android/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private boolean wakeDisplayGroupNoUpdateLocked(int groupId, long eventTime,
@WakeReason int reason, String details, int uid, String opPackageName, int opUid) {
if (DEBUG_SPEW) {
Slog.d(TAG, "wakeDisplayGroupNoUpdateLocked: eventTime=" + eventTime
+ ", groupId=" + groupId + ", uid=" + uid);
}
// 判断触发时间是否正确,系统是否挂起或者是否还在开机状态
if (eventTime < mLastSleepTime || mForceSuspendActive || !mSystemReady) {
return false;
}
final int currentState = mDisplayGroupPowerStateMapper.getWakefulnessLocked(groupId);
//设备已经完全唤醒
if (currentState == WAKEFULNESS_AWAKE) {
//没有开机完成并且sQuiescent 为true
if (!mBootCompleted && sQuiescent) {
mDirty |= DIRTY_QUIESCENT;
return true;
}
return false;
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "powerOnDisplay");
try {
Slog.i(TAG, "Powering on display group from"
+ PowerManagerInternal.wakefulnessToString(currentState)
+ " (groupId=" + groupId
+ ", uid=" + uid
+ ", reason=" + PowerManager.wakeReasonToString(reason)
+ ", details=" + details
+ ")...");
Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, groupId);
//设置Wakefulness,设置为亮屏
setWakefulnessLocked(groupId, WAKEFULNESS_AWAKE, eventTime, uid, reason, opUid,
opPackageName, details);
//
mDisplayGroupPowerStateMapper.setLastPowerOnTimeLocked(groupId, eventTime);
mDisplayGroupPowerStateMapper.setPoweringOnLocked(groupId, true);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
/**
* Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep().
* When the user activity timeout expires, the device may start dreaming or go to sleep.
*/
public static final int WAKEFULNESS_AWAKE = 1;// True if the lights should stay off until an explicit user action.
private static boolean sQuiescent;// Dirty bit: display group wakefulness has changed
private static final int DIRTY_DISPLAY_GROUP_WAKEFULNESS = 1 << 16;
(10)
setWakefulnessLocked 函数分析:
@VisibleForTesting
void setWakefulnessLocked(int groupId, int wakefulness, long eventTime, int uid, int reason,
int opUid, String opPackageName, String details) {
//表示在groupId 设置wakefulness 值是否成功,若设置成功则为true.
if (mDisplayGroupPowerStateMapper.setWakefulnessLocked(groupId, wakefulness)) { //增加flag表示唤醒状态发生了变化。
mDirty |= DIRTY_DISPLAY_GROUP_WAKEFULNESS;
// 设置全局参数状态,并对亮屏工作进行准备
setGlobalWakefulnessLocked(
mDisplayGroupPowerStateMapper.getGlobalWakefulnessLocked(),
eventTime, reason, uid, opUid, opPackageName, details); //
if (wakefulness == WAKEFULNESS_AWAKE) {
// Kick user activity to prevent newly awake group from timing out instantly.
userActivityNoUpdateLocked(
groupId, eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
}
}
}此函数中最重要的就是参数mDirty,这个是PMS中一个非常重要的标志位,通过对它的位运算,可以知晓当前power状态是否发生变化,根据变化的位置可以进行对应的业务操作。
(11) setGlobalWakefulnessLocked函数分析:
private void setGlobalWakefulnessLocked(int wakefulness, long eventTime, int reason, int uid,
int opUid, String opPackageName, String details) {
if (getWakefulnessLocked() == wakefulness) {
//若和当前状态是一样的,说明没有变化,则直接返回。
return;
}
// Phase 1: Handle pre-wakefulness change bookkeeping.
final String traceMethodName;
switch (wakefulness) {
case WAKEFULNESS_ASLEEP:
traceMethodName = "reallyGoToSleep";
Slog.i(TAG, "Sleeping (uid " + uid + ")...");
break;
case WAKEFULNESS_AWAKE:
traceMethodName = "wakeUp";
Slog.i(TAG, "Waking up from "
+ PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ " (uid=" + uid
+ ", reason=" + PowerManager.wakeReasonToString(reason)
+ ", details=" + details
+ ")...");
mLastWakeTime = eventTime;
mLastWakeReason = reason;
break;
case WAKEFULNESS_DREAMING:
traceMethodName = "nap";
Slog.i(TAG, "Nap time (uid " + uid + ")...");
break;
case WAKEFULNESS_DOZING:
traceMethodName = "goToSleep";
Slog.i(TAG, "Going to sleep due to " + PowerManager.sleepReasonToString(reason)
+ " (uid " + uid + ")...");
mLastSleepTime = eventTime;
mLastSleepReason = reason;
mDozeStartInProgress = true;
break;
default:
throw new IllegalArgumentException("Unexpected wakefulness: " + wakefulness);
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, traceMethodName);
try {
// Phase 2: Handle wakefulness change and bookkeeping.
// Under lock, invalidate before set ensures caches won't return stale values.
mInjector.invalidateIsInteractiveCaches();
mWakefulnessRaw = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
// This is only valid while we are in wakefulness dozing. Set to false otherwise.
mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);
if (mNotifier != null) {
// 通知系统中其他模块Wakefulness开始变化,发送亮屏广播
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
}
mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
// Phase 3: Handle post-wakefulness change bookkeeping.
switch (wakefulness) {
case WAKEFULNESS_AWAKE:
mNotifier.onWakeUp(reason, details, uid, opPackageName, opUid);
if (sQuiescent) {
mDirty |= DIRTY_QUIESCENT;
}
break;
case WAKEFULNESS_DOZING:
// 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++) {
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;
}
}
EventLogTags.writePowerSleepRequested(numWakeLocksCleared);
break;
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}(11) onWakefulnessChangeStarted函数分析:
frameworks/base/services/core/java/com/android/server/power/Notifier.java
/**
* Notifies that the device is changing wakefulness.
* This function may be called even if the previous change hasn't finished in
* which case it will assume that the state did not fully converge before the
* next transition began and will recover accordingly.
*/
public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
if (DEBUG) {
Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
+ ", reason=" + reason + ", interactive=" + interactive);
}
// Tell the activity manager about changes in wakefulness, not just interactivity.
// It needs more granularity than other components.
mHandler.post(new Runnable() {
@Override
public void run() {
mActivityManagerInternal.onWakefulnessChanged(wakefulness);
}
});
// Handle any early interactive state changes.
// Finish pending incomplete ones from a previous cycle.
if (mInteractive != interactive) {
// Finish up late behaviors if needed.
if (mInteractiveChanging) {
handleLateInteractiveChange();
}
// Start input as soon as we start waking up or going to sleep.
mInputManagerInternal.setInteractive(interactive);
mInputMethodManagerInternal.setInteractive(interactive);
// Notify battery stats.
try {
mBatteryStats.noteInteractive(interactive);
} catch (RemoteException ex) { }
FrameworkStatsLog.write(FrameworkStatsLog.INTERACTIVE_STATE_CHANGED,
interactive ? FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :
FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);
// Handle early behaviors.
mInteractive = interactive;
mInteractiveChangeReason = reason;
mInteractiveChangeStartTime = eventTime;
mInteractiveChanging = true;
//发送亮屏广播
handleEarlyInteractiveChange();
}
}
(12)handleEarlyInteractiveChange 函数:
frameworks/base/services/core/java/com/android/server/power/Notifier.java
/**
* Handle early interactive state changes such as getting applications or the lock
* screen running and ready for the user to see (such as when turning on the screen).
*/
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
// Waking up...
// 通知WMS正在亮屏
mHandler.post(() -> mPolicy.startedWakingUp(mInteractiveChangeReason));
// Send interactive broadcast.
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
mPendingWakeUpBroadcast = true;
//发送广播
updatePendingBroadcastLocked();
} else {
// Going to sleep...
// Tell the policy that we started going to sleep.
mHandler.post(() -> mPolicy.startedGoingToSleep(mInteractiveChangeReason));
}
}
}
private void updatePendingBroadcastLocked() {
if (!mBroadcastInProgress
&& mPendingInteractiveState != INTERACTIVE_STATE_UNKNOWN
&& (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState != mBroadcastedInteractiveState)) {
mBroadcastInProgress = true;
mSuspendBlocker.acquire();
Message msg = mHandler.obtainMessage(MSG_BROADCAST);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}case MSG_BROADCAST:
sendNextBroadcast();
sendNextBroadcast
private void sendNextBroadcast() {
final int powerState;
synchronized (mLock) {
if (mBroadcastedInteractiveState == INTERACTIVE_STATE_UNKNOWN) {
// Broadcasted power state is unknown.
// Send wake up or go to sleep.
switch (mPendingInteractiveState) {
case INTERACTIVE_STATE_ASLEEP:
mPendingGoToSleepBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
break;
case INTERACTIVE_STATE_AWAKE:
default:
mPendingWakeUpBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
break;
}
} else if (mBroadcastedInteractiveState == INTERACTIVE_STATE_AWAKE) {
// Broadcasted power state is awake. Send asleep if needed.
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_ASLEEP) {
mPendingGoToSleepBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_ASLEEP;
} else {
finishPendingBroadcastLocked();
return;
}
} else {
// Broadcasted power state is asleep. Send awake if needed.
if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
|| mPendingInteractiveState == INTERACTIVE_STATE_AWAKE) {
mPendingWakeUpBroadcast = false;
mBroadcastedInteractiveState = INTERACTIVE_STATE_AWAKE;
} else {
finishPendingBroadcastLocked();
return;
}
}
mBroadcastStartTime = SystemClock.uptimeMillis();
powerState = mBroadcastedInteractiveState;
}
//event log记录
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
if (powerState == INTERACTIVE_STATE_AWAKE) {
//发送亮屏广播
sendWakeUpBroadcast();
} else {
sendGoToSleepBroadcast();
}
}
(14) sendWakeUpBroadcast
private void sendWakeUpBroadcast() {
if (DEBUG) {
Slog.d(TAG, "Sending wake up broadcast.");
}
if (mActivityManagerInternal.isSystemReady()) {
//若AMS已经加载完成。
//发送亮屏广播,针对所有的USER
mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
mWakeUpBroadcastDone, mHandler, 0, null, null);
} else {
//log记录:
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
sendNextBroadcast();
}
}
mScreenOnIntent
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
mScreenOnIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
流程总结:
[1] 当收到电话铃声时,此时按下Power键,则停止响铃或结束通话。
关掉电话。
[3] 亮屏广播流程:
发送Intent.ACTION_SCREEN_ON的流程。PhoneWindowManager.java::interceptKeyBeforeQueueing()
---> PhoneWindowManager.java::interceptPowerKeyDown()
---> PhoneWindowManager.java::wakeUpFromPowerKey()
---> PhoneWindowManager.java::wakeUp()
---> PowerManager.java::wakeUp()
---> PowerManagerService.java::wakeUp()
---> PowerManagerService.java::wakeDisplayGroup()
---> PowerManagerService.java::wakeDisplayGroupNoUpdateLocked()
---> PowerManagerService.java::setWakefulnessLocked()
---> PowerManagerService.java::setGlobalWakefulnessLocked()
---> Notifier.java::onWakefulnessChangeStarted()
---> Notifier.java:: handleEarlyInteractiveChange()
---> Notifier.java:: updatePendingBroadcastLocked()
---> Notifier.java::updatePendingBroadcastLocked()
---> Notifier.java::sendNextBroadcast()
---> Notifier.java::sendWakeUpBroadcast()三. DisplayPowerController处理
DisplayPowerController 管理设备Display状态,主要处理近距sensor,亮灭屏.
PMS updatePowerStateLocked中进行DPC侧业务处理的发起
(1) updatePowerStateLocked函数:
// Phase 3: Update display power state.
final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
/**
* Updates the display power state asynchronously.
* When the update is finished, the ready state of the displays will be updated. The display
* controllers post a message to tell us when the actual display power state
* has been updated so we come back here to double-check and finish up.
*
* This function recalculates the display power state each time.
*
* @return {@code true} if all displays became ready; {@code false} otherwise
*/
private boolean updateDisplayPowerStateLocked(int dirty) {
...
//申请电源的状态。
final boolean ready =
mDisplayManagerInternal.requestPowerState(groupId,
displayPowerRequest, mRequestWaitForNegativeProximity);
...
}
这里最后调用了mDisplayManagerInternal的requestPowerState方法,DisplayManagerInternal是一个抽象类,其具体实现的类是DisplayManagerService,在其重写的方法中发起了对DPC的调用。
四. 阻塞亮屏
在DPC中,最主要的一个业务就是进行亮屏前的最后准备,为什么说是亮屏前呢?因为里面有一个非常重要的环节就是阻塞亮屏,试想如果直接点亮屏幕,可能会出现什么情况,首先可能出现窗口还没有绘制,用户会观看到整个窗口绘制的过程,或者锁屏没有绘制,这样用户体验很差,所以在点亮屏幕前,我们需要进行一个阻塞亮屏的流程。
(1) requestPowerState
android/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
/**
* Requests a new power state.
* The controller makes a copy of the provided object and then
* begins adjusting the power state to match what was requested.
*
* @param request The requested power state.
* @param waitForNegativeProximity If true, issues a request to wait for
* negative proximity before turning the screen back on, assuming the screen
* was turned off by the proximity sensor.
* @return True if display is ready, false if there are important changes that must
* be made asynchronously (such as turning the screen on), in which case the caller
* should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
* then try the request again later until the state converges.
*/
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
...
if (changed) {
mDisplayReadyLocked = false; /
if (!mPendingRequestChangedLocked) { /如果没有等待正在处理电源状态信息,将状态变成正在等待处理状态。
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
}
...
}private void sendUpdatePowerStateLocked() {
if (!mStopped && !mPendingUpdatePowerStateLocked) {
mPendingUpdatePowerStateLocked = true;
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
mHandler.sendMessage(msg);
}
}@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_POWER_STATE:
updatePowerState();
break;
updatePowerState函数分析:
private void updatePowerState() {
// Update the power state request.
// 更新power 状态
final boolean mustNotify;
final int previousPolicy;
boolean mustInitialize = false;
int brightnessAdjustmentFlags = 0;
//将BrightnessReasonTemp 清空
mBrightnessReasonTemp.set(null);
synchronized (mLock) {
//DisplayPowerController若已经停止,则直接返回。
if (mStopped) {
return;
}
//恢复mPendingUpdatePowerStateLocked 便于sendUpdatePowerStateLocked函数
mPendingUpdatePowerStateLocked = false;
if (mPendingRequestLocked == null) {
//mPendingRequestLocked变量为null,说明requestPowerState没有被调用,所以需要等待。
return; // wait until first actual power request
}
if (mPowerRequest == null) {
mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
updatePendingProximityRequestsLocked();
mPendingRequestChangedLocked = false;
mustInitialize = true;
// Assume we're on and bright until told otherwise, since that's the state we turn
// on in.
previousPolicy = DisplayPowerRequest.POLICY_BRIGHT;
} else if (mPendingRequestChangedLocked) {
previousPolicy = mPowerRequest.policy;
mPowerRequest.copyFrom(mPendingRequestLocked);
updatePendingProximityRequestsLocked();
mPendingRequestChangedLocked = false;
mDisplayReadyLocked = false;
} else {
previousPolicy = mPowerRequest.policy;
}
mustNotify = !mDisplayReadyLocked;
}
// Compute the basic display state using the policy.
// We might override this below based on other factors.
// Initialise brightness as invalid.
int state;
//初始化亮度状态为无效
float brightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
boolean performScreenOffTransition = false;
switch (mPowerRequest.policy) {
//灭屏状态
case DisplayPowerRequest.POLICY_OFF:
state = Display.STATE_OFF;
performScreenOffTransition = true;
break;
//doze状态
case DisplayPowerRequest.POLICY_DOZE:
if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) {
state = mPowerRequest.dozeScreenState;
} else {
state = Display.STATE_DOZE;
}
//不允许在低电量情况下,不允许自动调节亮度.
if (!mAllowAutoBrightnessWhileDozingConfig) {
//针对doze 进行设置.
brightnessState = mPowerRequest.dozeScreenBrightness;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE);
}
break;
case DisplayPowerRequest.POLICY_VR:
state = Display.STATE_VR;
break;
case DisplayPowerRequest.POLICY_DIM:
case DisplayPowerRequest.POLICY_BRIGHT:
default:
state = Display.STATE_ON;
break;
}
assert(state != Display.STATE_UNKNOWN);
// Initialize things the first time the power state is changed.
//初始化,则需要实例化数据
if (mustInitialize) {
initialize(state);
}
// Apply the proximity sensor.
//判断是否存在ProximitySensor
if (mProximitySensor != null) {
if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) {
// At this point the policy says that the screen should be on, but we've been
// asked to listen to the prox sensor to adjust the display state, so lets make
// sure the sensor is on.
setProximitySensorEnabled(true);
//mScreenOffBecauseOfProximity 为false,表示远离屏幕.
//sensor的距离是有效的.
//mIgnoreProximityUntilChanged 忽略
if (!mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE
&& !mIgnoreProximityUntilChanged) {
// Prox sensor already reporting "near" so we should turn off the screen.
// Also checked that we aren't currently set to ignore the proximity sensor
// temporarily.
//屏幕关闭因为靠近屏幕
mScreenOffBecauseOfProximity = true;
//
sendOnProximityPositiveWithWakelock();
}
} else if (mWaitingForNegativeProximity
&& mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE
&& state != Display.STATE_OFF) {
// The policy says that we should have the screen on, but it's off due to the prox
// and we've been asked to wait until the screen is far from the user to turn it
// back on. Let keep the prox sensor on so we can tell when it's far again.
setProximitySensorEnabled(true);
} else {
// We haven't been asked to use the prox sensor and we're not waiting on the screen
// to turn back on...so lets shut down the prox sensor.
setProximitySensorEnabled(false);
mWaitingForNegativeProximity = false;
}
if (mScreenOffBecauseOfProximity
&& (mProximity != PROXIMITY_POSITIVE || mIgnoreProximityUntilChanged)) {
// The screen *was* off due to prox being near, but now it's "far" so lets turn
// the screen back on. Also turn it back on if we've been asked to ignore the
// prox sensor temporarily.
mScreenOffBecauseOfProximity = false;
sendOnProximityNegativeWithWakelock();
}
} else {
mWaitingForNegativeProximity = false;
mIgnoreProximityUntilChanged = false;
}
if (!mLogicalDisplay.isEnabled()
|| mLogicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION
|| mScreenOffBecauseOfProximity) {
state = Display.STATE_OFF;
}
// Animate the screen state change unless already animating.
// The transition may be deferred, so after this point we will use the
// actual state instead of the desired one.
final int oldState = mPowerState.getScreenState();
// 准备执行屏幕变化动画,这里也可以认为是发起亮屏动画
animateScreenStateChange(state, performScreenOffTransition);
//获取屏幕状态,此时已经设置新的屏幕状态
state = mPowerState.getScreenState();
//如果屏幕此时的状态为灭屏,设置亮度为0
if (state == Display.STATE_OFF) {
brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
//说明亮度调节的原因
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF);
}
// Always use the VR brightness when in the VR state.
//若处于VR状态,则调节相应VR的亮度
if (state == Display.STATE_VR) {
brightnessState = mScreenBrightnessForVr;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_VR);
}
//brightnessState是非法数字,并且screen Brightness的Override 是有效值
//将screen Brightness的Override的值赋值给brightnessState
if ((Float.isNaN(brightnessState))
&& isValidBrightnessValue(mPowerRequest.screenBrightnessOverride)) {
brightnessState = mPowerRequest.screenBrightnessOverride;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_OVERRIDE);
mAppliedScreenBrightnessOverride = true;
} else {
//将mAppliedScreenBrightnessOverride 对应值设置为无效
mAppliedScreenBrightnessOverride = false;
}
//在Doze模式下自动调节亮度是否可用
final boolean autoBrightnessEnabledInDoze =
mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
//自动调节亮度是否可用
final boolean autoBrightnessEnabled = mPowerRequest.useAutoBrightness
&& (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
&& Float.isNaN(brightnessState)
&& mAutomaticBrightnessController != null;
//用户是否设置了亮度
final boolean userSetBrightnessChanged = updateUserSetScreenBrightness();
// Use the temporary screen brightness if there isn't an override, either from
// WindowManager or based on the display state.
//使用临时亮度
if (isValidBrightnessValue(mTemporaryScreenBrightness)) {
brightnessState = mTemporaryScreenBrightness;
mAppliedTemporaryBrightness = true;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_TEMPORARY);
} else {
mAppliedTemporaryBrightness = false;
}
//自动亮度调节
final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
//使用自动调节亮度,则将mTemporaryAutoBrightnessAdjustment 值可以赋值为无效值
if (autoBrightnessAdjustmentChanged) {
mTemporaryAutoBrightnessAdjustment = Float.NaN;
}
// Use the autobrightness adjustment override if set.
final float autoBrightnessAdjustment;
if (!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) {
autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment;
brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO_TEMP;
mAppliedTemporaryAutoBrightnessAdjustment = true;
} else {
autoBrightnessAdjustment = mAutoBrightnessAdjustment;
brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO;
mAppliedTemporaryAutoBrightnessAdjustment = false;
}
// Apply brightness boost.
// We do this here after deciding whether auto-brightness is enabled so that we don't
// disable the light sensor during this temporary state. That way when boost ends we will
// be able to resume normal auto-brightness behavior without any delay.
if (mPowerRequest.boostScreenBrightness
&& brightnessState != PowerManager.BRIGHTNESS_OFF_FLOAT) {
brightnessState = PowerManager.BRIGHTNESS_MAX;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_BOOST);
mAppliedBrightnessBoost = true;
} else {
mAppliedBrightnessBoost = false;
}
// If the brightness is already set then it's been overridden by something other than the
// user, or is a temporary adjustment.
boolean userInitiatedChange = (Float.isNaN(brightnessState))
&& (autoBrightnessAdjustmentChanged || userSetBrightnessChanged);
boolean hadUserBrightnessPoint = false;
// Configure auto-brightness.
if (mAutomaticBrightnessController != null) {
hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mBrightnessConfiguration,
mLastUserSetScreenBrightness,
userSetBrightnessChanged, autoBrightnessAdjustment,
autoBrightnessAdjustmentChanged, mPowerRequest.policy);
}
if (mBrightnessTracker != null) {
mBrightnessTracker.setBrightnessConfiguration(mBrightnessConfiguration);
}
boolean updateScreenBrightnessSetting = false;
// Apply auto-brightness.
boolean slowChange = false;
if (Float.isNaN(brightnessState)) {
float newAutoBrightnessAdjustment = autoBrightnessAdjustment;
if (autoBrightnessEnabled) {
brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness();
newAutoBrightnessAdjustment =
mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment();
}
if (isValidBrightnessValue(brightnessState)
|| brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) {
// Use current auto-brightness value and slowly adjust to changes.
brightnessState = clampScreenBrightness(brightnessState);
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
updateScreenBrightnessSetting = true;
mAppliedAutoBrightness = true;
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC);
} else {
mAppliedAutoBrightness = false;
}
if (autoBrightnessAdjustment != newAutoBrightnessAdjustment) {
// If the autobrightness controller has decided to change the adjustment value
// used, make sure that's reflected in settings.
putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment);
} else {
// Adjustment values resulted in no change
brightnessAdjustmentFlags = 0;
}
} else {
// Any non-auto-brightness values such as override or temporary should still be subject
// to clamping so that they don't go beyond the current max as specified by HBM
// Controller.
brightnessState = clampScreenBrightness(brightnessState);
mAppliedAutoBrightness = false;
brightnessAdjustmentFlags = 0;
}
// Use default brightness when dozing unless overridden.
if ((Float.isNaN(brightnessState))
&& Display.isDozeState(state)) {
brightnessState = clampScreenBrightness(mScreenBrightnessDozeConfig);
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
}
// Apply manual brightness.
if (Float.isNaN(brightnessState)) {
brightnessState = clampScreenBrightness(mCurrentScreenBrightnessSetting);
if (brightnessState != mCurrentScreenBrightnessSetting) {
// The manually chosen screen brightness is outside of the currently allowed
// range (i.e., high-brightness-mode), make sure we tell the rest of the system
// by updating the setting.
updateScreenBrightnessSetting = true;
}
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL);
}
// The current brightness to use has been calculated at this point (minus the adjustments
// like low-power and dim), and HbmController should be notified so that it can accurately
// calculate HDR or HBM levels. We specifically do it here instead of having HbmController
// listen to the brightness setting because certain brightness sources (just as an app
// override) are not saved to the setting, but should be reflected in HBM
// calculations.
mHbmController.onBrightnessChanged(brightnessState);
if (updateScreenBrightnessSetting) {
// Tell the rest of the system about the new brightness in case we had to change it
// for things like auto-brightness or high-brightness-mode. Note that we do this
// before applying the low power or dim transformations so that the slider
// accurately represents the full possible range, even if they range changes what
// it means in absolute terms.
putScreenBrightnessSetting(brightnessState, /* updateCurrent */ true);
}
// We save the brightness info *after* the brightness setting has been changed so that
// the brightness info reflects the latest value.
saveBrightnessInfo(getScreenBrightnessSetting());
// Apply dimming by at least some minimum amount when user activity
// timeout is about to expire.
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightnessState > PowerManager.BRIGHTNESS_MIN) {
brightnessState = Math.max(
Math.min(brightnessState - SCREEN_DIM_MINIMUM_REDUCTION_FLOAT,
mScreenBrightnessDimConfig),
PowerManager.BRIGHTNESS_MIN);
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_DIMMED);
}
if (!mAppliedDimming) {
slowChange = false;
}
mAppliedDimming = true;
} else if (mAppliedDimming) {
slowChange = false;
mAppliedDimming = false;
}
// If low power mode is enabled, scale brightness by screenLowPowerBrightnessFactor
// as long as it is above the minimum threshold.
if (mPowerRequest.lowPowerMode) {
if (brightnessState > PowerManager.BRIGHTNESS_MIN) {
final float brightnessFactor =
Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1);
final float lowPowerBrightnessFloat = (brightnessState * brightnessFactor);
brightnessState = Math.max(lowPowerBrightnessFloat, PowerManager.BRIGHTNESS_MIN);
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_LOW_POWER);
}
if (!mAppliedLowPower) {
slowChange = false;
}
mAppliedLowPower = true;
} else if (mAppliedLowPower) {
slowChange = false;
mAppliedLowPower = false;
}
// Animate the screen brightness when the screen is on or dozing.
// Skip the animation when the screen is off or suspended or transition to/from VR.
if (!mPendingScreenOff) {
if (mSkipScreenOnBrightnessRamp) {
if (state == Display.STATE_ON) {
if (mSkipRampState == RAMP_STATE_SKIP_NONE && mDozing) {
mInitialAutoBrightness = brightnessState;
mSkipRampState = RAMP_STATE_SKIP_INITIAL;
} else if (mSkipRampState == RAMP_STATE_SKIP_INITIAL
&& mUseSoftwareAutoBrightnessConfig
&& !BrightnessSynchronizer.floatEquals(brightnessState,
mInitialAutoBrightness)) {
mSkipRampState = RAMP_STATE_SKIP_AUTOBRIGHT;
} else if (mSkipRampState == RAMP_STATE_SKIP_AUTOBRIGHT) {
mSkipRampState = RAMP_STATE_SKIP_NONE;
}
} else {
mSkipRampState = RAMP_STATE_SKIP_NONE;
}
}
final boolean wasOrWillBeInVr =
(state == Display.STATE_VR || oldState == Display.STATE_VR);
final boolean initialRampSkip =
state == Display.STATE_ON && mSkipRampState != RAMP_STATE_SKIP_NONE;
// While dozing, sometimes the brightness is split into buckets. Rather than animating
// through the buckets, which is unlikely to be smooth in the first place, just jump
// right to the suggested brightness.
final boolean hasBrightnessBuckets =
Display.isDozeState(state) && mBrightnessBucketsInDozeConfig;
// If the color fade is totally covering the screen then we can change the backlight
// level without it being a noticeable jump since any actual content isn't yet visible.
final boolean isDisplayContentVisible =
mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f;
final boolean brightnessIsTemporary =
mAppliedTemporaryBrightness || mAppliedTemporaryAutoBrightnessAdjustment;
// We only want to animate the brightness if it is between 0.0f and 1.0f.
// brightnessState can contain the values -1.0f and NaN, which we do not want to
// animate to. To avoid this, we check the value first.
// If the brightnessState is off (-1.0f) we still want to animate to the minimum
// brightness (0.0f) to accommodate for LED displays, which can appear bright to the
// user even when the display is all black. We also clamp here in case some
// transformations to the brightness have pushed it outside of the currently
// allowed range.
float animateValue = clampScreenBrightness(brightnessState);
//Tinno: add by qipeng.wang for bug:DGF-21 date:2022-11-07 begin
if(mBrightnessReasonTemp.reason == BrightnessReason.REASON_TEMPORARY && TinnoFeature.FEATURE_HMD_BRIGHTNESS_CURVE) {
if(animateValue < 0.8189f){
Settings.System.putIntForUser(mContext.getContentResolver(), "brightness_boost_mode", 0, UserHandle.USER_CURRENT);
}
}
//Tinno: add by qipeng.wang for bug:DGF-21 date:2022-11-07 begin
// If there are any HDR layers on the screen, we have a special brightness value that we
// use instead. We still preserve the calculated brightness for Standard Dynamic Range
// (SDR) layers, but the main brightness value will be the one for HDR.
float sdrAnimateValue = animateValue;
if (mHbmController.getHighBrightnessMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
&& ((mBrightnessReason.modifier & BrightnessReason.MODIFIER_DIMMED) == 0
|| (mBrightnessReason.modifier & BrightnessReason.MODIFIER_LOW_POWER) == 0)) {
// We want to scale HDR brightness level with the SDR level
animateValue = mHbmController.getHdrBrightnessValue();
}
final float currentBrightness = mPowerState.getScreenBrightness();
final float currentSdrBrightness = mPowerState.getSdrScreenBrightness();
//animateValue 必须是有效值,animateValue必须和上次不一样
if (isValidBrightnessValue(animateValue)
&& (animateValue != currentBrightness
|| sdrAnimateValue != currentSdrBrightness)) {
if (initialRampSkip || hasBrightnessBuckets
|| wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
//设置屏幕亮度
animateScreenBrightness(animateValue, sdrAnimateValue,
SCREEN_ANIMATION_RATE_MINIMUM);
} else {
boolean isIncreasing = animateValue > currentBrightness;
final float rampSpeed;
if (isIncreasing && slowChange) {
rampSpeed = mBrightnessRampRateSlowIncrease;
} else if (isIncreasing && !slowChange) {
rampSpeed = mBrightnessRampRateFastIncrease;
} else if (!isIncreasing && slowChange) {
rampSpeed = mBrightnessRampRateSlowDecrease;
} else {
rampSpeed = mBrightnessRampRateFastDecrease;
}
//设置屏幕亮度
animateScreenBrightness(animateValue, sdrAnimateValue, rampSpeed);
}
}
if (!brightnessIsTemporary) {
if (userInitiatedChange && (mAutomaticBrightnessController == null
|| !mAutomaticBrightnessController.hasValidAmbientLux())) {
// If we don't have a valid lux reading we can't report a valid
// slider event so notify as if the system changed the brightness.
userInitiatedChange = false;
}
notifyBrightnessChanged(brightnessState, userInitiatedChange,
hadUserBrightnessPoint);
}
}
// Log any changes to what is currently driving the brightness setting.
if (!mBrightnessReasonTemp.equals(mBrightnessReason) || brightnessAdjustmentFlags != 0) {
Slog.v(TAG, "Brightness [" + brightnessState + "] reason changing to: '"
+ mBrightnessReasonTemp.toString(brightnessAdjustmentFlags)
+ "', previous reason: '" + mBrightnessReason + "'.");
if(mBrightnessReasonTemp.reason == BrightnessReason.REASON_SCREEN_OFF && mScreenOffBecauseOfProximity){
StatusBarManager statusBarManager = (StatusBarManager) mContext
.getSystemService(android.app.Service.STATUS_BAR_SERVICE);
if(statusBarManager != null){
statusBarManager.collapsePanels();
}
}
mBrightnessReason.set(mBrightnessReasonTemp);
} else if (mBrightnessReasonTemp.reason == BrightnessReason.REASON_MANUAL
&& userSetBrightnessChanged) {
Slog.v(TAG, "Brightness [" + brightnessState + "] manual adjustment.");
}
// Update display white-balance.
if (mDisplayWhiteBalanceController != null) {
if (state == Display.STATE_ON && mDisplayWhiteBalanceSettings.isEnabled()) {
mDisplayWhiteBalanceController.setEnabled(true);
mDisplayWhiteBalanceController.updateDisplayColorTemperature();
} else {
mDisplayWhiteBalanceController.setEnabled(false);
}
}
// Determine whether the display is ready for use in the newly requested state.
// Note that we do not wait for the brightness ramp animation to complete before
// reporting the display is ready because we only need to ensure the screen is in the
// right power state even as it continues to converge on the desired brightness.
final boolean ready = mPendingScreenOnUnblocker == null &&
(!mColorFadeEnabled ||
(!mColorFadeOnAnimator.isStarted() && !mColorFadeOffAnimator.isStarted()))
&& mPowerState.waitUntilClean(mCleanListener);
final boolean finished = ready
&& !mScreenBrightnessRampAnimator.isAnimating();
// Notify policy about screen turned on.
if (ready && state != Display.STATE_OFF
&& mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_ON) {
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_ON);
mWindowManagerPolicy.screenTurnedOn(mDisplayId);
}
// Grab a wake lock if we have unfinished business.
if (!finished && !mUnfinishedBusiness) {
if (DEBUG) {
Slog.d(TAG, "Unfinished business...");
}
mCallbacks.acquireSuspendBlocker();
mUnfinishedBusiness = true;
}
// Notify the power manager when ready.
if (ready && mustNotify) {
// Send state change.
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true;
if (DEBUG) {
Slog.d(TAG, "Display ready!");
}
}
}
sendOnStateChangedWithWakelock();
}
// Release the wake lock when we have no unfinished business.
if (finished && mUnfinishedBusiness) {
if (DEBUG) {
Slog.d(TAG, "Finished business...");
}
mUnfinishedBusiness = false;
mCallbacks.releaseSuspendBlocker();
}
// Record if dozing for future comparison.
mDozing = state != Display.STATE_ON;
if (previousPolicy != mPowerRequest.policy) {
logDisplayPolicyChanged(mPowerRequest.policy);
}
}(3) android/frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
private void animateScreenBrightness(float target, float sdrTarget, float rate) {
if (DEBUG) {
Slog.d(TAG, "Animating brightness: target=" + target + ", sdrTarget=" + sdrTarget
+ ", rate=" + rate);
}
mScreenBrightnessRampAnimator.setDisplayId(mDisplayId);
if (mScreenBrightnessRampAnimator.animateTo(target, sdrTarget, rate)) {
Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", (int) target);
// TODO(b/153319140) remove when we can get this from the above trace invocation
SystemProperties.set("debug.tracing.screen_brightness", String.valueOf(target));
noteScreenBrightness(target);
}
}
(4) mScreenBrightnessRampAnimator 的定义和对应的参数
frameworks/base/services/core/java/com/android/server/display/DisplayPowerController.java
mScreenBrightnessRampAnimator = mInjector.getDualRampAnimator(mPowerState,
//first Property
DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT,
//second Property
DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT);
//DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT定义:
public static final FloatProperty<DisplayPowerState> SCREEN_BRIGHTNESS_FLOAT =
new FloatProperty<DisplayPowerState>("screenBrightnessFloat") {
@Override
public void setValue(DisplayPowerState object, float value) {
object.setScreenBrightness(value);
}
@Override
public Float get(DisplayPowerState object) {
return object.getScreenBrightness();
}
};
(4) DisplayPowerState.setScreenBrightness 函数调用
/**
* Sets the display brightness.
*
* @param brightness The brightness, ranges from 0.0f (minimum) to 1.0f (brightest), or is -1f
* (off).
*/
public void setScreenBrightness(float brightness) {
if (mScreenBrightness != brightness) {
if (DEBUG) {
Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
}
mScreenBrightness = brightness;
if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
/ /更新背光值。
scheduleScreenUpdate();
}
}
}
private void scheduleScreenUpdate() {
if (!mScreenUpdatePending) {
mScreenUpdatePending = true;
postScreenUpdateThreadSafe();
}
}
private void postScreenUpdateThreadSafe() {
mHandler.removeCallbacks(mScreenUpdateRunnable);
//通过handle的方式
mHandler.post(mScreenUpdateRunnable);
}
private final Runnable mScreenUpdateRunnable = new Runnable() {
@Override
public void run() {
mScreenUpdatePending = false;
float brightnessState = mScreenState != Display.STATE_OFF
&& mColorFadeLevel > 0f ? mScreenBrightness : PowerManager.BRIGHTNESS_OFF_FLOAT;
float sdrBrightnessState = mScreenState != Display.STATE_OFF
&& mColorFadeLevel > 0f
? mSdrScreenBrightness : PowerManager.BRIGHTNESS_OFF_FLOAT;
//设置状态
if (mPhotonicModulator.setState(mScreenState, brightnessState, sdrBrightnessState)) {
if (DEBUG) {
Slog.d(TAG, "Screen ready");
}
mScreenReady = true;
invokeCleanListenerIfNeeded();
} else {
if (DEBUG) {
Slog.d(TAG, "Screen not ready");
}
}
}
};
(5)frameworks/base/services/core/java/com/android/server/display/DisplayPowerState.java::PhotonicModulator
public boolean setState(int state, float brightnessState, float sdrBrightnessState) {
synchronized (mLock) {
boolean stateChanged = state != mPendingState;
boolean backlightChanged = brightnessState != mPendingBacklight
|| sdrBrightnessState != mPendingSdrBacklight;
if (stateChanged || backlightChanged) {
if (DEBUG) {
Slog.d(TAG, "Requesting new screen state: state="
+ Display.stateToString(state) + ", backlight=" + brightnessState);
}
mPendingState = state;
mPendingBacklight = brightnessState;
mPendingSdrBacklight = sdrBrightnessState;
boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
mStateChangeInProgress = stateChanged || mStateChangeInProgress;
mBacklightChangeInProgress = backlightChanged || mBacklightChangeInProgress;
if (!changeInProgress) {
//唤醒锁==>直接找到mLock.wait()
mLock.notifyAll();
}
}
return !mStateChangeInProgress;
}
}
直接唤醒mLock.wait(),调用mBlanker.requestDisplayState()
@Override
public void run() {
for (;;) {
// Get pending change.
final int state;
final boolean stateChanged;
final float brightnessState;
final float sdrBrightnessState;
final boolean backlightChanged;
synchronized (mLock) {
state = mPendingState;
stateChanged = (state != mActualState);
brightnessState = mPendingBacklight;
sdrBrightnessState = mPendingSdrBacklight;
backlightChanged = brightnessState != mActualBacklight
|| sdrBrightnessState != mActualSdrBacklight;
if (!stateChanged) {
// State changed applied, notify outer class.
postScreenUpdateThreadSafe();
mStateChangeInProgress = false;
}
if (!backlightChanged) {
mBacklightChangeInProgress = false;
}
boolean valid = state != Display.STATE_UNKNOWN && !Float.isNaN(brightnessState);
boolean changed = stateChanged || backlightChanged;
//若是无效状态或者状态没有改变,则处于等待状态
if (!valid || !changed) {
try {
mLock.wait();
} catch (InterruptedException ex) {
if (mStopped) {
return;
}
}
continue;
}
mActualState = state;
mActualBacklight = brightnessState;
mActualSdrBacklight = sdrBrightnessState;
}
// Apply pending change.
if (DEBUG) {
Slog.d(TAG, "Updating screen state: id=" + mDisplayId + ", state="
+ Display.stateToString(state) + ", backlight=" + brightnessState
+ ", sdrBacklight=" + sdrBrightnessState);
}
mBlanker.requestDisplayState(mDisplayId, state, brightnessState,
sdrBrightnessState);
}
}
}
(6)frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
/** {@link DisplayBlanker} used by all {@link DisplayPowerController}s. */
private final DisplayBlanker mDisplayBlanker = new DisplayBlanker() {
// Synchronized to avoid race conditions when updating multiple display states.
@Override
public synchronized void requestDisplayState(int displayId, int state, float brightness,
float sdrBrightness) {
boolean allInactive = true;
boolean allOff = true;
final boolean stateChanged;
synchronized (mSyncRoot) {
final int index = mDisplayStates.indexOfKey(displayId);
if (index > -1) {
final int currentState = mDisplayStates.valueAt(index);
stateChanged = state != currentState;
if (stateChanged) {
final int size = mDisplayStates.size();
for (int i = 0; i < size; i++) {
final int displayState = i == index ? state : mDisplayStates.valueAt(i);
if (displayState != Display.STATE_OFF) {
allOff = false;
}
if (Display.isActiveState(displayState)) {
allInactive = false;
}
if (!allOff && !allInactive) {
break;
}
}
}
} else {
stateChanged = false;
}
}
// The order of operations is important for legacy reasons.
//当状态是Display.STATE_OFF时
if (state == Display.STATE_OFF) {
requestDisplayStateInternal(displayId, state, brightness, sdrBrightness);
}
if (stateChanged) {
mDisplayPowerCallbacks.onDisplayStateChange(allInactive, allOff);
}
//当状态不是Display.STATE_OFF时
if (state != Display.STATE_OFF) {
requestDisplayStateInternal(displayId, state, brightness, sdrBrightness);
}
}
};
private void requestDisplayStateInternal(int displayId, int state, float brightnessState,
float sdrBrightnessState) {
if (state == Display.STATE_UNKNOWN) {
state = Display.STATE_ON;
}
brightnessState = clampBrightness(state, brightnessState);
sdrBrightnessState = clampBrightness(state, sdrBrightnessState);
// Update the display state within the lock.
// Note that we do not need to schedule traversals here although it
// may happen as a side-effect of displays changing state.
final Runnable runnable;
final String traceMessage;
synchronized (mSyncRoot) {
final int index = mDisplayStates.indexOfKey(displayId);
final BrightnessPair brightnessPair =
index < 0 ? null : mDisplayBrightnesses.valueAt(index);
if (index < 0 || (mDisplayStates.valueAt(index) == state
&& brightnessPair.brightness == brightnessState
&& brightnessPair.sdrBrightness == sdrBrightnessState)) {
return; // Display no longer exists or no change.
}
if (Trace.isTagEnabled(Trace.TRACE_TAG_POWER)) {
traceMessage = Display.stateToString(state)
+ ", brightness=" + brightnessState
+ ", sdrBrightness=" + sdrBrightnessState;
Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_POWER,
"requestDisplayStateInternal:" + displayId,
traceMessage, displayId);
}
mDisplayStates.setValueAt(index, state);
brightnessPair.brightness = brightnessState;
brightnessPair.sdrBrightness = sdrBrightnessState;
runnable =
//更新显示状态
updateDisplayStateLocked(mLogicalDisplayMapper.getDisplayLocked(displayId)
.getPrimaryDisplayDeviceLocked());
if (Trace.isTagEnabled(Trace.TRACE_TAG_POWER)) {
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_POWER,
"requestDisplayStateInternal:" + displayId, displayId);
}
}
// Setting the display power state can take hundreds of milliseconds
// to complete so we defer the most expensive part of the work until
// after we have exited the critical section to avoid blocking other
// threads for a long time.
if (runnable != null) {
runnable.run();
}
}
private Runnable updateDisplayStateLocked(DisplayDevice device) {
// Blank or unblank the display immediately to match the state requested
// by the display power controller (if known).
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display == null) {
return null;
}
final int displayId = display.getDisplayIdLocked();
final int state = mDisplayStates.get(displayId);
// Only send a request for display state if display state has already been initialized.
if (state != Display.STATE_UNKNOWN) {
final BrightnessPair brightnessPair = mDisplayBrightnesses.get(displayId);
return device.requestDisplayStateLocked(state, brightnessPair.brightness,
brightnessPair.sdrBrightness);
}
}
return null;
}
(7) frameworks/base/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@Override
public Runnable requestDisplayStateLocked(final int state, final float brightnessState,
final float sdrBrightnessState) {
return new Runnable() {
@Override
public void run() {
// Apply brightness changes given that we are in a non-suspended state.
if (brightnessChanged || vrModeChange) {
setDisplayBrightness(brightnessState, sdrBrightnessState);
mBrightnessState = brightnessState;
mSdrBrightnessState = sdrBrightnessState;
}
}
private void setVrMode(boolean isVrEnabled) {
if (DEBUG) {
Slog.d(TAG, "setVrMode("
+ "id=" + physicalDisplayId
+ ", state=" + Display.stateToString(state) + ")");
}
mBacklightAdapter.setVrMode(isVrEnabled);
}
private void setDisplayState(int state) {
if (DEBUG || MTK_DEBUG) {
Slog.d(TAG, "setDisplayState("
+ "id=" + physicalDisplayId
+ ", state=" + Display.stateToString(state) + ")");
}
// We must tell sidekick to stop controlling the display before we
// can change its power mode, so do that first.
if (mSidekickActive) {
Trace.traceBegin(Trace.TRACE_TAG_POWER,
"SidekickInternal#endDisplayControl");
try {
mSidekickInternal.endDisplayControl();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
mSidekickActive = false;
}
final int mode = getPowerModeForState(state);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState("
+ "id=" + physicalDisplayId
+ ", state=" + Display.stateToString(state) + ")");
try {
mSurfaceControlProxy.setDisplayPowerMode(token, mode);
Trace.traceCounter(Trace.TRACE_TAG_POWER, "DisplayPowerMode", mode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
// If we're entering a suspended (but not OFF) power state and we
// have a sidekick available, tell it now that it can take control.
if (Display.isSuspendedState(state) && state != Display.STATE_OFF
&& mSidekickInternal != null && !mSidekickActive) {
Trace.traceBegin(Trace.TRACE_TAG_POWER,
"SidekickInternal#startDisplayControl");
try {
mSidekickActive = mSidekickInternal.startDisplayControl(state);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
}
private void setDisplayBrightness(float brightnessState,
float sdrBrightnessState) {
if (DEBUG || MTK_DEBUG) {
Slog.d(TAG, "setDisplayBrightness("
+ "id=" + physicalDisplayId
+ ", brightnessState=" + brightnessState
+ ", sdrBrightnessState=" + sdrBrightnessState + ")");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
+ "id=" + physicalDisplayId + ", brightnessState="
+ brightnessState + ", sdrBrightnessState=" + sdrBrightnessState
+ ")");
try {
final float backlight = brightnessToBacklight(brightnessState);
final float sdrBacklight = brightnessToBacklight(sdrBrightnessState);
final float nits = backlightToNits(backlight);
final float sdrNits = backlightToNits(sdrBacklight);
mBacklightAdapter.setBacklight(sdrBacklight, sdrNits, backlight, nits);
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"ScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(brightnessState));
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"SdrScreenBrightness",
BrightnessSynchronizer.brightnessFloatToInt(
sdrBrightnessState));
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
// Set backlight within min and max backlight values
void setBacklight(float sdrBacklight, float sdrNits, float backlight, float nits) {
if (mUseSurfaceControlBrightness || mForceSurfaceControl) {
if (BrightnessSynchronizer.floatEquals(
sdrBacklight, PowerManager.BRIGHTNESS_INVALID_FLOAT)) {
mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, backlight);
} else {
mSurfaceControlProxy.setDisplayBrightness(mDisplayToken, sdrBacklight, sdrNits,
backlight, nits);
}
} else if (mBacklight != null) {
//设置背光
mBacklight.setBrightness(backlight);
}
}
(7)frameworks/base/services/core/java/com/android/server/lights/LightsService.java
private final class LightImpl extends LogicalLight {
private LightImpl(Context context, HwLight hwLight) {
mHwLight = hwLight;
}
@Override
public void setBrightness(float brightness) {
setBrightness(brightness, BRIGHTNESS_MODE_USER);
}
@Override
public void setBrightness(float brightness, int brightnessMode) {
if (Float.isNaN(brightness)) {
Slog.w(TAG, "Brightness is not valid: " + brightness);
return;
}
synchronized (this) {
// LOW_PERSISTENCE cannot be manually set
if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mHwLight.id
+ ": brightness=" + brightness);
return;
}
int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt(brightness);
int color = brightnessInt & 0x000000ff;
color = 0xff000000 | (color << 16) | (color << 8) | color;
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
}
}
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
if (shouldBeInLowPersistenceMode()) {
brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE;
} else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
brightnessMode = mLastBrightnessMode;
}
if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
offMS != mOffMS || mBrightnessMode != brightnessMode) {
if (DEBUG) {
Slog.v(TAG, "setLight #" + mHwLight.id + ": color=#"
+ Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
}
mInitialized = true;
mLastColor = mColor;
mColor = color;
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
mBrightnessMode = brightnessMode;
setLightUnchecked(color, mode, onMS, offMS, brightnessMode);
}
}
private void setLightUnchecked(int color, int mode, int onMS, int offMS,
int brightnessMode) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
+ Integer.toHexString(color) + ")");
try {
if (mVintfLights != null) {
HwLightState lightState = new HwLightState();
lightState.color = color;
lightState.flashMode = (byte) mode;
lightState.flashOnMs = onMS;
lightState.flashOffMs = offMS;
lightState.brightnessMode = (byte) brightnessMode;
mVintfLights.get().setLightState(mHwLight.id, lightState);
} else {
// 这是一个native方法
setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
}
} catch (RemoteException | UnsupportedOperationException ex) {
Slog.e(TAG, "Failed issuing setLightState", ex);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
(8) frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
static const JNINativeMethod method_table[] = {
{ "setLight_native", "(IIIIII)V", (void*)setLight_native },
};
static void setLight_native(
JNIEnv* /* env */,
jobject /* clazz */,
jint light,
jint colorARGB,
jint flashMode,
jint onMS,
jint offMS,
jint brightnessMode) {
if (!sLightSupported) {
return;
}
if (!validate(light, flashMode, brightnessMode)) {
return;
}
Type type = static_cast<Type>(light);
LightState state = constructState(
colorARGB, flashMode, onMS, offMS, brightnessMode);
{
android::base::Timer t;
sp<ILight> hal = ILight::getService();
if (hal == nullptr) {
sLightSupported = false;
return;
}
Return<Status> ret = hal->setLight(type, state);
processReturn(ret, type, state);
if (t.duration() > 50ms) ALOGD("Excessive delay setting light");
}
}
(9)androids/vendor/mediatek/proprietary/hardware/liblights/aidl/default/Lights.cpp
/* LCD BACKLIGHT */
char const*const LCD_FILE
= "/sys/class/leds/lcd-backlight/brightness";
static int
set_light_backlight(struct light_device_t* dev,
struct light_state_t const* state)
{
int err = 0;
int brightness = rgb_to_brightness(state);
pthread_mutex_lock(&g_lock);
g_backlight = brightness;
err = write_int(LCD_FILE, brightness);
if (g_haveTrackballLight) {
handle_trackball_light_locked(dev);
}
pthread_mutex_unlock(&g_lock);
return err;
}
五. 从按下power键到亮屏的流程小结:
-->com_android_server_input_InputManagerService.cpp:: interceptKeyBeforeQueueing()
-->InputManagerService.java::interceptKeyBeforeQueueing()
-->InputManagerCallback.java::interceptKeyBeforeQueueing()
-->PhoneWindowManager.java::interceptKeyBeforeQueueing()
---> PhoneWindowManager.java::interceptPowerKeyDown()
---> PhoneWindowManager.java::wakeUpFromPowerKey()
---> PhoneWindowManager.java::wakeUp()
---> PowerManager.java::wakeUp()
---> PowerManagerService.java::wakeUp()
---> PowerManagerService.java::wakeDisplayGroup()---> PowerManagerService.java::wakeDisplayGroupNoUpdateLocked()
---> PowerManagerService.java::updatePowerStateLocked()---> PowerManagerService.java::updateDisplayPowerStateLocked()
---> DisplayPowerController.java::requestPowerState()
---> DisplayPowerController.java::sendUpdatePowerStateLocked()
---> DisplayPowerController.java::updatePowerState()
---> DisplayPowerController.java::animateScreenBrightness()
---> RampAnimator.java::DualRampAnimator::animateTo()
---> DisplayPowerState.java::SCREEN_BRIGHTNESS_FLOAT::setValue()
---> DisplayPowerState.java::setScreenBrightness()
---> DisplayPowerState.java::scheduleScreenUpdate()
---> DisplayPowerState.java::postScreenUpdateThreadSafe()
---> DisplayPowerState.java::mScreenUpdateRunnable::run()
---> DisplayPowerState.java::PhotonicModulator::setState() ==调用mLock.notifyAll()唤醒锁
---> DisplayPowerState.java::PhotonicModulator::run()
---> DisplayManagerService.java::mDisplayBlanker::requestDisplayState()
---> DisplayManagerService.java::requestDisplayStateInternal()
---> DisplayManagerService.java::updateDisplayStateLocked()
---> LocalDisplayAdapter.java::requestDisplayStateLocked()
---> LocalDisplayAdapter.java::setDisplayBrightness()
---> LocalDisplayAdapter.java::sBacklightAdapter::setBacklight()
--->LightsService.java::setBrightness()
--->LightsService.java::setLightLocked()
--->LightsService.java::setLightUnchecked()
-->LightsService.java::setLight_native() == 调用native方法
-->com_android_server_lights_LightsService.cpp::setLight_native()
Return<Status> ret = hal->setLight(type, state);
....(对HAL层不熟悉,跳过)
--->lights.cpp::set_light_backlight()
六.log 验证:
抓取日志的命令:
按照上面的分析,专门加日志。
sudo adb logcat -b all | grep -E "lights|LightsService|LocalDisplayAdapter|DisplayPowerState|RampAnimator|DisplayPowerController|DisplayPowerController2|DisplayManagerService|PowerGroup|PowerManagerService|PowerManager|PhoneWindowManager|InputManagerCallback|InputManagerService|InputManager-JNI|light"
下面是AndroidU项目打印的日志:可以看看和Android T 大部分逻辑是一样的。
12-09 15:03:25.674 1210 2448 E InputManager-JNI: com_android_server_input_InputManagerService.cpp::interceptKeyBeforeQueueing
12-09 15:03:25.674 1210 2448 E InputManagerService: interceptKeyBeforeQueueing
12-09 15:03:25.674 1210 2448 E InputManagerCallback: interceptKeyBeforeQueueing
12-09 15:03:25.674 1210 2448 E PhoneWindowManager: interceptKeyBeforeQueueing
12-09 15:03:25.676 1210 2448 E PowerManagerService: updatePowerStateLocked
12-09 15:03:25.676 1210 2448 E PowerManagerService: updatePowerGroupsLocked
12-09 15:03:25.676 1210 2448 E PowerGroup: updateLocked
12-09 15:03:25.676 1210 2448 E DisplayManagerService: requestPowerState
12-09 15:03:25.676 1210 2448 E DisplayPowerController2: requestPowerState
12-09 15:03:25.677 1210 2447 E PowerManagerService: updatePowerStateLocked
12-09 15:03:25.677 1210 2447 E PowerManagerService: updatePowerGroupsLocked
12-09 15:03:25.677 1210 2447 E PowerGroup: updateLocked
12-09 15:03:25.677 1210 2447 E DisplayManagerService: requestPowerState
12-09 15:03:25.677 1210 2447 E DisplayPowerController2: requestPowerState
12-09 15:03:25.686 1210 2949 E PowerManagerService: updatePowerStateLocked
12-09 15:03:25.686 1210 2949 E PowerManagerService: updatePowerGroupsLocked
12-09 15:03:25.686 1210 2949 E PowerGroup: updateLocked
12-09 15:03:25.686 1210 2949 E DisplayManagerService: requestPowerState
12-09 15:03:25.686 1210 2949 E DisplayPowerController2: requestPowerState
12-09 15:03:25.699 1210 4329 E PowerManagerService: updatePowerStateLocked
12-09 15:03:25.699 1210 4329 E PowerManagerService: updatePowerGroupsLocked
12-09 15:03:25.699 1210 4329 E PowerGroup: updateLocked
12-09 15:03:25.699 1210 4329 E DisplayManagerService: requestPowerState
12-09 15:03:25.699 1210 4329 E DisplayPowerController2: requestPowerState
12-09 15:03:25.711 1210 5026 E PowerManagerService: updatePowerStateLocked
12-09 15:03:25.712 1210 5026 E PowerManagerService: updatePowerGroupsLocked
12-09 15:03:25.712 1210 5026 E PowerGroup: updateLocked
12-09 15:03:25.712 1210 5026 E DisplayManagerService: requestPowerState
12-09 15:03:25.712 1210 5026 E DisplayPowerController2: requestPowerState
12-09 15:03:25.722 1210 5026 E PowerManagerService: updatePowerStateLocked
12-09 15:03:25.722 1210 5026 E PowerManagerService: updatePowerGroupsLocked
12-09 15:03:25.722 1210 5026 E PowerGroup: updateLocked
12-09 15:03:25.722 1210 5026 E DisplayManagerService: requestPowerState
12-09 15:03:25.722 1210 5026 E DisplayPowerController2: requestPowerState
12-09 15:03:25.733 1210 4329 E PowerManagerService: updatePowerStateLocked
12-09 15:03:25.733 1210 4329 E PowerManagerService: updatePowerGroupsLocked
12-09 15:03:25.734 1210 2770 E DisplayPowerState: postScreenUpdateThreadSafe
12-09 15:03:25.735 1210 1344 E DisplayPowerState: mScreenUpdateRunnable::run
12-09 15:03:25.735 1210 1344 E DisplayPowerState: PhotonicModulator::setState
12-09 15:03:25.736 1210 4329 E PowerGroup: updateLocked
12-09 15:03:25.736 1210 4329 E DisplayManagerService: requestPowerState
12-09 15:03:25.737 1210 4329 E DisplayPowerController2: requestPowerState
12-09 15:03:25.805 1210 1344 I DisplayPowerController2[0]: Unblocked screen on after 311 ms
12-09 15:03:25.806 1210 1344 E DisplayPowerController2: updatePowerState
12-09 15:03:25.806 1210 1344 E DisplayPowerController2: updatePowerStateInternal
12-09 15:03:25.810 1210 1344 E DisplayPowerState: scheduleScreenUpdate
12-09 15:03:25.810 1210 1344 E DisplayPowerState: postScreenUpdateThreadSafe
12-09 15:03:25.818 1210 1344 E DisplayPowerState: mScreenUpdateRunnable::run
12-09 15:03:25.818 1210 1344 E DisplayPowerState: PhotonicModulator::setState
12-09 15:03:25.818 1210 1344 E DisplayPowerState: PhotonicModulator::setState::mLock.notifyAll
12-09 15:03:25.818 1210 1344 E DisplayPowerController2: sendUpdatePowerState
12-09 15:03:25.818 1210 1344 E DisplayPowerController2: sendUpdatePowerStateLocked
12-09 15:03:25.818 1210 2770 E DisplayPowerState: postScreenUpdateThreadSafe
12-09 15:03:25.818 1210 2770 E DisplayManagerService: requestDisplayState
12-09 15:03:25.819 1210 2770 E DisplayManagerService: requestDisplayStateInternal
12-09 15:03:25.819 1210 2770 E DisplayManagerService: updateDisplayStateLocked
12-09 15:03:25.819 1210 2770 E LocalDisplayAdapter: requestDisplayStateLocked
12-09 15:03:25.819 1210 2770 E LocalDisplayAdapter: setDisplayBrightness
12-09 15:03:25.819 1210 2770 E LocalDisplayAdapter: BacklightAdapter::setBacklight
12-09 15:03:25.819 1210 2770 E LightsService: setBrightness(float brightness)
12-09 15:03:25.819 1210 2770 E LightsService: setBrightness(float brightness, int brightnessMode)
12-09 15:03:25.819 1210 1344 E DisplayPowerController2: updatePowerState
12-09 15:03:25.819 1210 1344 E DisplayPowerController2: updatePowerStateInternal
12-09 15:03:25.819 1210 2770 E LightsService: setLightLocked
12-09 15:03:25.819 1210 2770 E LightsService: setLightUnchecked
12-09 15:03:25.820 688 688 D android.hardware.lights-service.mediatek: Lights setting state for id=0, color=ffffffff
12-09 15:03:25.820 688 688 D android.hardware.lights-service.mediatek: set_light_backlight, level=255, onMS=0, offMS=0
12-09 15:03:25.820 688 688 D android.hardware.lights-service.mediatek: write 255 to /sys/class/leds/lcd-backlight/brightness
12-09 15:03:25.820 688 688 D android.hardware.lights-service.mediatek: write 255 to /sys/class/leds/lcd-backlight/brightness, result: 0
12-09 15:03:25.821 1210 2770 E DisplayPowerState: postScreenUpdateThreadSafe
12-09 15:03:25.823 1071 1071 I (3)[1071:AALMain]mtk_leds backlight_debug_log(119): [BL] Set Backlight directly T:1413.809,L:255 map:255
12-09 15:03:25.834 1071 1071 I (3)[1071:AALMain][PWM] disp_pwm_set_backlight_cmdq: (id = 0x1, level_1024 = 787), old = 0
12-09 15:03:25.834 1071 1071 I (3)[1071:AALMain][PWM] disp_pwm_backlight_status: backlight is on (1), power:(1), pwm id: (0)
12-09 15:03:25.829 1000 1071 D AAL : onBacklightChanged: 0/1023 -> 1023/1023(phy:4095/4095)
12-09 15:03:25.830 1000 1071 D AAL : onBacklightChanged: change screen state 0(Off) -> 3(On)