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

Commit 747174d5 authored by Muhammad Hasan Khan's avatar Muhammad Hasan Khan Committed by Android (Google) Code Review
Browse files

Merge "arc: Restrict only removal of first account" into main

parents f3c86086 99f75188
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -10308,6 +10308,13 @@ public final class Settings {
        @Readable
        public static final String SHOW_NOTIFICATION_SNOOZE = "show_notification_snooze";
       /**
         * 1 if it is allowed to remove the primary GAIA account. 0 by default.
         * @hide
         */
        public static final String ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS =
                "allow_primary_gaia_account_removal_for_tests";
        /**
         * List of TV inputs that are currently hidden. This is a string
         * containing the IDs of all hidden TV inputs. Each ID is encoded by
+9 −0
Original line number Diff line number Diff line
@@ -4372,6 +4372,15 @@
         UI is handled by ActivityManagerService -->
    <bool name="config_customUserSwitchUi">false</bool>

    <!-- Flag specifying whether the first account added can be removed or renamed. By default,
    this ability is enabled. When false, user will not be able to remove the first account. -->
    <bool name="config_canRemoveFirstAccount">true</bool>

    <!-- Used together with config_canRemoveOrRenameFirstAccount when set to false. By default, this
    is blank. Check if the first account is of this account type. If it is, then disable
    remove/rename. -->
    <string name="config_accountTypeToKeepFirstAccount"></string>

    <!-- A array of regex to treat a SMS as VVM SMS if the message body matches.
         Each item represents an entry, which consists of two parts:
         a comma (,) separated list of MCCMNC the regex applies to, followed by a semicolon (;), and
+2 −0
Original line number Diff line number Diff line
@@ -1723,6 +1723,8 @@
  <java-symbol type="bool" name="config_startDreamImmediatelyOnDock" />
  <java-symbol type="bool" name="config_carDockEnablesAccelerometer" />
  <java-symbol type="bool" name="config_customUserSwitchUi" />
  <java-symbol type="bool" name="config_canRemoveFirstAccount" />
  <java-symbol type="string" name="config_accountTypeToKeepFirstAccount" />
  <java-symbol type="bool" name="config_deskDockEnablesAccelerometer" />
  <java-symbol type="bool" name="config_disableMenuKeyInLockScreen" />
  <java-symbol type="bool" name="config_enableCarDockHomeLaunch" />
+1 −0
Original line number Diff line number Diff line
@@ -691,6 +691,7 @@ public class SettingsBackupTest {
             newHashSet(
                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
                 Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, // Deprecated since O.
                 Settings.Secure.ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS,
                 Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
                 Settings.Secure.ALWAYS_ON_VPN_APP,
                 Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
+59 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ import android.os.StrictMode;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.stats.devicepolicy.DevicePolicyEnums;
import android.text.TextUtils;
import android.util.EventLog;
@@ -2346,6 +2347,18 @@ public class AccountManagerService
            }
            return;
        }
        if (isFirstAccountRemovalDisabled(account)) {
            try {
                response.onError(
                        AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
                        "User cannot remove the first "
                                + account.type
                                + " account on the device.");
            } catch (RemoteException re) {
                Log.w(TAG, "RemoteException while removing account", re);
            }
            return;
        }
        final long identityToken = clearCallingIdentity();
        UserAccounts accounts = getUserAccounts(userId);
        cancelNotification(getSigninRequiredNotificationId(accounts, account), accounts);
@@ -2395,6 +2408,10 @@ public class AccountManagerService
                    account.type);
            throw new SecurityException(msg);
        }
        if (isFirstAccountRemovalDisabled(account)) {
            Log.e(TAG, "Cannot remove the first " + account.type + " account on the device.");
            return false;
        }
        UserAccounts accounts = getUserAccountsForCaller();
        final long accountId = accounts.accountsDb.findDeAccountId(account);
        logRecord(
@@ -6426,6 +6443,48 @@ public class AccountManagerService
        }
    }

    /**
     * Returns true if the config_canRemoveOrRenameFirstUser is false, and the given account type
     * matches the one provided by config_accountTypeToKeepFirstUser.
     */
    private boolean isFirstAccountRemovalDisabled(Account account) {
        // Skip if not targeting the first user.
        int userId = UserHandle.getCallingUserId();
        if (userId != 0) {
            return false;
        }

        // Skip if we are allowed to remove/rename first account.
        if (mContext.getResources()
                .getBoolean(com.android.internal.R.bool.config_canRemoveFirstAccount)) {
            return false;
        }

        // Skip if needed for testing.
        if (Settings.Secure.getIntForUser(
                mContext.getContentResolver(),
                Settings.Secure.ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS,
                0 /* default */,
                0 /* userHandle */) != 0) {
            return false;
        }

        // Skip if not targeting desired account.
        String typeToKeep =
                mContext.getResources()
                        .getString(
                                com.android.internal.R.string.config_accountTypeToKeepFirstAccount);
        if (typeToKeep.isEmpty() || !typeToKeep.equals(account.type)) {
            return false;
        }

        // Only restrict first account.
        UserAccounts accounts = getUserAccounts(0 /* userId */);
        Account[] accountsOfType = getAccountsFromCache(accounts, typeToKeep,
                Process.SYSTEM_UID, "android" /* packageName */, false);
        return accountsOfType.length > 0 && accountsOfType[0].equals(account);
    }

    private final class AccountManagerInternalImpl extends AccountManagerInternal {
        private final Object mLock = new Object();