Fix VR interaction with screen on/off/lockscreen.

- Add mechanism to prevent VR mode from being enabled.
- Disable VR mode while screen is off, or user is in lockscreen,
  and re-enable when this is no longer the case.

Merged-In: Ia0a7fe8d443a24dce9395053cfe3d1c5847a88f2

Bug: 31665197
Change-Id: Ia0a7fe8d443a24dce9395053cfe3d1c5847a88f2
This commit is contained in:
Ruben Brunk
2016-10-28 20:18:57 -07:00
parent 7ba6d21aac
commit 040484cf90
4 changed files with 167 additions and 76 deletions

View File

@@ -1212,6 +1212,15 @@ public final class ActivityManagerService extends ActivityManagerNative
/** /**
* Set while we are wanting to sleep, to prevent any * Set while we are wanting to sleep, to prevent any
* activities from being started/resumed. * activities from being started/resumed.
*
* TODO(b/33594039): Clarify the actual state transitions represented by mSleeping.
*
* Currently mSleeping is set to true when transitioning into the sleep state, and remains true
* while in the sleep state until there is a pending transition out of sleep, in which case
* mSleeping is set to false, and remains false while awake.
*
* Whether mSleeping can quickly toggled between true/false without the device actually
* display changing states is undefined.
*/ */
private boolean mSleeping = false; private boolean mSleeping = false;
@@ -1537,8 +1546,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66; static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66;
static final int NOTIFY_FORCED_RESIZABLE_MSG = 67; static final int NOTIFY_FORCED_RESIZABLE_MSG = 67;
static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 68; static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 68;
static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69; static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 69;
static final int SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG = 70;
static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200; static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2353,14 +2361,6 @@ public final class ActivityManagerService extends ActivityManagerNative
} }
vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage); vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
} break; } break;
case VR_MODE_APPLY_IF_NEEDED_MSG: {
final ActivityRecord r = (ActivityRecord) msg.obj;
final boolean needsVrMode = r != null && r.requestedVrComponent != null;
if (needsVrMode) {
applyVrMode(msg.arg1 == 1, r.requestedVrComponent, r.userId,
r.info.getComponentName(), false);
}
} break;
} }
} }
}; };
@@ -3159,20 +3159,12 @@ public final class ActivityManagerService extends ActivityManagerNative
mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r));
} }
private void applyVrModeIfNeededLocked(ActivityRecord r, boolean enable) { private void notifyVrManagerOfSleepState(boolean isSleeping) {
mHandler.sendMessage( final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
mHandler.obtainMessage(VR_MODE_APPLY_IF_NEEDED_MSG, enable ? 1 : 0, 0, r)); if (vrService == null) {
} return;
private void applyVrMode(boolean enabled, ComponentName packageName, int userId,
ComponentName callingPackage, boolean immediate) {
VrManagerInternal vrService =
LocalServices.getService(VrManagerInternal.class);
if (immediate) {
vrService.setVrModeImmediate(enabled, packageName, userId, callingPackage);
} else {
vrService.setVrMode(enabled, packageName, userId, callingPackage);
} }
vrService.onSleepStateChanged(isSleeping);
} }
final void showAskCompatModeDialogLocked(ActivityRecord r) { final void showAskCompatModeDialogLocked(ActivityRecord r) {
@@ -6754,7 +6746,6 @@ public final class ActivityManagerService extends ActivityManagerNative
// Some stack visibility might change (e.g. docked stack) // Some stack visibility might change (e.g. docked stack)
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
applyVrModeIfNeededLocked(mFocusedActivity, true);
} }
} }
} finally { } finally {
@@ -11683,6 +11674,7 @@ public final class ActivityManagerService extends ActivityManagerNative
startTimeTrackingFocusedActivityLocked(); startTimeTrackingFocusedActivityLocked();
mTopProcessState = ActivityManager.PROCESS_STATE_TOP; mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
mStackSupervisor.comeOutOfSleepIfNeededLocked(); mStackSupervisor.comeOutOfSleepIfNeededLocked();
notifyVrManagerOfSleepState(false);
updateOomAdjLocked(); updateOomAdjLocked();
} else if (!mSleeping && shouldSleepLocked()) { } else if (!mSleeping && shouldSleepLocked()) {
mSleeping = true; mSleeping = true;
@@ -11691,6 +11683,7 @@ public final class ActivityManagerService extends ActivityManagerNative
} }
mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING; mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING;
mStackSupervisor.goingToSleepLocked(); mStackSupervisor.goingToSleepLocked();
notifyVrManagerOfSleepState(true);
updateOomAdjLocked(); updateOomAdjLocked();
// Initialize the wake times of all processes. // Initialize the wake times of all processes.
@@ -21916,21 +21909,6 @@ public final class ActivityManagerService extends ActivityManagerNative
public SleepToken acquireSleepToken(String tag) { public SleepToken acquireSleepToken(String tag) {
Preconditions.checkNotNull(tag); Preconditions.checkNotNull(tag);
ComponentName requestedVrService = null;
ComponentName callingVrActivity = null;
int userId = -1;
synchronized (ActivityManagerService.this) {
if (mFocusedActivity != null) {
requestedVrService = mFocusedActivity.requestedVrComponent;
callingVrActivity = mFocusedActivity.info.getComponentName();
userId = mFocusedActivity.userId;
}
}
if (requestedVrService != null) {
applyVrMode(false, requestedVrService, userId, callingVrActivity, true);
}
synchronized (ActivityManagerService.this) { synchronized (ActivityManagerService.this) {
SleepTokenImpl token = new SleepTokenImpl(tag); SleepTokenImpl token = new SleepTokenImpl(tag);
mSleepTokens.add(token); mSleepTokens.add(token);

View File

@@ -152,6 +152,7 @@ import com.android.server.LocalServices;
import com.android.server.policy.keyguard.KeyguardServiceDelegate; import com.android.server.policy.keyguard.KeyguardServiceDelegate;
import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener; import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.vr.VrManagerInternal;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
@@ -6522,6 +6523,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDelegate.onScreenTurnedOff(); mKeyguardDelegate.onScreenTurnedOff();
} }
} }
reportScreenStateToVrManager(false);
} }
// Called on the DisplayManager's DisplayPowerController thread. // Called on the DisplayManager's DisplayPowerController thread.
@@ -6557,6 +6559,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDelegate.onScreenTurnedOn(); mKeyguardDelegate.onScreenTurnedOn();
} }
} }
reportScreenStateToVrManager(true);
}
private void reportScreenStateToVrManager(boolean isScreenOn) {
VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
if (vrService == null) {
return;
}
vrService.onScreenStateChanged(isScreenOn);
} }
private void finishWindowsDrawn() { private void finishWindowsDrawn() {

View File

@@ -56,25 +56,27 @@ public abstract class VrManagerInternal {
int userId, @NonNull ComponentName calling); int userId, @NonNull ComponentName calling);
/** /**
* Set the current VR mode state immediately. * Set whether the system has acquired a sleep token.
* *
* @param enabled {@code true} to enable VR mode. * @param isAsleep is {@code true} if the device is asleep, or {@code false} otherwise.
* @param packageName The package name of the requested VrListenerService to bind.
* @param userId the user requesting the VrListenerService component.
* @param calling the component currently using VR mode, or null to leave unchanged.
*/ */
public abstract void setVrModeImmediate(boolean enabled, @NonNull ComponentName packageName, public abstract void onSleepStateChanged(boolean isAsleep);
int userId, @NonNull ComponentName calling);
/**
* Set whether the display used for VR output is on.
*
* @param isScreenOn is {@code true} if the display is on and can receive commands,
* or {@code false} otherwise.
*/
public abstract void onScreenStateChanged(boolean isScreenOn);
/** /**
* Return NO_ERROR if the given package is installed on the device and enabled as a * Return NO_ERROR if the given package is installed on the device and enabled as a
* VrListenerService for the given current user, or a negative error code indicating a failure. * VrListenerService for the given current user, or a negative error code indicating a failure.
* *
* @param packageName the name of the package to check, or null to select the default package. * @param packageName the name of the package to check, or null to select the default package.
* @return NO_ERROR if the given package is installed and is enabled, or a negative error code * @return NO_ERROR if the given package is installed and is enabled, or a negative error code
* given in {@link android.service.vr.VrModeException} on failure. * given in {@link android.service.vr.VrModeException} on failure.
*/ */
public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId); public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
} }

View File

@@ -101,6 +101,14 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private static final int PENDING_STATE_DELAY_MS = 300; private static final int PENDING_STATE_DELAY_MS = 300;
private static final int EVENT_LOG_SIZE = 32; private static final int EVENT_LOG_SIZE = 32;
private static final int INVALID_APPOPS_MODE = -1; private static final int INVALID_APPOPS_MODE = -1;
/** Null set of sleep sleep flags. */
private static final int FLAG_NONE = 0;
/** Flag set when the device is not sleeping. */
private static final int FLAG_AWAKE = 1;
/** Flag set when the screen has been turned on. */
private static final int FLAG_SCREEN_ON = 2;
/** Flag indicating that all system sleep flags have been set.*/
private static final int FLAG_ALL = FLAG_AWAKE | FLAG_SCREEN_ON;
private static native void initializeNative(); private static native void initializeNative();
private static native void setVrModeNative(boolean enabled); private static native void setVrModeNative(boolean enabled);
@@ -110,6 +118,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private final IBinder mOverlayToken = new Binder(); private final IBinder mOverlayToken = new Binder();
// State protected by mLock // State protected by mLock
private boolean mVrModeAllowed;
private boolean mVrModeEnabled; private boolean mVrModeEnabled;
private EnabledComponentsObserver mComponentObserver; private EnabledComponentsObserver mComponentObserver;
private ManagedApplicationService mCurrentVrService; private ManagedApplicationService mCurrentVrService;
@@ -125,10 +134,64 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private VrState mPendingState; private VrState mPendingState;
private final ArrayDeque<VrState> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE); private final ArrayDeque<VrState> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager(); private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
/** Tracks the state of the screen and keyguard UI.*/
private int mSystemSleepFlags = FLAG_NONE;
private static final int MSG_VR_STATE_CHANGE = 0; private static final int MSG_VR_STATE_CHANGE = 0;
private static final int MSG_PENDING_VR_STATE_CHANGE = 1; private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
/**
* Set whether VR mode may be enabled.
* <p/>
* If VR mode is not allowed to be enabled, calls to set VR mode will be cached. When VR mode
* is again allowed to be enabled, the most recent cached state will be applied.
*
* @param allowed {@code true} if calling any of the setVrMode methods may cause the device to
* enter VR mode.
*/
private void setVrModeAllowedLocked(boolean allowed) {
if (mVrModeAllowed != allowed) {
mVrModeAllowed = allowed;
Slog.i(TAG, "VR mode is " + ((allowed) ? "allowed" : "disallowed"));
if (mVrModeAllowed) {
consumeAndApplyPendingStateLocked();
} else {
// Set pending state to current state.
mPendingState = (mVrModeEnabled && mCurrentVrService != null)
? new VrState(mVrModeEnabled, mCurrentVrService.getComponent(),
mCurrentVrService.getUserId(), mCurrentVrModeComponent)
: null;
// Unbind current VR service and do necessary callbacks.
updateCurrentVrServiceLocked(false, null, 0, null);
}
}
}
private void setSleepState(boolean isAsleep) {
synchronized(mLock) {
if (!isAsleep) {
mSystemSleepFlags |= FLAG_AWAKE;
} else {
mSystemSleepFlags &= ~FLAG_AWAKE;
}
setVrModeAllowedLocked(mSystemSleepFlags == FLAG_ALL);
}
}
private void setScreenOn(boolean isScreenOn) {
synchronized(mLock) {
if (isScreenOn) {
mSystemSleepFlags |= FLAG_SCREEN_ON;
} else {
mSystemSleepFlags &= ~FLAG_SCREEN_ON;
}
setVrModeAllowedLocked(mSystemSleepFlags == FLAG_ALL);
}
}
private final Handler mHandler = new Handler() { private final Handler mHandler = new Handler() {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
@@ -148,7 +211,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC
} break; } break;
case MSG_PENDING_VR_STATE_CHANGE : { case MSG_PENDING_VR_STATE_CHANGE : {
synchronized(mLock) { synchronized(mLock) {
VrManagerService.this.consumeAndApplyPendingStateLocked(); if (mVrModeAllowed) {
VrManagerService.this.consumeAndApplyPendingStateLocked();
}
} }
} break; } break;
default : default :
@@ -268,8 +333,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
} }
mNotifAccessManager.update(enabledPackages); mNotifAccessManager.update(enabledPackages);
if (mCurrentVrService == null) { if (!mVrModeAllowed) {
return; // No active services return; // Don't do anything, we shouldn't be in VR mode.
} }
// If there is a pending state change, we'd better deal with that first // If there is a pending state change, we'd better deal with that first
@@ -321,6 +386,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
return; return;
} }
pw.println("********* Dump of VrManagerService *********"); pw.println("********* Dump of VrManagerService *********");
pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
pw.println("Previous state transitions:\n"); pw.println("Previous state transitions:\n");
String tab = " "; String tab = " ";
dumpStateTransitions(pw); dumpStateTransitions(pw);
@@ -374,13 +440,17 @@ public class VrManagerService extends SystemService implements EnabledComponentC
@Override @Override
public void setVrMode(boolean enabled, ComponentName packageName, int userId, public void setVrMode(boolean enabled, ComponentName packageName, int userId,
ComponentName callingPackage) { ComponentName callingPackage) {
VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, false); VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
} }
@Override @Override
public void setVrModeImmediate(boolean enabled, ComponentName packageName, int userId, public void onSleepStateChanged(boolean isAsleep) {
ComponentName callingPackage) { VrManagerService.this.setSleepState(isAsleep);
VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, true); }
@Override
public void onScreenStateChanged(boolean isScreenOn) {
VrManagerService.this.setScreenOn(isScreenOn);
} }
@Override @Override
@@ -424,6 +494,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
mComponentObserver.rebuildAll(); mComponentObserver.rebuildAll();
} }
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mLock) {
mVrModeAllowed = true;
}
} }
} }
@@ -466,12 +540,16 @@ public class VrManagerService extends SystemService implements EnabledComponentC
false, mOverlayToken, null, oldUserId); false, mOverlayToken, null, oldUserId);
} }
if (!mVrModeEnabled) {
return;
}
// Apply the restrictions for the current user based on vr state // Apply the restrictions for the current user based on vr state
String[] exemptions = (exemptedPackage == null) ? new String[0] : String[] exemptions = (exemptedPackage == null) ? new String[0] :
new String[] { exemptedPackage }; new String[] { exemptedPackage };
appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
mVrModeEnabled, mOverlayToken, exemptions, newUserId); true, mOverlayToken, exemptions, newUserId);
} }
private void updateDependentAppOpsLocked(String newVrServicePackage, int newUserId, private void updateDependentAppOpsLocked(String newVrServicePackage, int newUserId,
@@ -512,7 +590,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
boolean validUserComponent = (mComponentObserver.isValid(component, userId) == boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
EnabledComponentsObserver.NO_ERROR); EnabledComponentsObserver.NO_ERROR);
if (!mVrModeEnabled && !enabled) { boolean goingIntoVrMode = validUserComponent && enabled;
if (!mVrModeEnabled && !goingIntoVrMode) {
return validUserComponent; // Disabled -> Disabled transition does nothing. return validUserComponent; // Disabled -> Disabled transition does nothing.
} }
@@ -520,29 +599,37 @@ public class VrManagerService extends SystemService implements EnabledComponentC
? mCurrentVrService.getComponent().getPackageName() : null; ? mCurrentVrService.getComponent().getPackageName() : null;
final int oldUserId = mCurrentVrModeUser; final int oldUserId = mCurrentVrModeUser;
// Always send mode change events. // Notify system services and VR HAL of mode change.
changeVrModeLocked(enabled); changeVrModeLocked(goingIntoVrMode);
if (!enabled || !validUserComponent) { boolean nothingChanged = false;
// Unbind whatever is running if (!goingIntoVrMode) {
// Not going into VR mode, unbind whatever is running
if (mCurrentVrService != null) { if (mCurrentVrService != null) {
Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " + Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
mCurrentVrService.getUserId()); mCurrentVrService.getUserId());
mCurrentVrService.disconnect(); mCurrentVrService.disconnect();
mCurrentVrService = null; mCurrentVrService = null;
} else {
nothingChanged = true;
} }
} else { } else {
// Going into VR mode
if (mCurrentVrService != null) { if (mCurrentVrService != null) {
// Unbind any running service that doesn't match the component/user selection // Unbind any running service that doesn't match the latest component/user
// selection.
if (mCurrentVrService.disconnectIfNotMatching(component, userId)) { if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
" for user " + mCurrentVrService.getUserId()); " for user " + mCurrentVrService.getUserId());
createAndConnectService(component, userId); createAndConnectService(component, userId);
sendUpdatedCaller = true; sendUpdatedCaller = true;
} else {
nothingChanged = true;
} }
// The service with the correct component/user is bound // The service with the correct component/user is already bound, do nothing.
} else { } else {
// Nothing was previously running, bind a new service // Nothing was previously running, bind a new service for the latest
// component/user selection.
createAndConnectService(component, userId); createAndConnectService(component, userId);
sendUpdatedCaller = true; sendUpdatedCaller = true;
} }
@@ -577,7 +664,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
} }
}); });
} }
logStateLocked();
if (!nothingChanged) {
logStateLocked();
}
return validUserComponent; return validUserComponent;
} finally { } finally {
@@ -772,7 +862,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC
mPendingState.targetPackageName, mPendingState.userId, mPendingState.targetPackageName, mPendingState.userId,
mPendingState.callingPackage); mPendingState.callingPackage);
mPendingState = null; mPendingState = null;
} else {
updateCurrentVrServiceLocked(false, null, 0, null);
} }
} }
private void logStateLocked() { private void logStateLocked() {
@@ -822,13 +915,20 @@ public class VrManagerService extends SystemService implements EnabledComponentC
/* /*
* Implementation of VrManagerInternal calls. These are callable from system services. * Implementation of VrManagerInternal calls. These are callable from system services.
*/ */
private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName, private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
int userId, @NonNull ComponentName callingPackage, boolean immediate) { int userId, @NonNull ComponentName callingPackage) {
synchronized (mLock) { synchronized (mLock) {
VrState pending = new VrState(enabled, targetPackageName, userId, callingPackage);
if (!mVrModeAllowed) {
// We're not allowed to be in VR mode. Make this state pending. This will be
// applied the next time we are allowed to enter VR mode unless it is superseded by
// another call.
mPendingState = pending;
return;
}
if (!enabled && mCurrentVrService != null && !immediate) { if (!enabled && mCurrentVrService != null) {
// If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls // If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
// and service bind/unbind in case we are immediately switching to another VR app. // and service bind/unbind in case we are immediately switching to another VR app.
if (mPendingState == null) { if (mPendingState == null) {
@@ -836,7 +936,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
PENDING_STATE_DELAY_MS); PENDING_STATE_DELAY_MS);
} }
mPendingState = new VrState(enabled, targetPackageName, userId, callingPackage); mPendingState = pending;
return; return;
} else { } else {
mHandler.removeMessages(MSG_PENDING_VR_STATE_CHANGE); mHandler.removeMessages(MSG_PENDING_VR_STATE_CHANGE);