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

Commit f60aa384 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Integrate new boot user flow with auto" into udc-dev am: 25126020

parents cf376650 25126020
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -573,5 +573,6 @@ public abstract class UserManagerInternal {


     * @throws UserManager.CheckedUserOperationException if no switchable user can be found
     * @throws UserManager.CheckedUserOperationException if no switchable user can be found
     */
     */
    public abstract @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException;
    public abstract @UserIdInt int getBootUser(boolean waitUntilSet)
            throws UserManager.CheckedUserOperationException;
}
}
+70 −38
Original line number Original line Diff line number Diff line
@@ -161,7 +161,9 @@ import java.util.LinkedList;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
import java.util.Set;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReference;


@@ -278,6 +280,8 @@ public class UserManagerService extends IUserManager.Stub {
    static final int WRITE_USER_MSG = 1;
    static final int WRITE_USER_MSG = 1;
    static final int WRITE_USER_DELAY = 2*1000;  // 2 seconds
    static final int WRITE_USER_DELAY = 2*1000;  // 2 seconds


    private static final long BOOT_USER_SET_TIMEOUT_MS = 300_000;

    // Tron counters
    // Tron counters
    private static final String TRON_GUEST_CREATED = "users_guest_created";
    private static final String TRON_GUEST_CREATED = "users_guest_created";
    private static final String TRON_USER_CREATED = "users_user_created";
    private static final String TRON_USER_CREATED = "users_user_created";
@@ -333,6 +337,8 @@ public class UserManagerService extends IUserManager.Stub {
    /** Indicates that this is the 1st boot after the system user mode was changed by emulation. */
    /** Indicates that this is the 1st boot after the system user mode was changed by emulation. */
    private boolean mUpdatingSystemUserMode;
    private boolean mUpdatingSystemUserMode;


    /** Count down latch to wait while boot user is not set.*/
    private final CountDownLatch mBootUserLatch = new CountDownLatch(1);
    /**
    /**
     * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps.
     * Internal non-parcelable wrapper for UserInfo that is not exposed to other system apps.
     */
     */
@@ -952,18 +958,62 @@ public class UserManagerService extends IUserManager.Stub {
            Slogf.i(LOG_TAG, "setBootUser %d", userId);
            Slogf.i(LOG_TAG, "setBootUser %d", userId);
            mBootUser = userId;
            mBootUser = userId;
        }
        }
        mBootUserLatch.countDown();
    }
    }


    @Override
    @Override
    public @UserIdInt int getBootUser() {
    public @UserIdInt int getBootUser() {
        checkCreateUsersPermission("Get boot user");
        checkCreateUsersPermission("Get boot user");
        try {
        try {
            return mLocalService.getBootUser();
            return getBootUserUnchecked();
        } catch (UserManager.CheckedUserOperationException e) {
        } catch (UserManager.CheckedUserOperationException e) {
            throw e.toServiceSpecificException();
            throw e.toServiceSpecificException();
        }
        }
    }
    }


    private @UserIdInt int getBootUserUnchecked() throws UserManager.CheckedUserOperationException {
        synchronized (mUsersLock) {
            if (mBootUser != UserHandle.USER_NULL) {
                final UserData userData = mUsers.get(mBootUser);
                if (userData != null && userData.info.supportsSwitchToByUser()) {
                    Slogf.i(LOG_TAG, "Using provided boot user: %d", mBootUser);
                    return mBootUser;
                } else {
                    Slogf.w(LOG_TAG,
                            "Provided boot user cannot be switched to: %d", mBootUser);
                }
            }
        }

        if (isHeadlessSystemUserMode()) {
            // Return the previous foreground user, if there is one.
            final int previousUser = getPreviousFullUserToEnterForeground();
            if (previousUser != UserHandle.USER_NULL) {
                Slogf.i(LOG_TAG, "Boot user is previous user %d", previousUser);
                return previousUser;
            }
            // No previous user. Return the first switchable user if there is one.
            synchronized (mUsersLock) {
                final int userSize = mUsers.size();
                for (int i = 0; i < userSize; i++) {
                    final UserData userData = mUsers.valueAt(i);
                    if (userData.info.supportsSwitchToByUser()) {
                        int firstSwitchable = userData.info.id;
                        Slogf.i(LOG_TAG,
                                "Boot user is first switchable user %d", firstSwitchable);
                        return firstSwitchable;
                    }
                }
            }
            // No switchable users found. Uh oh!
            throw new UserManager.CheckedUserOperationException(
                    "No switchable users found", USER_OPERATION_ERROR_UNKNOWN);
        }
        // Not HSUM, return system user.
        return UserHandle.USER_SYSTEM;
    }


    @Override
    @Override
    public int getPreviousFullUserToEnterForeground() {
    public int getPreviousFullUserToEnterForeground() {
        checkQueryOrCreateUsersPermission("get previous user");
        checkQueryOrCreateUsersPermission("get previous user");
@@ -7182,47 +7232,29 @@ public class UserManagerService extends IUserManager.Stub {
        }
        }


        @Override
        @Override
        public @UserIdInt int getBootUser() throws UserManager.CheckedUserOperationException {
        public @UserIdInt int getBootUser(boolean waitUntilSet)
            synchronized (mUsersLock) {
                throws UserManager.CheckedUserOperationException {
                // TODO(b/242195409): On Automotive, block if boot user not provided.
            if (waitUntilSet) {
                if (mBootUser != UserHandle.USER_NULL) {
                final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
                    final UserData userData = mUsers.get(mBootUser);
                t.traceBegin("wait-boot-user");
                    if (userData != null && userData.info.supportsSwitchToByUser()) {
                try {
                        Slogf.i(LOG_TAG, "Using provided boot user: %d", mBootUser);
                    if (mBootUserLatch.getCount() != 0) {
                        return mBootUser;
                        Slogf.d(LOG_TAG,
                    } else {
                                "Sleeping for boot user to be set. "
                        Slogf.w(LOG_TAG,
                                + "Max sleep for Time: %d", BOOT_USER_SET_TIMEOUT_MS);
                                "Provided boot user cannot be switched to: %d", mBootUser);
                    }
                }
            }

            if (isHeadlessSystemUserMode()) {
                // Return the previous foreground user, if there is one.
                final int previousUser = getPreviousFullUserToEnterForeground();
                if (previousUser != UserHandle.USER_NULL) {
                    Slogf.i(LOG_TAG, "Boot user is previous user %d", previousUser);
                    return previousUser;
                }
                // No previous user. Return the first switchable user if there is one.
                synchronized (mUsersLock) {
                    final int userSize = mUsers.size();
                    for (int i = 0; i < userSize; i++) {
                        final UserData userData = mUsers.valueAt(i);
                        if (userData.info.supportsSwitchToByUser()) {
                            int firstSwitchable = userData.info.id;
                            Slogf.i(LOG_TAG,
                                    "Boot user is first switchable user %d", firstSwitchable);
                            return firstSwitchable;
                    }
                    }
                    if (!mBootUserLatch.await(BOOT_USER_SET_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
                        Slogf.w(LOG_TAG, "Boot user not set. Timeout: %d",
                                BOOT_USER_SET_TIMEOUT_MS);
                    }
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    Slogf.w(LOG_TAG, e, "InterruptedException during wait for boot user.");
                }
                }
                // No switchable users found. Uh oh!
                t.traceEnd();
                throw new UserManager.CheckedUserOperationException(
                        "No switchable users found", USER_OPERATION_ERROR_UNKNOWN);
            }
            }
            // Not HSUM, return system user.

            return UserHandle.USER_SYSTEM;
            return getBootUserUnchecked();
        }
        }


    } // class LocalService
    } // class LocalService
+11 −4
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
import android.content.ContentResolver;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Handler;
@@ -27,6 +28,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings;


import com.android.server.am.ActivityManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.Slogf;
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -41,6 +43,7 @@ final class HsumBootUserInitializer {


    private final UserManagerInternal mUmi;
    private final UserManagerInternal mUmi;
    private final ActivityManagerService mAms;
    private final ActivityManagerService mAms;
    private final PackageManagerService mPms;
    private final ContentResolver mContentResolver;
    private final ContentResolver mContentResolver;


    private final ContentObserver mDeviceProvisionedObserver =
    private final ContentObserver mDeviceProvisionedObserver =
@@ -63,20 +66,23 @@ final class HsumBootUserInitializer {


    /** Static factory method for creating a {@link HsumBootUserInitializer} instance. */
    /** Static factory method for creating a {@link HsumBootUserInitializer} instance. */
    public static @Nullable HsumBootUserInitializer createInstance(ActivityManagerService am,
    public static @Nullable HsumBootUserInitializer createInstance(ActivityManagerService am,
            ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser) {
            PackageManagerService pms, ContentResolver contentResolver,
            boolean shouldAlwaysHaveMainUser) {


        if (!UserManager.isHeadlessSystemUserMode()) {
        if (!UserManager.isHeadlessSystemUserMode()) {
            return null;
            return null;
        }
        }
        return new HsumBootUserInitializer(
        return new HsumBootUserInitializer(
                LocalServices.getService(UserManagerInternal.class),
                LocalServices.getService(UserManagerInternal.class),
                am, contentResolver, shouldAlwaysHaveMainUser);
                am, pms, contentResolver, shouldAlwaysHaveMainUser);
    }
    }


    private HsumBootUserInitializer(UserManagerInternal umi, ActivityManagerService am,
    private HsumBootUserInitializer(UserManagerInternal umi, ActivityManagerService am,
            ContentResolver contentResolver, boolean shouldAlwaysHaveMainUser) {
            PackageManagerService pms, ContentResolver contentResolver,
            boolean shouldAlwaysHaveMainUser) {
        mUmi = umi;
        mUmi = umi;
        mAms = am;
        mAms = am;
        mPms = pms;
        mContentResolver = contentResolver;
        mContentResolver = contentResolver;
        mShouldAlwaysHaveMainUser = shouldAlwaysHaveMainUser;
        mShouldAlwaysHaveMainUser = shouldAlwaysHaveMainUser;
    }
    }
@@ -131,7 +137,8 @@ final class HsumBootUserInitializer {


        try {
        try {
            t.traceBegin("getBootUser");
            t.traceBegin("getBootUser");
            final int bootUser = mUmi.getBootUser();
            final int bootUser = mUmi.getBootUser(/* waitUntilSet= */ mPms
                    .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, /* version= */0));
            t.traceEnd();
            t.traceEnd();
            t.traceBegin("switchToBootUser-" + bootUser);
            t.traceBegin("switchToBootUser-" + bootUser);
            switchToBootUser(bootUser);
            switchToBootUser(bootUser);
+2 −3
Original line number Original line Diff line number Diff line
@@ -2721,7 +2721,7 @@ public final class SystemServer implements Dumpable {
        // on it in their setup, but likely needs to be done after LockSettingsService is ready.
        // on it in their setup, but likely needs to be done after LockSettingsService is ready.
        final HsumBootUserInitializer hsumBootUserInitializer =
        final HsumBootUserInitializer hsumBootUserInitializer =
                HsumBootUserInitializer.createInstance(
                HsumBootUserInitializer.createInstance(
                        mActivityManagerService, mContentResolver,
                        mActivityManagerService, mPackageManagerService, mContentResolver,
                        context.getResources().getBoolean(R.bool.config_isMainUserPermanentAdmin));
                        context.getResources().getBoolean(R.bool.config_isMainUserPermanentAdmin));
        if (hsumBootUserInitializer != null) {
        if (hsumBootUserInitializer != null) {
            t.traceBegin("HsumBootUserInitializer.init");
            t.traceBegin("HsumBootUserInitializer.init");
@@ -3021,8 +3021,7 @@ public final class SystemServer implements Dumpable {
            mSystemServiceManager.startBootPhase(t, SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
            mSystemServiceManager.startBootPhase(t, SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
            t.traceEnd();
            t.traceEnd();


            if (hsumBootUserInitializer != null && !isAutomotive) {
            if (hsumBootUserInitializer != null) {
                // TODO(b/261924826): remove isAutomotive check once the workflow is finalized
                t.traceBegin("HsumBootUserInitializer.systemRunning");
                t.traceBegin("HsumBootUserInitializer.systemRunning");
                hsumBootUserInitializer.systemRunning(t);
                hsumBootUserInitializer.systemRunning(t);
                t.traceEnd();
                t.traceEnd();
+9 −6
Original line number Original line Diff line number Diff line
@@ -260,7 +260,7 @@ public final class UserManagerServiceTest {
        mUms.setBootUser(OTHER_USER_ID);
        mUms.setBootUser(OTHER_USER_ID);


        assertWithMessage("getBootUser")
        assertWithMessage("getBootUser")
                .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID);
                .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID);
    }
    }


    @Test
    @Test
@@ -273,7 +273,8 @@ public final class UserManagerServiceTest {
        mUms.setBootUser(PROFILE_USER_ID);
        mUms.setBootUser(PROFILE_USER_ID);


        assertWithMessage("getBootUser")
        assertWithMessage("getBootUser")
                .that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM);
                .that(mUmi.getBootUser(/* waitUntilSet= */ false))
                .isEqualTo(UserHandle.USER_SYSTEM);
    }
    }


    @Test
    @Test
@@ -289,7 +290,7 @@ public final class UserManagerServiceTest {


        // Boot user not switchable so return most recently in foreground.
        // Boot user not switchable so return most recently in foreground.
        assertWithMessage("getBootUser")
        assertWithMessage("getBootUser")
                .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID);
                .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID);
    }
    }


    @Test
    @Test
@@ -299,7 +300,8 @@ public final class UserManagerServiceTest {
        addUser(OTHER_USER_ID);
        addUser(OTHER_USER_ID);


        assertWithMessage("getBootUser")
        assertWithMessage("getBootUser")
                .that(mUmi.getBootUser()).isEqualTo(UserHandle.USER_SYSTEM);
                .that(mUmi.getBootUser(/* waitUntilSet= */ false))
                .isEqualTo(UserHandle.USER_SYSTEM);
    }
    }


    @Test
    @Test
@@ -312,14 +314,15 @@ public final class UserManagerServiceTest {
        setLastForegroundTime(OTHER_USER_ID, 2_000_000L);
        setLastForegroundTime(OTHER_USER_ID, 2_000_000L);


        assertWithMessage("getBootUser")
        assertWithMessage("getBootUser")
                .that(mUmi.getBootUser()).isEqualTo(OTHER_USER_ID);
                .that(mUmi.getBootUser(/* waitUntilSet= */ false)).isEqualTo(OTHER_USER_ID);
    }
    }


    @Test
    @Test
    public void testGetBootUser_Headless_ThrowsIfOnlySystemUserExists() throws Exception {
    public void testGetBootUser_Headless_ThrowsIfOnlySystemUserExists() throws Exception {
        setSystemUserHeadless(true);
        setSystemUserHeadless(true);


        assertThrows(UserManager.CheckedUserOperationException.class, () -> mUmi.getBootUser());
        assertThrows(UserManager.CheckedUserOperationException.class,
                () -> mUmi.getBootUser(/* waitUntilSet= */ false));
    }
    }


    private void mockCurrentUser(@UserIdInt int userId) {
    private void mockCurrentUser(@UserIdInt int userId) {