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

Commit a4d54848 authored by Ruslan Tkhakokhov's avatar Ruslan Tkhakokhov Committed by Android (Google) Code Review
Browse files

Merge "[Multi-user] Make AccountSettingsBackupHelper multi-user aware"

parents bb780768 19513033
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -2747,6 +2747,19 @@ public abstract class ContentResolver implements ContentInterface {
        }
    }

    /**
     * @see #setIsSyncable(Account, String, int)
     * @hide
     */
    public static void setIsSyncableAsUser(Account account, String authority, int syncable,
            int userId) {
        try {
            getContentService().setIsSyncableAsUser(account, authority, syncable, userId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Gets the master auto-sync setting that applies to all the providers and accounts.
     * If this is false then the per-provider auto-sync setting is ignored.
+1 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ interface IContentService {
     * @param syncable, >0 denotes syncable, 0 means not syncable, <0 means unknown
     */
    void setIsSyncable(in Account account, String providerName, int syncable);
    void setIsSyncableAsUser(in Account account, String providerName, int syncable, int userId);

    void setMasterSyncAutomatically(boolean flag);
    void setMasterSyncAutomaticallyAsUser(boolean flag, int userId);
+51 −35
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.SyncAdapterType;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.util.Log;

import org.json.JSONArray;
@@ -48,6 +49,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Helper for backing up account sync settings (whether or not a service should be synced). The
@@ -76,15 +78,17 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
    private static final String KEY_AUTHORITY_NAME = "name";
    private static final String KEY_AUTHORITY_SYNC_STATE = "syncState";
    private static final String KEY_AUTHORITY_SYNC_ENABLED = "syncEnabled";
    private static final String STASH_FILE = Environment.getDataDirectory()
            + "/backup/unadded_account_syncsettings.json";
    private static final String STASH_FILE = "/backup/unadded_account_syncsettings.json";

    private Context mContext;
    private AccountManager mAccountManager;
    private final int mUserId;

    public AccountSyncSettingsBackupHelper(Context context) {
    public AccountSyncSettingsBackupHelper(Context context, int userId) {
        mContext = context;
        mAccountManager = AccountManager.get(mContext);

        mUserId = userId;
    }

    /**
@@ -94,7 +98,7 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput output,
            ParcelFileDescriptor newState) {
        try {
            JSONObject dataJSON = serializeAccountSyncSettingsToJSON();
            JSONObject dataJSON = serializeAccountSyncSettingsToJSON(mUserId);

            if (DEBUG) {
                Log.d(TAG, "Account sync settings JSON: " + dataJSON);
@@ -123,10 +127,9 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
    /**
     * Fetch and serialize Account and authority information as a JSON Array.
     */
    private JSONObject serializeAccountSyncSettingsToJSON() throws JSONException {
        Account[] accounts = mAccountManager.getAccounts();
        SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
                mContext.getUserId());
    private JSONObject serializeAccountSyncSettingsToJSON(int userId) throws JSONException {
        Account[] accounts = mAccountManager.getAccountsAsUser(userId);
        SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(userId);

        // Create a map of Account types to authorities. Later this will make it easier for us to
        // generate our JSON.
@@ -146,7 +149,8 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
        // Generate JSON.
        JSONObject backupJSON = new JSONObject();
        backupJSON.put(KEY_VERSION, JSON_FORMAT_VERSION);
        backupJSON.put(KEY_MASTER_SYNC_ENABLED, ContentResolver.getMasterSyncAutomatically());
        backupJSON.put(KEY_MASTER_SYNC_ENABLED, ContentResolver.getMasterSyncAutomaticallyAsUser(
                userId));

        JSONArray accountJSONArray = new JSONArray();
        for (Account account : accounts) {
@@ -165,8 +169,9 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
            // Add authorities for this Account type and check whether or not sync is enabled.
            JSONArray authoritiesJSONArray = new JSONArray();
            for (String authority : authorities) {
                int syncState = ContentResolver.getIsSyncable(account, authority);
                boolean syncEnabled = ContentResolver.getSyncAutomatically(account, authority);
                int syncState = ContentResolver.getIsSyncableAsUser(account, authority, userId);
                boolean syncEnabled = ContentResolver.getSyncAutomaticallyAsUser(account, authority,
                        userId);

                JSONObject authorityJSON = new JSONObject();
                authorityJSON.put(KEY_AUTHORITY_NAME, authority);
@@ -254,17 +259,18 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
            boolean masterSyncEnabled = dataJSON.getBoolean(KEY_MASTER_SYNC_ENABLED);
            JSONArray accountJSONArray = dataJSON.getJSONArray(KEY_ACCOUNTS);

            boolean currentMasterSyncEnabled = ContentResolver.getMasterSyncAutomatically();
            boolean currentMasterSyncEnabled = ContentResolver.getMasterSyncAutomaticallyAsUser(
                    mUserId);
            if (currentMasterSyncEnabled) {
                // Disable master sync to prevent any syncs from running.
                ContentResolver.setMasterSyncAutomatically(false);
                ContentResolver.setMasterSyncAutomaticallyAsUser(false, mUserId);
            }

            try {
                restoreFromJsonArray(accountJSONArray);
                restoreFromJsonArray(accountJSONArray, mUserId);
            } finally {
                // Set the master sync preference to the value from the backup set.
                ContentResolver.setMasterSyncAutomatically(masterSyncEnabled);
                ContentResolver.setMasterSyncAutomaticallyAsUser(masterSyncEnabled, mUserId);
            }
            Log.i(TAG, "Restore successful.");
        } catch (IOException | JSONException e) {
@@ -272,9 +278,9 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
        }
    }

    private void restoreFromJsonArray(JSONArray accountJSONArray)
    private void restoreFromJsonArray(JSONArray accountJSONArray, int userId)
            throws JSONException {
        HashSet<Account> currentAccounts = getAccounts();
        Set<Account> currentAccounts = getAccounts(userId);
        JSONArray unaddedAccountsJSONArray = new JSONArray();
        for (int i = 0; i < accountJSONArray.length(); i++) {
            JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
@@ -292,14 +298,14 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
            // yet won't be restored.
            if (currentAccounts.contains(account)) {
                if (DEBUG) Log.i(TAG, "Restoring Sync Settings for" + accountName);
                restoreExistingAccountSyncSettingsFromJSON(accountJSON);
                restoreExistingAccountSyncSettingsFromJSON(accountJSON, userId);
            } else {
                unaddedAccountsJSONArray.put(accountJSON);
            }
        }

        if (unaddedAccountsJSONArray.length() > 0) {
            try (FileOutputStream fOutput = new FileOutputStream(STASH_FILE)) {
            try (FileOutputStream fOutput = new FileOutputStream(getStashFile(userId))) {
                String jsonString = unaddedAccountsJSONArray.toString();
                DataOutputStream out = new DataOutputStream(fOutput);
                out.writeUTF(jsonString);
@@ -308,18 +314,20 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
                Log.e(TAG, "unable to write the sync settings to the stash file", ioe);
            }
        } else {
            File stashFile = new File(STASH_FILE);
            if (stashFile.exists()) stashFile.delete();
            File stashFile = getStashFile(userId);
            if (stashFile.exists()) {
                stashFile.delete();
            }
        }
    }

    /**
     * Restore SyncSettings for all existing accounts from a stashed backup-set
     */
    private void accountAddedInternal() {
    private void accountAddedInternal(int userId) {
        String jsonString;

        try (FileInputStream fIn = new FileInputStream(new File(STASH_FILE))) {
        try (FileInputStream fIn = new FileInputStream(getStashFile(userId))) {
            DataInputStream in = new DataInputStream(fIn);
            jsonString = in.readUTF();
        } catch (FileNotFoundException fnfe) {
@@ -333,7 +341,7 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {

        try {
            JSONArray unaddedAccountsJSONArray = new JSONArray(jsonString);
            restoreFromJsonArray(unaddedAccountsJSONArray);
            restoreFromJsonArray(unaddedAccountsJSONArray, userId);
        } catch (JSONException jse) {
            // Malformed jsonString
            Log.e(TAG, "there was an error with the stashed sync settings", jse);
@@ -343,9 +351,10 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
    /**
     * Restore SyncSettings for all existing accounts from a stashed backup-set
     */
    public static void accountAdded(Context context) {
        AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context);
        helper.accountAddedInternal();
    public static void accountAdded(Context context, int userId) {
        AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context,
                userId);
        helper.accountAddedInternal(userId);
    }

    /**
@@ -353,9 +362,9 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
     *
     * @return Accounts in a HashSet.
     */
    private HashSet<Account> getAccounts() {
        Account[] accounts = mAccountManager.getAccounts();
        HashSet<Account> accountHashSet = new HashSet<Account>();
    private Set<Account> getAccounts(int userId) {
        Account[] accounts = mAccountManager.getAccountsAsUser(userId);
        Set<Account> accountHashSet = new HashSet<Account>();
        for (Account account : accounts) {
            accountHashSet.add(account);
        }
@@ -391,7 +400,7 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
     * initialization sync, while an adapter that the user had off will be off until the user
     * enables it on this device at which point it will get an initialization sync.
     */
    private void restoreExistingAccountSyncSettingsFromJSON(JSONObject accountJSON)
    private void restoreExistingAccountSyncSettingsFromJSON(JSONObject accountJSON, int userId)
            throws JSONException {
        // Restore authorities.
        JSONArray authorities = accountJSON.getJSONArray(KEY_ACCOUNT_AUTHORITIES);
@@ -406,14 +415,15 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
            int wasSyncable = authority.getInt(KEY_AUTHORITY_SYNC_STATE);

            ContentResolver.setSyncAutomaticallyAsUser(
                    account, authorityName, wasSyncEnabled, 0 /* user Id */);
                    account, authorityName, wasSyncEnabled, userId);

            if (!wasSyncEnabled) {
                ContentResolver.setIsSyncable(
                ContentResolver.setIsSyncableAsUser(
                        account,
                        authorityName,
                        wasSyncable == 0 ?
                                0 /* not syncable */ : 2 /* syncable but needs initialization */);
                                0 /* not syncable */ : 2 /* syncable but needs initialization */,
                        userId);
            }
        }
    }
@@ -422,4 +432,10 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
    public void writeNewStateDescription(ParcelFileDescriptor newState) {

    }

    private static File getStashFile(int userId) {
        File baseDir = userId == UserHandle.USER_SYSTEM ? Environment.getDataDirectory()
                : Environment.getDataSystemCeDirectory(userId);
        return new File(baseDir, STASH_FILE);
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
    private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;

    private static final Set<String> sEligibleForMultiUser = Sets.newArraySet(
            PERMISSION_HELPER, NOTIFICATION_HELPER);
            PERMISSION_HELPER, NOTIFICATION_HELPER, SYNC_SETTINGS_HELPER);

    private int mUserId = UserHandle.USER_SYSTEM;

@@ -91,7 +91,7 @@ public class SystemBackupAgent extends BackupAgentHelper {

        mUserId = user.getIdentifier();

        addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
        addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this, mUserId));
        addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
        addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(mUserId));
        addHelper(PERMISSION_HELPER, new PermissionBackupHelper(mUserId));
+11 −1
Original line number Diff line number Diff line
@@ -899,9 +899,20 @@ public final class ContentService extends IContentService.Stub {

    @Override
    public void setIsSyncable(Account account, String providerName, int syncable) {
        setIsSyncableAsUser(account, providerName, syncable, UserHandle.getCallingUserId());
    }

    /**
     * @hide
     */
    @Override
    public void setIsSyncableAsUser(Account account, String providerName, int syncable,
            int userId) {
        if (TextUtils.isEmpty(providerName)) {
            throw new IllegalArgumentException("Authority must not be empty");
        }
        enforceCrossUserPermission(userId,
                "no permission to set the sync settings for user " + userId);
        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                "no permission to write the sync settings");

@@ -909,7 +920,6 @@ public final class ContentService extends IContentService.Stub {
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();

        int userId = UserHandle.getCallingUserId();
        long identityToken = clearCallingIdentity();
        try {
            SyncManager syncManager = getSyncManager();
Loading