diff options
| author | 2015-12-23 18:24:23 +0000 | |
|---|---|---|
| committer | 2016-02-12 15:49:01 +0000 | |
| commit | ae0bcddc86752d2368ebcb73dab0b7d9133b3f67 (patch) | |
| tree | 95ecbecfdead7ca546b4733798a98c299627050c | |
| parent | 19ff7804b394e80a6adf731e756c3d7c361cba42 (diff) | |
Stashing SyncSettings for accounts added aft SUW
Stashing SyncSettings for accounts not added by SUW Restore time
and restoring these settings whenever the account is added.
Bug: 26181613
Change-Id: Ia83e3fd43385a05424a8991115aa21ac90f4cd49
| -rw-r--r-- | core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java | 113 | ||||
| -rw-r--r-- | services/core/java/com/android/server/content/SyncManager.java | 80 |
2 files changed, 135 insertions, 58 deletions
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java index 0449340ea21a..1b4049212255 100644 --- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java +++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java @@ -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) { } -} +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index 218e529d5366..2f87f8024c2e 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -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; } } -} +}
\ No newline at end of file |