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

Commit 99f75188 authored by Muhammad Hasan Khan's avatar Muhammad Hasan Khan
Browse files

arc: Restrict only removal of first account

For upstreaming the change, it is important that we do not restrict
renaming of the account as it is going to become an official feature of
GAIA accounts where accounts can be renamed.

We don't need to restrict rename anyway since it is not possible to
rename an account from the UI. The change originally was intended to
prevent removal from the settings app thus rename isn't as critical to
the implementation.

In this change we're renaming the config used to restrict the removal to
only be limited to remove.

See b/26267455 for additional context.

Bug: 301629223
Test: From the settings app attempt to remove the account. Verify it is
disabled.

Change-Id: If8def9e6bc1be39616ff9fa3d861d92997e800d8
(cherry picked from commit 30cc36f8a4df8e5489222346155de7c8472d0ed7)
parent 0bab1185
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
@@ -4369,6 +4369,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
@@ -1721,6 +1721,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();