在开发指纹功能的时候,发现在息屏模式打开时,锁屏后指纹可以直接解锁,但是过了4秒钟后却不行了。发现在4秒钟之前,屏幕的tp还是有反馈的,并没有完全关闭。所以为了搞清楚为什么会有这种现象,研究了一下其中的流程。
先说一下修改点。DozeScreenState.java 的 private static final int ENTER_DOZE_DELAY = 4000; 修改一下这个时间就可以了。
这里涉及了集合关键类:
frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
frameworks/base/core/java/android/app/DreamManager.java
frameworks/base/services/core/java/com/android/server/dreams/DreamManagerService.java
frameworks/base/services/core/java/com/android/server/dreams/DreamController.java
frameworks/base/core/java/android/service/dreams/DreamService.java
frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
frameworks/base/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
frameworks/base/core/java/android/hardware/display/AmbientDisplayConfiguration.java
packages/apps/Settings/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceController.java
AmbientDisplayAlwaysOnPreferenceController.java 开启息屏模式会设置Settings.Secure.DOZE_ALWAYS_ON 这个系统属性。
@Override
public boolean isChecked() {
return getConfig().alwaysOnEnabled(MY_USER);
}
@Override
public boolean setChecked(boolean isChecked) {
int enabled = isChecked ? ON : OFF;
Settings.Secure.putInt(
mContext.getContentResolver(), Settings.Secure.DOZE_ALWAYS_ON, enabled);
return true;
}
然后我们跟着实际使用时的流程跟下去。
在按下power键后,会走息屏流程,这个网上很多可以自己去搜一下。
关键方式是这个
PhoneWindowManager.java
private void attemptToDreamFromShortPowerButtonPress(
boolean isScreenOn, Runnable noDreamAction) {
if (mShortPressOnPowerBehavior != SHORT_PRESS_POWER_DREAM_OR_SLEEP) {
noDreamAction.run();
return;
}
final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal();
if (dreamManagerInternal == null || !dreamManagerInternal.canStartDreaming(isScreenOn)) {
Slog.d(TAG, "Can't start dreaming when attempting to dream from short power"
+ " press (isScreenOn=" + isScreenOn + ")");
noDreamAction.run();
return;
}
synchronized (mLock) {
// If the setting to lock instantly on power button press is true, then set the flag to
// lock after the dream transition has finished.
mLockAfterAppTransitionFinished =
mLockPatternUtils.getPowerButtonInstantlyLocks(mCurrentUserId);
}
dreamManagerInternal.requestDream();
}
dreamManagerInternal.requestDream(); 这个开始走Dream流程。
PhoneWindowManager
private void sleepDefaultDisplay(long eventTime, int reason, int flags) {
mRequestedOrSleepingDefaultDisplay = true;
mPowerManager.goToSleep(eventTime, reason, flags);
}
这里会调用到powermanager 去
@Override // Binder call
@RequiresPermission(android.Manifest.permission.DEVICE_POWER)
public void goToSleep(long eventTime, int reason, int flags) {
goToSleepInternal(DEFAULT_DISPLAY_GROUP_IDS, eventTime, reason, flags);
}
@RequiresPermission(android.Manifest.permission.DEVICE_POWER)
private void goToSleepInternal(IntArray groupIds, long eventTime, int reason, int flags) {
final long now = mClock.uptimeMillis();
if (eventTime > now) {
Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
throw new IllegalArgumentException("event time must not be in the future");
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
/* message= */ null);
boolean isNoDoze = (flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0;
int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
for (int i = 0; i < groupIds.size(); i++) {
int groupId = groupIds.get(i);
PowerGroup powerGroup = mPowerGroups.get(groupId);
if (powerGroup == null) {
throw new IllegalArgumentException("power group(" + groupId
+ ") doesn't exist");
}
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP) != 0) {
if (powerGroup.hasWakeLockKeepingScreenOnLocked()) {
continue;
}
}
if (isNoDoze) {
sleepPowerGroupLocked(powerGroup, eventTime, reason, uid);
} else {
dozePowerGroupLocked(powerGroup, eventTime, reason, uid);
}
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
这里有个isNoDoze 的判断来确认进入息屏模式的流程。
后面方法太多了这里只写方法名算了。
dozePowerGroupLocked(powerGroup, eventTime, reason, uid); ----> PowerGroup.dozeLocked(eventTime, uid, reason); ---->
PowerGroup.setWakefulnessLocked(); ----> PowerManagerService.PowerGroupWakefulnessChangeListener.onWakefulnessChangedLocked () -----> PowerManagerService.updateGlobalWakefulnessLocked() ----->Notifier.onGlobalWakefulnessChangeStarted() ------> ActivityManagerService.onWakefulnessChanged()
这些方法里面主要是更新一些状态信息
真正执行的方法是PowerManagerService.PowerGroupWakefulnessChangeListener.onWakefulnessChangedLocked ()
中的 updatePowerStateLocked()
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0 || mUpdatePowerStateInProgress) {
return;
}
if (!Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
mUpdatePowerStateInProgress = true;
try {
// Phase 0: Basic state updates.
updateIsPoweredLocked(mDirty);
updateStayOnLocked(mDirty);
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = mClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
updateAttentiveStateLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Lock profiles that became inactive/not kept awake.
updateProfilesLocked(now);
// Phase 3: Update power state of all PowerGroups.
final boolean powerGroupsBecameReady = updatePowerGroupsLocked(dirtyPhase2);
// Phase 4: Update dream state (depends on power group ready signal).
updateDreamLocked(dirtyPhase2, powerGroupsBecameReady);
// Phase 5: Send notifications, if needed.
finishWakefulnessChangeIfNeededLocked();
// Phase 6: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
mUpdatePowerStateInProgress = false;
}
}
updateDreamLocked(dirtyPhase2, powerGroupsBecameReady)
private void updateDreamLocked(int dirty, boolean powerGroupBecameReady) {
if ((dirty & (DIRTY_WAKEFULNESS
| DIRTY_USER_ACTIVITY
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED
| DIRTY_ATTENTIVE
| DIRTY_WAKE_LOCKS
| DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS
| DIRTY_IS_POWERED
| DIRTY_STAY_ON
| DIRTY_PROXIMITY_POSITIVE
| DIRTY_BATTERY_STATE)) != 0 || powerGroupBecameReady) {
if (areAllPowerGroupsReadyLocked()) {
scheduleSandmanLocked();
}
}
}
scheduleSandmanLocked();
private void scheduleSandmanLocked() {
if (!mSandmanScheduled) {
mSandmanScheduled = true;
for (int idx = 0; idx < mPowerGroups.size(); idx++) {
final PowerGroup powerGroup = mPowerGroups.valueAt(idx);
if (powerGroup.supportsSandmanLocked()) {
Message msg = mHandler.obtainMessage(MSG_SANDMAN);
msg.arg1 = powerGroup.getGroupId();
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
}
}
}
}
Message msg = mHandler.obtainMessage(MSG_SANDMAN);
case MSG_SANDMAN:
handleSandman(msg.arg1);
break
;
private void handleSandman(int groupId) { // runs on handler thread
// Handle preconditions.
final boolean startDreaming;
final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
if (!mPowerGroups.contains(groupId)) {
// Group has been removed.
return;
}
final PowerGroup powerGroup = mPowerGroups.get(groupId);
wakefulness = powerGroup.getWakefulnessLocked();
if (powerGroup.isSandmanSummonedLocked() && powerGroup.isReadyLocked()) {
startDreaming = canDreamLocked(powerGroup) || canDozeLocked(powerGroup);
powerGroup.setSandmanSummonedLocked(/* isSandmanSummoned= */ false);
} else {
startDreaming = false;
}
}
// Start dreaming if needed.
// We only control the dream on the handler thread, so we don't need to worry about
// concurrent attempts to start or stop the dream.
final boolean isDreaming;
if (mDreamManager != null) {
// Restart the dream whenever the sandman is summoned.
if (startDreaming) {
mDreamManager.stopDream(/* immediate= */ false,
"power manager request before starting dream" /*reason*/);
mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING,
"power manager request" /*reason*/);
}
isDreaming = mDreamManager.isDreaming();
} else {
isDreaming = false;
}
// At this point, we either attempted to start the dream or no attempt will be made,
// so stop holding the display suspend blocker for Doze.
mDozeStartInProgress = false;
// Update dream state.
synchronized (mLock) {
if (!mPowerGroups.contains(groupId)) {
// Group has been removed.
return;
}
// Remember the initial battery level when the dream started.
if (startDreaming && isDreaming) {
mDreamsBatteryLevelDrain = 0;
if (wakefulness == WAKEFULNESS_DOZING) {
Slog.i(TAG, "Dozing...");
} else {
Slog.i(TAG, "Dreaming...");
}
}
// If preconditions changed, wait for the next iteration to determine
// whether the dream should continue (or be restarted).
final PowerGroup powerGroup = mPowerGroups.get(groupId);
if (powerGroup.isSandmanSummonedLocked()
|| powerGroup.getWakefulnessLocked() != wakefulness) {
return; // wait for next cycle
}
// Determine whether the dream should continue.
long now = mClock.uptimeMillis();
if (wakefulness == WAKEFULNESS_DREAMING) {
if (isDreaming && canDreamLocked(powerGroup)) {
if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mDreamsBatteryLevelDrain > mDreamsBatteryLevelDrainCutoffConfig
&& !isBeingKeptAwakeLocked(powerGroup)) {
// If the user activity timeout expired and the battery appears
// to be draining faster than it is charging then stop dreaming
// and go to sleep.
Slog.i(TAG, "Stopping dream because the battery appears to "
+ "be draining faster than it is charging. "
+ "Battery level drained while dreaming: "
+ mDreamsBatteryLevelDrain + "%. "
+ "Battery level now: " + mBatteryLevel + "%.");
} else {
return; // continue dreaming
}
}
// Dream has ended or will be stopped. Update the power state.
if (isItBedTimeYetLocked(powerGroup)) {
if (isAttentiveTimeoutExpired(powerGroup, now)) {
sleepPowerGroupLocked(powerGroup, now,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, Process.SYSTEM_UID);
} else {
dozePowerGroupLocked(powerGroup, now,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, Process.SYSTEM_UID);
}
} else {
wakePowerGroupLocked(powerGroup, now,
PowerManager.WAKE_REASON_DREAM_FINISHED,
"android.server.power:DREAM_FINISHED", Process.SYSTEM_UID,
mContext.getOpPackageName(), Process.SYSTEM_UID);
}
} else if (wakefulness == WAKEFULNESS_DOZING) {
if (isDreaming) {
return; // continue dozing
}
// Doze has ended or will be stopped. Update the power state.
sleepPowerGroupLocked(powerGroup, now, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
Process.SYSTEM_UID);
}
}
// Stop dream.
if (isDreaming) {
mDreamManager.stopDream(/* immediate= */ false, "power manager request" /*reason*/);
}
} }
}
mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING,
"power manager request" /*reason*/);
mDreamManager 的实现是在DreamManagerService.java 的 LocalService
DreamManagerService.java
private final class LocalService extends DreamManagerInternal {
@Override
public void startDream(boolean doze, String reason) {
startDreamInternal(doze, reason);
}
private void startDreamInternal(boolean doze, String reason) {
Log.e(TAG, "xz startDreamInternal: doze = " + doze + " reason = " + reason,new Throwable());
final int userId = ActivityManager.getCurrentUser();
final ComponentName dream = chooseDreamForUser(doze, userId);
if (dream != null) {
synchronized (mLock) {
startDreamLocked(dream, false /*isPreviewMode*/, true, userId, reason);
}
}
}
private void startDreamLocked(final ComponentName name,
final boolean isPreviewMode, final boolean canDoze, final int userId,
final String reason) {
if (mCurrentDream != null
&& !mCurrentDream.isWaking
&& Objects.equals(mCurrentDream.name, name)
&& mCurrentDream.isPreview == isPreviewMode
&& mCurrentDream.canDoze == canDoze
&& mCurrentDream.userId == userId) {
Slog.i(TAG, "Already in target dream.");
return;
}
Slog.i(TAG, "Entering dreamland.");
if (mCurrentDream != null && mCurrentDream.isDozing) {
stopDozingInternal(mCurrentDream.token);
}
mCurrentDream = new DreamRecord(name, userId, isPreviewMode, canDoze);
if (!mCurrentDream.name.equals(mAmbientDisplayComponent)) {
// TODO(b/213906448): Remove when metrics based on new atom are fully rolled out.
mUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_START);
mDreamUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_START,
mCurrentDream.name.flattenToString());
}
PowerManager.WakeLock wakeLock = mPowerManager
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, DREAM_WAKE_LOCK_TAG);
final Binder dreamToken = mCurrentDream.token;
mHandler.post(wakeLock.wrap(() -> {
mAtmInternal.notifyActiveDreamChanged(name);
Log.d(TAG, "xz startDreamLocked: mHandler post ");
mController.startDream(dreamToken, name, isPreviewMode, canDoze, userId, wakeLock,
mDreamOverlayServiceName, reason);
}));
}
mController.startDream(dreamToken, name, isPreviewMode, canDoze, userId, wakeLock,
mDreamOverlayServiceName, reason);
DreamController.java
public void startDream(Binder token, ComponentName name,
boolean isPreviewMode, boolean canDoze, int userId, PowerManager.WakeLock wakeLock,
ComponentName overlayComponentName, String reason) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
try {
// Close the notification shade. No need to send to all, but better to be explicit.
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL,
null /* receiverPermission */, mCloseNotificationShadeOptions);
Slog.i(TAG, "Starting dream: name=" + name
+ ", isPreviewMode=" + isPreviewMode + ", canDoze=" + canDoze
+ ", userId=" + userId + ", reason='" + reason + "'");
final DreamRecord oldDream = mCurrentDream;
mCurrentDream = new DreamRecord(token, name, isPreviewMode, canDoze, userId, wakeLock);
if (oldDream != null) {
if (Objects.equals(oldDream.mName, mCurrentDream.mName)) {
// We are attempting to start a dream that is currently waking up gently.
// Let's silently stop the old instance here to clear the dream state.
// This should happen after the new mCurrentDream is set to avoid announcing
// a "dream stopped" state.
stopDreamInstance(/* immediately */ true, "restarting same dream", oldDream);
} else {
mPreviousDreams.add(oldDream);
}
}
mCurrentDream.mDreamStartTime = SystemClock.elapsedRealtime();
MetricsLogger.visible(mContext,
mCurrentDream.mCanDoze ? MetricsEvent.DOZING : MetricsEvent.DREAMING);
Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.putExtra(DreamService.EXTRA_DREAM_OVERLAY_COMPONENT, overlayComponentName);
try {
if (!mContext.bindServiceAsUser(intent, mCurrentDream,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
new UserHandle(userId))) {
Slog.e(TAG, "Unable to bind dream service: " + intent);
stopDream(true /*immediate*/, "bindService failed");
return;
}
} catch (SecurityException ex) {
Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
stopDream(true /*immediate*/, "unable to bind service: SecExp.");
return;
}
mCurrentDream.mBound = true;
mHandler.postDelayed(mCurrentDream.mStopUnconnectedDreamRunnable,
DREAM_CONNECTION_TIMEOUT);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
mContext.bindServiceAsUser(intent, mCurrentDream,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
new UserHandle(userId))
DreamController.java 这里绑定了 DreamService,
@Override
public void onServiceConnected(ComponentName name, final IBinder service) {
mHandler.post(() -> {
mConnected = true;
if (mCurrentDream == DreamRecord.this && mService == null) {
attach(IDreamService.Stub.asInterface(service));
// Wake lock will be released once dreaming starts.
} else {
releaseWakeLockIfNeeded();
}
});
}
private void attach(IDreamService service) {
try {
service.asBinder().linkToDeath(mCurrentDream, 0);
service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze,
mCurrentDream.mIsPreviewMode, mCurrentDream.mDreamingStartedCallback);
} catch (RemoteException ex) {
Slog.e(TAG, "The dream service died unexpectedly.", ex);
stopDream(true /*immediate*/, "attach failed");
return;
}
mCurrentDream.mService = service;
if (!mCurrentDream.mIsPreviewMode && !mSentStartBroadcast) {
mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL,
null /* receiverPermission */, mDreamingStartedStoppedOptions);
mListener.onDreamStarted(mCurrentDream.mToken);
mSentStartBroadcast = true;
}
}
service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze,
mCurrentDream.mIsPreviewMode, mCurrentDream.mDreamingStartedCallback);
这个service是的实现是
DozeService.java 但是 它继承自 DreamService.java
DreamService.java 绑定后返回的是 DreamServiceWrapper
final class DreamServiceWrapper extends IDreamService.Stub {
@Override
public void attach(final IBinder dreamToken, final boolean canDoze,
final boolean isPreviewMode, IRemoteCallback started) {
mHandler.post(
() -> DreamService.this.attach(dreamToken, canDoze, isPreviewMode, started));
}
@Override
public void detach() {
mHandler.post(DreamService.this::detach);
}
@Override
public void wakeUp() {
mHandler.post(() -> DreamService.this.wakeUp(true /*fromSystem*/));
}
}
DreamService.this.attach(dreamToken, canDoze, isPreviewMode, started));
private void attach(IBinder dreamToken, boolean canDoze, boolean isPreviewMode,
IRemoteCallback started) {
if (mDreamToken != null) {
Slog.e(mTag, "attach() called when dream with token=" + mDreamToken
+ " already attached");
return;
}
if (mFinished || mWaking) {
Slog.w(mTag, "attach() called after dream already finished");
try {
mDreamManager.finishSelf(dreamToken, true /*immediate*/);
} catch (RemoteException ex) {
// system server died
}
return;
}
mDreamToken = dreamToken;
mCanDoze = canDoze;
if (mWindowless && !mCanDoze) {
throw new IllegalStateException("Only doze dreams can be windowless");
}
mDispatchAfterOnAttachedToWindow = () -> {
if (mWindow != null || mWindowless) {
mStarted = true;
try {
onDreamingStarted();
} finally {
try {
started.sendResult(null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
};
// We need to defer calling onDreamingStarted until after the activity is created.
// If the dream is windowless, we can call it immediately. Otherwise, we wait
// for the DreamActivity to report onActivityCreated via
// DreamServiceWrapper.onActivityCreated.
if (!mWindowless) {
Intent i = new Intent(this, DreamActivity.class);
i.setPackage(getApplicationContext().getPackageName());
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
i.putExtra(DreamActivity.EXTRA_CALLBACK, new DreamActivityCallbacks(mDreamToken));
final ServiceInfo serviceInfo = fetchServiceInfo(this,
new ComponentName(this, getClass()));
i.putExtra(DreamActivity.EXTRA_DREAM_TITLE,
fetchDreamLabel(this, serviceInfo, isPreviewMode));
try {
if (!ActivityTaskManager.getService().startDreamActivity(i)) {
detach();
}
} catch (SecurityException e) {
Log.w(mTag,
"Received SecurityException trying to start DreamActivity. "
+ "Aborting dream start.");
detach();
} catch (RemoteException e) {
Log.w(mTag, "Could not connect to activity task manager to start dream activity");
e.rethrowFromSystemServer();
}
} else {
mDispatchAfterOnAttachedToWindow.run();
}
}
onDreamingStarted();
这里的DreamService是空实现,所以实现实在DozeService里面
DozeService.java
@Override
public void onDreamingStarted() {
super.onDreamingStarted();
mDozeMachine.requestState(DozeMachine.State.INITIALIZED);
startDozing();
if (mDozePlugin != null) {
mDozePlugin.onDreamingStarted();
}
}
mDozeMachine.requestState(DozeMachine.State.INITIALIZED);
startDozing();
注意这两句,我们先看第一句:这里会改变屏幕状态
DozeMachine.java
private void transitionTo(State requestedState, int pulseReason) {
State newState = transitionPolicy(requestedState);
if (DEBUG) {
Log.i(TAG, "transition: old=" + mState + " req=" + requestedState + " new=" + newState);
}
if (newState == mState) {
return;
}
validateTransition(newState);
State oldState = mState;
mState = newState;
mDozeLog.traceState(newState);
Trace.traceCounter(Trace.TRACE_TAG_APP, "doze_machine_state", newState.ordinal());
updatePulseReason(newState, oldState, pulseReason);
performTransitionOnComponents(oldState, newState);
updateWakeLockState(newState);
resolveIntermediateState(newState);
}
private void performTransitionOnComponents(State oldState, State newState) {
for (Part p : mParts) {
p.transitionTo(oldState, newState);
}
mDozeLog.traceDozeStateSendComplete(newState);
if (newState == State.FINISH) {
mDozeService.finish();
}
}
p.transitionTo(oldState, newState); 注意这个方法会进入到
DozeScreenState.java
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
int screenState = newState.screenState(mParameters);
mDozeHost.cancelGentleSleep();
if (newState == DozeMachine.State.FINISH) {
// Make sure not to apply the screen state after DozeService was destroyed.
mPendingScreenState = Display.STATE_UNKNOWN;
mHandler.removeCallbacks(mApplyPendingScreenState);
applyScreenState(screenState);
mWakeLock.setAcquired(false);
return;
}
if (screenState == Display.STATE_UNKNOWN) {
// We'll keep it in the existing state
return;
}
final boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
final boolean pulseEnding = oldState == DOZE_PULSE_DONE && newState.isAlwaysOn();
final boolean turningOn = (oldState == DOZE_AOD_PAUSED || oldState == DOZE)
&& newState.isAlwaysOn();
final boolean turningOff = (oldState.isAlwaysOn() && newState == DOZE)
|| (oldState == DOZE_AOD_PAUSING && newState == DOZE_AOD_PAUSED);
final boolean justInitialized = oldState == DozeMachine.State.INITIALIZED;
if (messagePending || justInitialized || pulseEnding || turningOn) {
// During initialization, we hide the navigation bar. That is however only applied after
// a traversal; setting the screen state here is immediate however, so it can happen
// that the screen turns on again before the navigation bar is hidden. To work around
// that, wait for a traversal to happen before applying the initial screen state.
mPendingScreenState = screenState;
// Delay screen state transitions even longer while animations are running.
boolean shouldDelayTransitionEnteringDoze = newState == DOZE_AOD
&& mParameters.shouldDelayDisplayDozeTransition() && !turningOn;
// Delay screen state transition longer if UDFPS is actively authenticating a fp
boolean shouldDelayTransitionForUDFPS = newState == DOZE_AOD
&& mUdfpsController != null && mUdfpsController.isFingerDown();
if (!messagePending) {
if (DEBUG) {
Log.d(TAG, "Display state changed to " + screenState + " delayed by "
+ (shouldDelayTransitionEnteringDoze ? ENTER_DOZE_DELAY : 1));
}
if (shouldDelayTransitionEnteringDoze) {
if (justInitialized) {
// If we are delaying transitioning to doze and the display was not
// turned on we set it to 'on' first to make sure that the animation
// is visible before eventually moving it to doze state.
// The display might be off at this point for example on foldable devices
// when we switch displays and go to doze at the same time.
applyScreenState(Display.STATE_ON);
// Restore pending screen state as it gets cleared by 'applyScreenState'
mPendingScreenState = screenState;
}
mHandler.postDelayed(mApplyPendingScreenState, ENTER_DOZE_DELAY);
} else if (shouldDelayTransitionForUDFPS) {
mDozeLog.traceDisplayStateDelayedByUdfps(mPendingScreenState);
mHandler.postDelayed(mApplyPendingScreenState, UDFPS_DISPLAY_STATE_DELAY);
} else {
mHandler.post(mApplyPendingScreenState);
}
} else if (DEBUG) {
Log.d(TAG, "Pending display state change to " + screenState);
}
if (shouldDelayTransitionEnteringDoze || shouldDelayTransitionForUDFPS) {
mWakeLock.setAcquired(true);
}
} else if (turningOff) {
mDozeHost.prepareForGentleSleep(() -> applyScreenState(screenState));
} else {
applyScreenState(screenState);
}
}
延迟进入Doze模式 的关键就是在这里。这里延时改变了屏幕状态。
mHandler.postDelayed(mApplyPendingScreenState, ENTER_DOZE_DELAY);
这个方法会调用到applyScreenState 只有屏幕状态 变成 Display.STATE_DOZE ,屏幕才能进入Doze模式。
private void applyScreenState(int screenState) {
if (screenState != Display.STATE_UNKNOWN) {
if (DEBUG) Log.d(TAG, "setDozeScreenState(" + screenState + ")");
mDozeService.setDozeScreenState(screenState);
if (screenState == Display.STATE_DOZE) {
// If we're entering doze, update the doze screen brightness. We might have been
// clamping it to the dim brightness during the screen off animation, and we should
// now change it to the brightness we actually want according to the sensor.
mDozeScreenBrightness.updateBrightnessAndReady(false /* force */);
}
mPendingScreenState = Display.STATE_UNKNOWN;
mWakeLock.setAcquired(false);
}
}
后面又会调用PowerManagerService.java的updatePowerStateLocked() 更新屏幕状态。
监听到状态改变后会
PowerManagerService.java
@Override
public void onDisplayStateChange(boolean allInactive, boolean allOff) {
// This method is only needed to support legacy display blanking behavior
// where the display's power state is coupled to suspend or to the power HAL.
// The order of operations matters here.
synchronized (mLock) {
setPowerModeInternal(MODE_DISPLAY_INACTIVE, allInactive);
if (allOff) {
if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
setHalInteractiveModeLocked(false);
}
if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true);
}
} else {
if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(false);
}
if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
setHalInteractiveModeLocked(true);
}
}
}
}
setPowerModeInternal(MODE_DISPLAY_INACTIVE, allInactive);
private boolean setPowerModeInternal(int mode, boolean enabled) {
// Maybe filter the event.
if (mode == Mode.LAUNCH && enabled && mBatterySaverController.isLaunchBoostDisabled()) {
return false;
}
return mNativeWrapper.nativeSetPowerMode(mode, enabled);
}
这里就会调用native方法改变屏幕的模式去了.到这里就差不多结束了。
这里接一下上面的
mDozeMachine.requestState(DozeMachine.State.INITIALIZED);
startDozing();
进入到DreamService.java
public void startDozing() {
if (mCanDoze && !mDozing) {
mDozing = true;
updateDoze();
}
}
private void updateDoze() {
if (mDreamToken == null) {
Slog.w(mTag, "Updating doze without a dream token.");
return;
}
if (mDozing) {
try {
mDreamManager.startDozing(mDreamToken, mDozeScreenState, mDozeScreenBrightness);
} catch (RemoteException ex) {
// system server died
}
}
}
mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
这里的mDreamManager 的实现是 DreamManagerService.java 中的 BinderService
@Override // Binder call
public void startDozing(IBinder token, int screenState, int screenBrightness) {
// Requires no permission, called by Dream from an arbitrary process.
if (token == null) {
throw new IllegalArgumentException("token must not be null");
}
final long ident = Binder.clearCallingIdentity();
try {
startDozingInternal(token, screenState, screenBrightness);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void startDozingInternal(IBinder token, int screenState,
int screenBrightness) {
if (DEBUG) {
Slog.d(TAG, "Dream requested to start dozing: " + token
+ ", screenState=" + screenState
+ ", screenBrightness=" + screenBrightness);
}
synchronized (mLock) {
if (mCurrentDream != null && mCurrentDream.token == token && mCurrentDream.canDoze) {
mCurrentDream.dozeScreenState = screenState;
mCurrentDream.dozeScreenBrightness = screenBrightness;
mPowerManagerInternal.setDozeOverrideFromDreamManager(
screenState, screenBrightness);
if (!mCurrentDream.isDozing) {
mCurrentDream.isDozing = true;
mDozeWakeLock.acquire();
}
}
}
}
注意这一句
mPowerManagerInternal.setDozeOverrideFromDreamManager(
screenState, screenBrightness);
这里进入到了PowerManagerService.java
@Override
public void setDozeOverrideFromDreamManager(int screenState, int screenBrightness) {
switch (screenState) {
case Display.STATE_UNKNOWN:
case Display.STATE_OFF:
case Display.STATE_DOZE:
case Display.STATE_DOZE_SUSPEND:
case Display.STATE_ON_SUSPEND:
case Display.STATE_ON:
break;
default:
screenState = Display.STATE_UNKNOWN;
break;
}
if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
|| screenBrightness > PowerManager.BRIGHTNESS_ON) {
screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
}
setDozeOverrideFromDreamManagerInternal(screenState, screenBrightness);
}
第一次进入一般传的是Display.STATE_ON
private void setDozeOverrideFromDreamManagerInternal(
int screenState, int screenBrightness) {
synchronized (mLock) {
if (mDozeScreenStateOverrideFromDreamManager != screenState
|| mDozeScreenBrightnessOverrideFromDreamManager != screenBrightness) {
mDozeScreenStateOverrideFromDreamManager = screenState;
mDozeScreenBrightnessOverrideFromDreamManager = screenBrightness;
mDozeScreenBrightnessOverrideFromDreamManagerFloat =
BrightnessSynchronizer.brightnessIntToFloat(mDozeScreenBrightnessOverrideFromDreamManager);
mDirty |= DIRTY_SETTINGS;
updatePowerStateLocked();
}
}
}
updatePowerStateLocked(); 更新屏幕状态
private void updatePowerStateLocked() {
if (!mSystemReady || mDirty == 0 || mUpdatePowerStateInProgress) {
return;
}
if (!Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
mUpdatePowerStateInProgress = true;
try {
// Phase 0: Basic state updates.
updateIsPoweredLocked(mDirty);
updateStayOnLocked(mDirty);
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = mClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
updateAttentiveStateLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Lock profiles that became inactive/not kept awake.
updateProfilesLocked(now);
// Phase 3: Update power state of all PowerGroups.
final boolean powerGroupsBecameReady = updatePowerGroupsLocked(dirtyPhase2);
// Phase 4: Update dream state (depends on power group ready signal).
updateDreamLocked(dirtyPhase2, powerGroupsBecameReady);
// Phase 5: Send notifications, if needed.
finishWakefulnessChangeIfNeededLocked();
// Phase 6: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
mUpdatePowerStateInProgress = false;
}
}