Merge "Stashing SyncSettings for accounts added aft SUW" into nyc-dev
This commit is contained in:
@@ -16,10 +16,6 @@
|
||||
|
||||
package com.android.server.backup;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.backup.BackupDataInputStream;
|
||||
@@ -28,14 +24,21 @@ import android.app.backup.BackupHelper;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SyncAdapterType;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
@@ -73,6 +76,8 @@ 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 Context mContext;
|
||||
private AccountManager mAccountManager;
|
||||
@@ -256,41 +261,99 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
|
||||
}
|
||||
|
||||
try {
|
||||
HashSet<Account> currentAccounts = getAccountsHashSet();
|
||||
for (int i = 0; i < accountJSONArray.length(); i++) {
|
||||
JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
|
||||
String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
|
||||
String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
|
||||
|
||||
Account account = new Account(accountName, accountType);
|
||||
|
||||
// Check if the account already exists. Accounts that don't exist on the device
|
||||
// yet won't be restored.
|
||||
if (currentAccounts.contains(account)) {
|
||||
restoreExistingAccountSyncSettingsFromJSON(accountJSON);
|
||||
} else {
|
||||
// TODO:
|
||||
// Stash the data to a file that the SyncManager can read from to restore
|
||||
// settings at a later date.
|
||||
}
|
||||
}
|
||||
restoreFromJsonArray(accountJSONArray);
|
||||
} finally {
|
||||
// Set the master sync preference to the value from the backup set.
|
||||
ContentResolver.setMasterSyncAutomatically(masterSyncEnabled);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Restore successful.");
|
||||
} catch (IOException | JSONException e) {
|
||||
Log.e(TAG, "Couldn't restore account sync settings\n" + e);
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreFromJsonArray(JSONArray accountJSONArray)
|
||||
throws JSONException {
|
||||
HashSet<Account> currentAccounts = getAccounts();
|
||||
JSONArray unaddedAccountsJSONArray = new JSONArray();
|
||||
for (int i = 0; i < accountJSONArray.length(); i++) {
|
||||
JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
|
||||
String accountName = accountJSON.getString(KEY_ACCOUNT_NAME);
|
||||
String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE);
|
||||
|
||||
Account account = null;
|
||||
try {
|
||||
account = new Account(accountName, accountType);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the account already exists. Accounts that don't exist on the device
|
||||
// yet won't be restored.
|
||||
if (currentAccounts.contains(account)) {
|
||||
if (DEBUG) Log.i(TAG, "Restoring Sync Settings for" + accountName);
|
||||
restoreExistingAccountSyncSettingsFromJSON(accountJSON);
|
||||
} else {
|
||||
unaddedAccountsJSONArray.put(accountJSON);
|
||||
}
|
||||
}
|
||||
|
||||
if (unaddedAccountsJSONArray.length() > 0) {
|
||||
try (FileOutputStream fOutput = new FileOutputStream(STASH_FILE)) {
|
||||
String jsonString = unaddedAccountsJSONArray.toString();
|
||||
DataOutputStream out = new DataOutputStream(fOutput);
|
||||
out.writeUTF(jsonString);
|
||||
} catch (IOException ioe) {
|
||||
// Error in writing to stash file
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore SyncSettings for all existing accounts from a stashed backup-set
|
||||
*/
|
||||
private void accountAddedInternal() {
|
||||
String jsonString;
|
||||
|
||||
try (FileInputStream fIn = new FileInputStream(new File(STASH_FILE))) {
|
||||
DataInputStream in = new DataInputStream(fIn);
|
||||
jsonString = in.readUTF();
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
// This is expected to happen when there is no accounts info stashed
|
||||
if (DEBUG) Log.d(TAG, "unable to find the stash file", fnfe);
|
||||
return;
|
||||
} catch (IOException ioe) {
|
||||
if (DEBUG) Log.d(TAG, "could not read sync settings from stash file", ioe);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONArray unaddedAccountsJSONArray = new JSONArray(jsonString);
|
||||
restoreFromJsonArray(unaddedAccountsJSONArray);
|
||||
} catch (JSONException jse) {
|
||||
// Malformed jsonString
|
||||
Log.e(TAG, "there was an error with the stashed sync settings", jse);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore SyncSettings for all existing accounts from a stashed backup-set
|
||||
*/
|
||||
public static void accountAdded(Context context) {
|
||||
AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context);
|
||||
helper.accountAddedInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method - fetch accounts and return them as a HashSet.
|
||||
*
|
||||
* @return Accounts in a HashSet.
|
||||
*/
|
||||
private HashSet<Account> getAccountsHashSet() {
|
||||
private HashSet<Account> getAccounts() {
|
||||
Account[] accounts = mAccountManager.getAccounts();
|
||||
HashSet<Account> accountHashSet = new HashSet<Account>();
|
||||
for (Account account : accounts) {
|
||||
@@ -359,4 +422,4 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper {
|
||||
public void writeNewStateDescription(ParcelFileDescriptor newState) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
@@ -70,41 +71,42 @@ import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.WorkSource;
|
||||
import android.os.Messenger;
|
||||
import android.provider.Settings;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.format.Time;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.Pair;
|
||||
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
import com.google.android.collect.Maps;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.accounts.AccountManagerService;
|
||||
import com.android.server.backup.AccountSyncSettingsBackupHelper;
|
||||
import com.android.server.content.SyncStorageEngine.AuthorityInfo;
|
||||
import com.android.server.content.SyncStorageEngine.EndPoint;
|
||||
import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
|
||||
import com.google.android.collect.Lists;
|
||||
import com.google.android.collect.Maps;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Implementation details:
|
||||
@@ -510,12 +512,12 @@ public class SyncManager {
|
||||
|
||||
mSyncStorageEngine.setPeriodicSyncAddedListener(
|
||||
new SyncStorageEngine.PeriodicSyncAddedListener() {
|
||||
@Override
|
||||
public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
|
||||
long flex) {
|
||||
updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
|
||||
long flex) {
|
||||
updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
|
||||
}
|
||||
});
|
||||
|
||||
mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
|
||||
@Override
|
||||
@@ -750,8 +752,8 @@ public class SyncManager {
|
||||
* @param onlyThoseWithUnkownSyncableState Only sync authorities that have unknown state.
|
||||
*/
|
||||
public void scheduleSync(Account requestedAccount, int userId, int reason,
|
||||
String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
|
||||
long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
|
||||
String requestedAuthority, Bundle extras, long beforeRuntimeMillis,
|
||||
long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
|
||||
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
if (extras == null) {
|
||||
extras = new Bundle();
|
||||
@@ -941,7 +943,7 @@ public class SyncManager {
|
||||
* flexMillis will be updated.
|
||||
*/
|
||||
public void updateOrAddPeriodicSync(EndPoint target, long pollFrequency, long flex,
|
||||
Bundle extras) {
|
||||
Bundle extras) {
|
||||
UpdatePeriodicSyncMessagePayload payload = new UpdatePeriodicSyncMessagePayload(target,
|
||||
pollFrequency, flex, extras);
|
||||
mSyncHandler.obtainMessage(SyncHandler.MESSAGE_UPDATE_PERIODIC_SYNC, payload)
|
||||
@@ -995,7 +997,7 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
|
||||
SyncResult syncResult) {
|
||||
SyncResult syncResult) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
|
||||
Message msg = mSyncHandler.obtainMessage();
|
||||
msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
|
||||
@@ -1053,7 +1055,7 @@ public class SyncManager {
|
||||
public final SyncResult syncResult;
|
||||
|
||||
SyncFinishedOrCancelledMessagePayload(ActiveSyncContext syncContext,
|
||||
SyncResult syncResult) {
|
||||
SyncResult syncResult) {
|
||||
this.activeSyncContext = syncContext;
|
||||
this.syncResult = syncResult;
|
||||
}
|
||||
@@ -1066,7 +1068,7 @@ public class SyncManager {
|
||||
public final Bundle extras;
|
||||
|
||||
UpdatePeriodicSyncMessagePayload(EndPoint target, long pollFrequency, long flex,
|
||||
Bundle extras) {
|
||||
Bundle extras) {
|
||||
this.target = target;
|
||||
this.pollFrequency = pollFrequency;
|
||||
this.flex = flex;
|
||||
@@ -1297,7 +1299,7 @@ public class SyncManager {
|
||||
JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
|
||||
|
||||
JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
|
||||
new ComponentName(mContext, SyncJobService.class))
|
||||
new ComponentName(mContext, SyncJobService.class))
|
||||
.setExtras(syncOperation.toJobInfoExtras())
|
||||
.setRequiredNetworkType(networkType)
|
||||
.setPersisted(true)
|
||||
@@ -1502,7 +1504,7 @@ public class SyncManager {
|
||||
* for this sync. This is used to attribute the wakelock hold to that application.
|
||||
*/
|
||||
public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
|
||||
int syncAdapterUid) {
|
||||
int syncAdapterUid) {
|
||||
super();
|
||||
mSyncAdapterUid = syncAdapterUid;
|
||||
mSyncOperation = syncOperation;
|
||||
@@ -1731,7 +1733,7 @@ public class SyncManager {
|
||||
new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
|
||||
@Override
|
||||
public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
|
||||
RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
|
||||
RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
|
||||
return lhs.type.authority.compareTo(rhs.type.authority);
|
||||
}
|
||||
});
|
||||
@@ -2572,6 +2574,7 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
private void updateRunningAccountsH(EndPoint syncTargets) {
|
||||
AccountAndUser[] oldAccounts = mRunningAccounts;
|
||||
mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Slog.v(TAG, "Accounts list: ");
|
||||
@@ -2595,6 +2598,17 @@ public class SyncManager {
|
||||
}
|
||||
}
|
||||
|
||||
// On account add, check if there are any settings to be restored.
|
||||
for (AccountAndUser aau : mRunningAccounts) {
|
||||
if (!containsAccountAndUser(oldAccounts, aau.account, aau.userId)) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
|
||||
}
|
||||
AccountSyncSettingsBackupHelper.accountAdded(mContext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<SyncOperation> ops = getAllPendingSyncsFromCache();
|
||||
for (SyncOperation op: ops) {
|
||||
if (!containsAccountAndUser(accounts, op.target.account, op.target.userId)) {
|
||||
@@ -2618,7 +2632,7 @@ public class SyncManager {
|
||||
* @param flexMillis new flex time in milliseconds.
|
||||
*/
|
||||
private void maybeUpdateSyncPeriodH(SyncOperation syncOperation, long pollFrequencyMillis,
|
||||
long flexMillis) {
|
||||
long flexMillis) {
|
||||
if (!(pollFrequencyMillis == syncOperation.periodMillis
|
||||
&& flexMillis == syncOperation.flexMillis)) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
@@ -2633,7 +2647,7 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
private void updateOrAddPeriodicSyncH(EndPoint target, long pollFrequency, long flex,
|
||||
Bundle extras) {
|
||||
Bundle extras) {
|
||||
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
verifyJobScheduler(); // Will fill in mScheduledSyncs cache if it is not already filled.
|
||||
final long pollFrequencyMillis = pollFrequency * 1000L;
|
||||
@@ -2821,7 +2835,7 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext,
|
||||
IBinder syncAdapter) {
|
||||
IBinder syncAdapter) {
|
||||
final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
|
||||
try {
|
||||
activeSyncContext.mIsLinkedToDeath = true;
|
||||
@@ -2889,7 +2903,7 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
private void runSyncFinishedOrCanceledH(SyncResult syncResult,
|
||||
ActiveSyncContext activeSyncContext) {
|
||||
ActiveSyncContext activeSyncContext) {
|
||||
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
|
||||
@@ -3023,7 +3037,7 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
private void installHandleTooManyDeletesNotification(Account account, String authority,
|
||||
long numDeletes, int userId) {
|
||||
long numDeletes, int userId) {
|
||||
if (mNotificationMgr == null) return;
|
||||
|
||||
final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
|
||||
@@ -3099,7 +3113,7 @@ public class SyncManager {
|
||||
}
|
||||
|
||||
public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
|
||||
int upstreamActivity, int downstreamActivity, long elapsedTime) {
|
||||
int upstreamActivity, int downstreamActivity, long elapsedTime) {
|
||||
EventLog.writeEvent(2720,
|
||||
syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
|
||||
mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
|
||||
@@ -3263,4 +3277,4 @@ public class SyncManager {
|
||||
return mContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user