目录
一. 源码分析:
二. 简单整理流程:
三. 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 = LocalServices.getService( StatusBarManagerInternal.class)的对象获取:
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; }
7. 处理 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 isSetupComplete &= isAutoUserSetupComplete(); } return isSetupComplete; }
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; }
(5)mPowerManager.wakeUp对应的函数:
android/frameworks/base/core/java/android/os/PowerManager.java
/** * Forces the {@link android.view.Display#DEFAULT_DISPLAY default display} to turn on. * *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. * *
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. * *
* This is what happens when the power key is pressed to turn on the screen. *
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. *
* * @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();
(13) 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键,则停止响铃或结束通话。
[2] 当正在通话时,此时按下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 管理设备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;
(2) 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 FloatPropertySCREEN_BRIGHTNESS_FLOAT = new FloatProperty ("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(light); LightState state = constructState( colorARGB, flashMode, onMS, offMS, brightnessMode); { android::base::Timer t; sp hal = ILight::getService(); if (hal == nullptr) { sLightSupported = false; return; } Return 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;
}
-->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
ret = hal->setLight(type, state); ....(对HAL层不熟悉,跳过)
--->lights.cpp::set_light_backlight() ===>写入节点亮屏
抓取日志的命令:
按照上面的分析,专门加日志。
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)