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

This commit is contained in:
Ruslan Tkhakokhov
2019-02-06 17:21:12 +00:00
committed by Android (Google) Code Review
6 changed files with 79 additions and 39 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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));

View File

@@ -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();

View File

@@ -3261,7 +3261,7 @@ public class SyncManager {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
}
AccountSyncSettingsBackupHelper.accountAdded(mContext);
AccountSyncSettingsBackupHelper.accountAdded(mContext, syncTargets.userId);
break;
}
}