Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 124a5084 authored by Matt Pietal's avatar Matt Pietal
Browse files

Update user switching processes

Add a new callback for UserController. If the user is secure, initiate
a call to SystemUI to lockNow(), and wait for the callback. If the
callback does not arrive, crash the system after some time.

In SystemUI, add support for onBeforeUserSwitching. When this request
comes in, prepare the keyguard and show it before calling back to notify
UserController that it is ready to proceed.

Also, ensure that any switch is user that occurs after WM has been
notified that SystemUI is going away is stopped.

Bug: 322157041
Test: atest KeyguardViewMediatorTest
Flag: EXEMPT bugfix

Change-Id: I6e48ae4787680f0be80525b0228883523ef08a7d
parent abef94fb
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -204,6 +204,15 @@ public class KeyguardManager {
     */
    public static final String EXTRA_DISALLOW_BIOMETRICS_IF_POLICY_EXISTS = "check_dpm";

    /**
     * When switching to a secure user, system server will expect a callback when the UI has
     * completed the switch.
     *
     * @hide
     */
    public static final String LOCK_ON_USER_SWITCH_CALLBACK = "onSwitchCallback";


    /**
     *
     * Password lock type, see {@link #setLock}
+199 −33

File changed.

Preview size limit exceeded, changes collapsed.

+153 −13

File changed.

Preview size limit exceeded, changes collapsed.

+10 −28
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -3904,10 +3905,6 @@ class UserController implements Handler.Callback {
            return mService.mWindowManager;
        }

        ActivityTaskManagerInternal getActivityTaskManagerInternal() {
            return mService.mAtmInternal;
        }

        void activityManagerOnUserStopped(@UserIdInt int userId) {
            LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId);
        }
@@ -4122,40 +4119,25 @@ class UserController implements Handler.Callback {
        }

        void lockDeviceNowAndWaitForKeyguardShown() {
            if (getWindowManager().isKeyguardLocked()) {
                Slogf.w(TAG, "Not locking the device since the keyguard is already locked");
                return;
            }

            final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
            t.traceBegin("lockDeviceNowAndWaitForKeyguardShown");

            final CountDownLatch latch = new CountDownLatch(1);
            ActivityTaskManagerInternal.ScreenObserver screenObserver =
                    new ActivityTaskManagerInternal.ScreenObserver() {
                        @Override
                        public void onAwakeStateChanged(boolean isAwake) {

                        }

                        @Override
                        public void onKeyguardStateChanged(boolean isShowing) {
                            if (isShowing) {
            Bundle bundle = new Bundle();
            bundle.putBinder(LOCK_ON_USER_SWITCH_CALLBACK, new IRemoteCallback.Stub() {
                public void sendResult(Bundle data) {
                    latch.countDown();
                }
                        }
                    };

            getActivityTaskManagerInternal().registerScreenObserver(screenObserver);
            getWindowManager().lockDeviceNow();
            });
            getWindowManager().lockNow(bundle);
            try {
                if (!latch.await(20, TimeUnit.SECONDS)) {
                    throw new RuntimeException("Keyguard is not shown in 20 seconds");
                    throw new RuntimeException("User controller expected a callback while waiting "
                            + "to show the keyguard. Timed out after 20 seconds.");
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                getActivityTaskManagerInternal().unregisterScreenObserver(screenObserver);
                t.traceEnd();
            }
        }
+6 −13
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;

@@ -115,7 +116,6 @@ import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.UserTypeDetails;
import com.android.server.pm.UserTypeFactory;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerService;

import com.google.common.collect.Range;
@@ -1563,11 +1563,11 @@ public class UserControllerTest {
        // and the thread is still alive
        assertTrue(threadStartUser.isAlive());

        // mock send the keyguard shown event
        ArgumentCaptor<ActivityTaskManagerInternal.ScreenObserver> captor = ArgumentCaptor.forClass(
                ActivityTaskManagerInternal.ScreenObserver.class);
        verify(mInjector.mActivityTaskManagerInternal).registerScreenObserver(captor.capture());
        captor.getValue().onKeyguardStateChanged(true);
        // mock the binder response for the user switch completion
        ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
        verify(mInjector.mWindowManagerMock).lockNow(captor.capture());
        IRemoteCallback.Stub.asInterface(captor.getValue().getBinder(
                LOCK_ON_USER_SWITCH_CALLBACK)).sendResult(null);

        // verify the switch now moves on...
        Thread.sleep(1000);
@@ -1757,7 +1757,6 @@ public class UserControllerTest {
        private final IStorageManager mStorageManagerMock;
        private final UserManagerInternal mUserManagerInternalMock;
        private final WindowManagerService mWindowManagerMock;
        private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
        private final PowerManagerInternal mPowerManagerInternal;
        private final AlarmManagerInternal mAlarmManagerInternal;
        private final KeyguardManager mKeyguardManagerMock;
@@ -1779,7 +1778,6 @@ public class UserControllerTest {
            mUserManagerMock = mock(UserManagerService.class);
            mUserManagerInternalMock = mock(UserManagerInternal.class);
            mWindowManagerMock = mock(WindowManagerService.class);
            mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
            mStorageManagerMock = mock(IStorageManager.class);
            mPowerManagerInternal = mock(PowerManagerInternal.class);
            mAlarmManagerInternal = mock(AlarmManagerInternal.class);
@@ -1842,11 +1840,6 @@ public class UserControllerTest {
            return mWindowManagerMock;
        }

        @Override
        ActivityTaskManagerInternal getActivityTaskManagerInternal() {
            return mActivityTaskManagerInternal;
        }

        @Override
        PowerManagerInternal getPowerManagerInternal() {
            return mPowerManagerInternal;