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

Commit 386f5f2c authored by Anna Bauza's avatar Anna Bauza Committed by Automerger Merge Worker
Browse files

Merge "Add Android Multiuser Atom which will contain number of supported...

Merge "Add Android Multiuser Atom which will contain number of supported users." into tm-qpr-dev am: 661265f4

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19715873



Change-Id: I408738843e8700293d77dd1d41a415e98581b1b8
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 491c08b6 661265f4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ interface IUserManager {
    String getUserAccount(int userId);
    void setUserAccount(int userId, String accountName);
    long getUserCreationTime(int userId);
    boolean isUserSwitcherEnabled(int mUserId);
    boolean isRestricted(int userId);
    boolean canHaveRestrictedProfile(int userId);
    int getUserSerialNumber(int userId);
+7 −17
Original line number Diff line number Diff line
@@ -5132,23 +5132,13 @@ public class UserManager {
    })
    @UserHandleAware
    public boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable) {
        if (!supportsMultipleUsers()) {
            return false;
        }
        if (hasUserRestrictionForUser(DISALLOW_USER_SWITCH, mUserId)) {
            return false;
        }
        // If Demo Mode is on, don't show user switcher
        if (isDeviceInDemoMode(mContext)) {

        try {
            if (!mService.isUserSwitcherEnabled(mUserId)) {
                return false;
            }
        // Check the Settings.Global.USER_SWITCHER_ENABLED that the user can toggle on/off.
        final boolean userSwitcherSettingOn = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.USER_SWITCHER_ENABLED,
                Resources.getSystem().getBoolean(R.bool.config_showUserSwitcherByDefault) ? 1 : 0)
                != 0;
        if (!userSwitcherSettingOn) {
            return false;
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }

        // The feature is enabled. But is it worth showing?
+60 −32
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.pm;

import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.UserManager.DISALLOW_USER_SWITCH;

import android.Manifest;
import android.accounts.Account;
@@ -1762,6 +1763,19 @@ public class UserManagerService extends IUserManager.Stub {
        }
    }

    @Override
    public boolean isUserSwitcherEnabled(@UserIdInt int mUserId) {
        boolean multiUserSettingOn = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.USER_SWITCHER_ENABLED,
                Resources.getSystem().getBoolean(com.android.internal
                        .R.bool.config_showUserSwitcherByDefault) ? 1 : 0) != 0;

        return UserManager.supportsMultipleUsers()
                && !hasUserRestriction(DISALLOW_USER_SWITCH, mUserId)
                && !UserManager.isDeviceInDemoMode(mContext)
                && multiUserSettingOn;
    }

    @Override
    public boolean isRestricted(@UserIdInt int userId) {
        if (userId != UserHandle.getCallingUserId()) {
@@ -2052,7 +2066,6 @@ public class UserManagerService extends IUserManager.Stub {
                    originatingUserId, local);
            localChanged = updateLocalRestrictionsForTargetUsersLR(originatingUserId, local,
                    updatedLocalTargetUserIds);

            if (isDeviceOwner) {
                // Remember the global restriction owner userId to be able to make a distinction
                // in getUserRestrictionSource on who set local policies.
@@ -4435,27 +4448,25 @@ public class UserManagerService extends IUserManager.Stub {
                null, // use default PullAtomMetadata values
                BackgroundThread.getExecutor(),
                this::onPullAtom);
        statsManager.setPullAtomCallback(
                FrameworkStatsLog.MULTI_USER_INFO,
                null, // use default PullAtomMetadata values
                BackgroundThread.getExecutor(),
                this::onPullAtom);
    }

    /** Writes a UserInfo pulled atom for each user on the device. */
    private int onPullAtom(int atomTag, List<StatsEvent> data) {
        if (atomTag != FrameworkStatsLog.USER_INFO) {
            Slogf.e(LOG_TAG, "Unexpected atom tag: %d", atomTag);
            return android.app.StatsManager.PULL_SKIP;
        }
        if (atomTag == FrameworkStatsLog.USER_INFO) {
            final List<UserInfo> users = getUsersInternal(true, true, true);
            final int size = users.size();
            if (size > 1) {
                for (int idx = 0; idx < size; idx++) {
                    final UserInfo user = users.get(idx);
            if (user.id == UserHandle.USER_SYSTEM) {
                // Skip user 0. It's not interesting. We already know it exists, is running, and (if
                // we know the device configuration) its userType.
                continue;
            }

                    final int userTypeStandard = UserManager.getUserTypeForStatsd(user.userType);
            final String userTypeCustom = (userTypeStandard ==
                    FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN) ?
                    final String userTypeCustom = (userTypeStandard == FrameworkStatsLog
                            .USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN)
                            ?
                            user.userType : null;

                    boolean isUserRunningUnlocked;
@@ -4474,6 +4485,23 @@ public class UserManagerService extends IUserManager.Stub {
                            isUserRunningUnlocked
                    ));
                }
            }
        } else if (atomTag == FrameworkStatsLog.MULTI_USER_INFO) {
            if (UserManager.getMaxSupportedUsers() > 1) {
                int deviceOwnerUserId = UserHandle.USER_NULL;

                synchronized (mRestrictionsLock) {
                    deviceOwnerUserId = mDeviceOwnerUserId;
                }

                data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.MULTI_USER_INFO,
                        UserManager.getMaxSupportedUsers(),
                        isUserSwitcherEnabled(deviceOwnerUserId)));
            }
        } else {
            Slogf.e(LOG_TAG, "Unexpected atom tag: %d", atomTag);
            return android.app.StatsManager.PULL_SKIP;
        }
        return android.app.StatsManager.PULL_SUCCESS;
    }

+170 −29
Original line number Diff line number Diff line
@@ -16,53 +16,79 @@

package com.android.server.pm;

import static android.os.UserManager.DISALLOW_USER_SWITCH;

import static com.google.common.truth.Truth.assertThat;

import android.app.ActivityManager;
import android.app.PropertyInvalidatedCache;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.Looper;
import android.os.Parcelable;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Postsubmit;
import android.support.test.uiautomator.UiDevice;
import android.test.AndroidTestCase;
import android.text.TextUtils;
import android.util.AtomicFile;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.server.LocalServices;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

/** Test {@link UserManagerService} functionality. */
@Postsubmit
@SmallTest
public class UserManagerServiceTest extends AndroidTestCase {
@RunWith(AndroidJUnit4.class)
public class UserManagerServiceTest {
    private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
    private File restrictionsFile;
    private int tempUserId = UserHandle.USER_NULL;
    private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
    private UserManagerService mUserManagerService;

    @Before
    public void setup() throws Exception {
        // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup
        // TODO: Remove once UMS supports proper dependency injection
        if (Looper.myLooper() == null) {
            Looper.prepare();
        }
        // Disable binder caches in this process.
        PropertyInvalidatedCache.disableForTestMode();

        LocalServices.removeServiceForTest(UserManagerInternal.class);
        mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext());

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        restrictionsFile = new File(mContext.getCacheDir(), "restrictions.xml");
        restrictionsFile.delete();
    }

    @Override
    protected void tearDown() throws Exception {
    @After
    public void teardown() throws Exception {
        restrictionsFile.delete();
        if (tempUserId != UserHandle.USER_NULL) {
            UserManager.get(mContext).removeUser(tempUserId);
        }
        super.tearDown();
    }

    @Test
    public void testWriteReadApplicationRestrictions() throws IOException {
        AtomicFile atomicFile = new AtomicFile(restrictionsFile);
        Bundle bundle = createBundle();
        UserManagerService.writeApplicationRestrictionsLAr(bundle, atomicFile);
        assertTrue(atomicFile.getBaseFile().exists());
        assertThat(atomicFile.getBaseFile().exists()).isTrue();
        String s = FileUtils.readTextFile(restrictionsFile, 10000, "");
        System.out.println("restrictionsFile: " + s);
        bundle = UserManagerService.readApplicationRestrictionsLAr(atomicFile);
@@ -70,22 +96,22 @@ public class UserManagerServiceTest extends AndroidTestCase {
        assertBundle(bundle);
    }

    @Test
    public void testAddUserWithAccount() {
        UserManager um = UserManager.get(mContext);
        UserInfo user = um.createUser("Test User", 0);
        assertNotNull(user);
        assertThat(user).isNotNull();
        tempUserId = user.id;
        String accountName = "Test Account";
        um.setUserAccount(tempUserId, accountName);
        assertEquals(accountName, um.getUserAccount(tempUserId));
        assertThat(um.getUserAccount(tempUserId)).isEqualTo(accountName);
    }

    @Test
    public void testUserSystemPackageWhitelist() throws Exception {
        String cmd = "cmd user report-system-user-package-whitelist-problems --critical-only";
        final String result = runShellCommand(cmd);
        if (!TextUtils.isEmpty(result)) {
            fail("Command '" + cmd + " reported errors:\n" + result);
        }
        assertThat(result).isEmpty();
    }

    private Bundle createBundle() {
@@ -114,26 +140,141 @@ public class UserManagerServiceTest extends AndroidTestCase {
    }

    private void assertBundle(Bundle bundle) {
        assertFalse(bundle.getBoolean("boolean_0"));
        assertTrue(bundle.getBoolean("boolean_1"));
        assertEquals(100, bundle.getInt("integer"));
        assertEquals("", bundle.getString("empty"));
        assertEquals("text", bundle.getString("string"));
        assertEquals(Arrays.asList(STRING_ARRAY), Arrays.asList(bundle.getStringArray("string[]")));
        assertThat(bundle.getBoolean("boolean_0")).isFalse();
        assertThat(bundle.getBoolean("boolean_1")).isTrue();
        assertThat(bundle.getInt("integer")).isEqualTo(100);
        assertThat(bundle.getString("empty")).isEqualTo("");
        assertThat(bundle.getString("string")).isEqualTo("text");
        assertThat(Arrays.asList(bundle.getStringArray("string[]")))
                .isEqualTo(Arrays.asList(STRING_ARRAY));
        Parcelable[] bundle_array = bundle.getParcelableArray("bundle_array");
        assertEquals(2, bundle_array.length);
        assertThat(bundle_array.length).isEqualTo(2);
        Bundle bundle1 = (Bundle) bundle_array[0];
        assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
        assertNotNull(bundle1.getBundle("bundle_array_bundle"));
        assertThat(bundle1.getString("bundle_array_string"))
                .isEqualTo("bundle_array_string");
        assertThat(bundle1.getBundle("bundle_array_bundle")).isNotNull();
        Bundle bundle2 = (Bundle) bundle_array[1];
        assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
        assertThat(bundle2.getString("bundle_array_string2"))
                .isEqualTo("bundle_array_string2");
        Bundle childBundle = bundle.getBundle("bundle");
        assertEquals("bundle_string", childBundle.getString("bundle_string"));
        assertEquals(1, childBundle.getInt("bundle_int"));
        assertThat(childBundle.getString("bundle_string"))
                .isEqualTo("bundle_string");
        assertThat(childBundle.getInt("bundle_int")).isEqualTo(1);
    }

    @Test
    public void assertHasUserRestriction() throws Exception {
        int userId = ActivityManager.getCurrentUser();

        mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, true, userId);
        assertThat(mUserManagerService.hasUserRestriction(DISALLOW_USER_SWITCH, userId)).isTrue();

        mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId);
        assertThat(mUserManagerService.hasUserRestriction(DISALLOW_USER_SWITCH, userId)).isFalse();
    }

    @Test
    public void assertIsUserSwitcherEnabledOnMultiUserSettings() throws Exception {
        int userId = ActivityManager.getCurrentUser();
        resetUserSwitcherEnabled();

        setUserSwitch(false);
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();

        setUserSwitch(true);
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
    }

    @Test
    public void assertIsUserSwitcherEnabledOnMaxSupportedUsers()  throws Exception {
        int userId = ActivityManager.getCurrentUser();
        setMaxSupportedUsers(1);

        assertThat(UserManager.supportsMultipleUsers()).isFalse();
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();

        setMaxSupportedUsers(8);

        assertThat(UserManager.supportsMultipleUsers()).isTrue();
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
    }


    @Test
    public void assertIsUserSwitcherEnabledOnShowMultiuserUI()  throws Exception {
        int userId = ActivityManager.getCurrentUser();
        setShowMultiuserUI(false);

        assertThat(UserManager.supportsMultipleUsers()).isFalse();
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();

        setShowMultiuserUI(true);

        assertThat(UserManager.supportsMultipleUsers()).isTrue();
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
    }

    @Test
    public void assertIsUserSwitcherEnabledOnUserRestrictions() throws Exception {
        int userId = ActivityManager.getCurrentUser();
        resetUserSwitcherEnabled();

        mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, true, userId);
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();

        mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId);
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
    }

    @Test
    public void assertIsUserSwitcherEnabledOnDemoMode()  throws Exception {
        int userId = ActivityManager.getCurrentUser();
        resetUserSwitcherEnabled();

        setDeviceDemoMode(true);
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isFalse();

        setDeviceDemoMode(false);
        assertThat(mUserManagerService.isUserSwitcherEnabled(userId)).isTrue();
    }

    private void resetUserSwitcherEnabled() throws Exception {
        int userId = ActivityManager.getCurrentUser();
        setUserSwitch(true);
        setShowMultiuserUI(true);
        setDeviceDemoMode(false);
        setMaxSupportedUsers(8);
        mUserManagerService.setUserRestriction(DISALLOW_USER_SWITCH, false, userId);
    }

    private void setUserSwitch(boolean enabled) {
        android.provider.Settings.Global.putInt(mContext.getContentResolver(),
                android.provider.Settings.Global.USER_SWITCHER_ENABLED, enabled ? 1 : 0);
    }

    private void setDeviceDemoMode(boolean enabled) {
        android.provider.Settings.Global.putInt(mContext.getContentResolver(),
                android.provider.Settings.Global.DEVICE_DEMO_MODE, enabled ? 1 : 0);
    }


    private static String runShellCommand(String cmd) throws Exception {
        return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
                .executeShellCommand(cmd);
    }

    private static String setSystemProperty(String name, String value) throws Exception {
        final String oldValue = runShellCommand("getprop " + name);
        assertThat(runShellCommand("setprop " + name + " " + value))
                .isEqualTo("");
        return oldValue;
    }

    private static void setMaxSupportedUsers(int max) throws Exception {
        setSystemProperty("fw.max_users", String.valueOf(max));
    }

    public static void setShowMultiuserUI(boolean show) throws Exception {
        setSystemProperty("fw.show_multiuserui", String.valueOf(show));
    }
}