diff options
Diffstat (limited to 'core/java/android/content/TempProviderSyncAdapter.java')
-rw-r--r-- | core/java/android/content/TempProviderSyncAdapter.java | 550 |
1 files changed, 0 insertions, 550 deletions
diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java deleted file mode 100644 index eb3a5da..0000000 --- a/core/java/android/content/TempProviderSyncAdapter.java +++ /dev/null @@ -1,550 +0,0 @@ -package android.content; - -import android.database.SQLException; -import android.os.Bundle; -import android.os.Debug; -import android.os.NetStat; -import android.os.Parcelable; -import android.os.Process; -import android.os.SystemProperties; -import android.text.TextUtils; -import android.util.Config; -import android.util.EventLog; -import android.util.Log; -import android.util.TimingLogger; - -/** - * @hide - */ -public abstract class TempProviderSyncAdapter extends SyncAdapter { - private static final String TAG = "Sync"; - - private static final int MAX_GET_SERVER_DIFFS_LOOP_COUNT = 20; - private static final int MAX_UPLOAD_CHANGES_LOOP_COUNT = 10; - private static final int NUM_ALLOWED_SIMULTANEOUS_DELETIONS = 5; - private static final long PERCENT_ALLOWED_SIMULTANEOUS_DELETIONS = 20; - - private volatile SyncableContentProvider mProvider; - private volatile SyncThread mSyncThread = null; - private volatile boolean mProviderSyncStarted; - private volatile boolean mAdapterSyncStarted; - - public TempProviderSyncAdapter(SyncableContentProvider provider) { - super(); - mProvider = provider; - } - - /** - * Used by getServerDiffs() to track the sync progress for a given - * sync adapter. Implementations of SyncAdapter generally specialize - * this class in order to track specific data about that SyncAdapter's - * sync. If an implementation of SyncAdapter doesn't need to store - * any data for a sync it may use TrivialSyncData. - */ - public static abstract class SyncData implements Parcelable { - - } - - public final void setContext(Context context) { - mContext = context; - } - - /** - * Retrieve the Context this adapter is running in. Only available - * once onSyncStarting() is called (not available from constructor). - */ - final public Context getContext() { - return mContext; - } - - /** - * Called right before a sync is started. - * - * @param context allows you to publish status and interact with the - * @param account the account to sync - * @param forced if true then the sync was forced - * @param result information to track what happened during this sync attempt - * @return true, if the sync was successfully started. One reason it can - * fail to start is if there is no user configured on the device. - */ - public abstract void onSyncStarting(SyncContext context, String account, boolean forced, - SyncResult result); - - /** - * Called right after a sync is completed - * - * @param context allows you to publish status and interact with the - * user during interactive syncs. - * @param success true if the sync suceeded, false if an error occured - */ - public abstract void onSyncEnding(SyncContext context, boolean success); - - /** - * Implement this to return true if the data in your content provider - * is read only. - */ - public abstract boolean isReadOnly(); - - /** - * Get diffs from the server since the last completed sync and put them - * into a temporary provider. - * - * @param context allows you to publish status and interact with the - * user during interactive syncs. - * @param syncData used to track the progress this client has made in syncing data - * from the server - * @param tempProvider this is where the diffs should be stored - * @param extras any extra data describing the sync that is desired - * @param syncInfo sync adapter-specific data that is used during a single sync operation - * @param syncResult information to track what happened during this sync attempt - */ - public abstract void getServerDiffs(SyncContext context, - SyncData syncData, SyncableContentProvider tempProvider, - Bundle extras, Object syncInfo, SyncResult syncResult); - - /** - * Send client diffs to the server, optionally receiving more diffs from the server - * - * @param context allows you to publish status and interact with the - * user during interactive syncs. - * @param clientDiffs the diffs from the client - * @param serverDiffs the SyncableContentProvider that should be populated with -* the entries that were returned in response to an insert/update/delete request -* to the server - * @param syncResult information to track what happened during this sync attempt - * @param dontActuallySendDeletes - */ - public abstract void sendClientDiffs(SyncContext context, - SyncableContentProvider clientDiffs, - SyncableContentProvider serverDiffs, SyncResult syncResult, - boolean dontActuallySendDeletes); - - /** - * Reads the sync data from the ContentProvider - * @param contentProvider the ContentProvider to read from - * @return the SyncData for the provider. This may be null. - */ - public SyncData readSyncData(SyncableContentProvider contentProvider) { - return null; - } - - /** - * Create and return a new, empty SyncData object - */ - public SyncData newSyncData() { - return null; - } - - /** - * Stores the sync data in the Sync Stats database, keying it by - * the account that was set in the last call to onSyncStarting() - */ - public void writeSyncData(SyncData syncData, SyncableContentProvider contentProvider) {} - - /** - * Indicate to the SyncAdapter that the last sync that was started has - * been cancelled. - */ - public abstract void onSyncCanceled(); - - /** - * Initializes the temporary content providers used during - * {@link TempProviderSyncAdapter#sendClientDiffs}. - * May copy relevant data from the underlying db into this provider so - * joins, etc., can work. - * - * @param cp The ContentProvider to initialize. - */ - protected void initTempProvider(SyncableContentProvider cp) {} - - protected Object createSyncInfo() { - return null; - } - - /** - * Called when the accounts list possibly changed, to give the - * SyncAdapter a chance to do any necessary bookkeeping, e.g. - * to make sure that any required SubscribedFeeds subscriptions - * exist. - * @param accounts the list of accounts - */ - public abstract void onAccountsChanged(String[] accounts); - - private Context mContext; - - private class SyncThread extends Thread { - private final String mAccount; - private final Bundle mExtras; - private final SyncContext mSyncContext; - private volatile boolean mIsCanceled = false; - private long mInitialTxBytes; - private long mInitialRxBytes; - private final SyncResult mResult; - - SyncThread(SyncContext syncContext, String account, Bundle extras) { - super("SyncThread"); - mAccount = account; - mExtras = extras; - mSyncContext = syncContext; - mResult = new SyncResult(); - } - - void cancelSync() { - mIsCanceled = true; - if (mAdapterSyncStarted) onSyncCanceled(); - if (mProviderSyncStarted) mProvider.onSyncCanceled(); - // We may lose the last few sync events when canceling. Oh well. - int uid = Process.myUid(); - logSyncDetails(NetStat.getUidTxBytes(uid) - mInitialTxBytes, - NetStat.getUidRxBytes(uid) - mInitialRxBytes, mResult); - } - - @Override - public void run() { - Process.setThreadPriority(Process.myTid(), - Process.THREAD_PRIORITY_BACKGROUND); - int uid = Process.myUid(); - mInitialTxBytes = NetStat.getUidTxBytes(uid); - mInitialRxBytes = NetStat.getUidRxBytes(uid); - try { - sync(mSyncContext, mAccount, mExtras); - } catch (SQLException e) { - Log.e(TAG, "Sync failed", e); - mResult.databaseError = true; - } finally { - mSyncThread = null; - if (!mIsCanceled) { - logSyncDetails(NetStat.getUidTxBytes(uid) - mInitialTxBytes, - NetStat.getUidRxBytes(uid) - mInitialRxBytes, mResult); - mSyncContext.onFinished(mResult); - } - } - } - - private void sync(SyncContext syncContext, String account, Bundle extras) { - mIsCanceled = false; - - mProviderSyncStarted = false; - mAdapterSyncStarted = false; - String message = null; - - boolean syncForced = extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false); - - try { - mProvider.onSyncStart(syncContext, account); - mProviderSyncStarted = true; - onSyncStarting(syncContext, account, syncForced, mResult); - if (mResult.hasError()) { - message = "SyncAdapter failed while trying to start sync"; - return; - } - mAdapterSyncStarted = true; - if (mIsCanceled) { - return; - } - final String syncTracingEnabledValue = SystemProperties.get(TAG + "Tracing"); - final boolean syncTracingEnabled = !TextUtils.isEmpty(syncTracingEnabledValue); - try { - if (syncTracingEnabled) { - System.gc(); - System.gc(); - Debug.startMethodTracing("synctrace." + System.currentTimeMillis()); - } - runSyncLoop(syncContext, account, extras); - } finally { - if (syncTracingEnabled) Debug.stopMethodTracing(); - } - onSyncEnding(syncContext, !mResult.hasError()); - mAdapterSyncStarted = false; - mProvider.onSyncStop(syncContext, true); - mProviderSyncStarted = false; - } finally { - if (mAdapterSyncStarted) { - mAdapterSyncStarted = false; - onSyncEnding(syncContext, false); - } - if (mProviderSyncStarted) { - mProviderSyncStarted = false; - mProvider.onSyncStop(syncContext, false); - } - if (!mIsCanceled) { - if (message != null) syncContext.setStatusText(message); - } - } - } - - private void runSyncLoop(SyncContext syncContext, String account, Bundle extras) { - TimingLogger syncTimer = new TimingLogger(TAG + "Profiling", "sync"); - syncTimer.addSplit("start"); - int loopCount = 0; - boolean tooManyGetServerDiffsAttempts = false; - - final boolean overrideTooManyDeletions = - extras.getBoolean(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS, - false); - final boolean discardLocalDeletions = - extras.getBoolean(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS, false); - boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, - false /* default this flag to false */); - SyncableContentProvider serverDiffs = null; - TempProviderSyncResult result = new TempProviderSyncResult(); - try { - if (!uploadOnly) { - /** - * This loop repeatedly calls SyncAdapter.getServerDiffs() - * (to get changes from the feed) followed by - * ContentProvider.merge() (to incorporate these changes - * into the provider), stopping when the SyncData returned - * from getServerDiffs() indicates that all the data was - * fetched. - */ - while (!mIsCanceled) { - // Don't let a bad sync go forever - if (loopCount++ == MAX_GET_SERVER_DIFFS_LOOP_COUNT) { - Log.e(TAG, "runSyncLoop: Hit max loop count while getting server diffs " - + getClass().getName()); - // TODO: change the structure here to schedule a new sync - // with a backoff time, keeping track to be sure - // we don't keep doing this forever (due to some bug or - // mismatch between the client and the server) - tooManyGetServerDiffsAttempts = true; - break; - } - - // Get an empty content provider to put the diffs into - if (serverDiffs != null) serverDiffs.close(); - serverDiffs = mProvider.getTemporaryInstance(); - - // Get records from the server which will be put into the serverDiffs - initTempProvider(serverDiffs); - Object syncInfo = createSyncInfo(); - SyncData syncData = readSyncData(serverDiffs); - // syncData will only be null if there was a demarshalling error - // while reading the sync data. - if (syncData == null) { - mProvider.wipeAccount(account); - syncData = newSyncData(); - } - mResult.clear(); - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: running getServerDiffs using syncData " - + syncData.toString()); - } - getServerDiffs(syncContext, syncData, serverDiffs, extras, syncInfo, - mResult); - - if (mIsCanceled) return; - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: result: " + mResult); - } - if (mResult.hasError()) return; - if (mResult.partialSyncUnavailable) { - if (Config.LOGD) { - Log.d(TAG, "partialSyncUnavailable is set, setting " - + "ignoreSyncData and retrying"); - } - mProvider.wipeAccount(account); - continue; - } - - // write the updated syncData back into the temp provider - writeSyncData(syncData, serverDiffs); - - // apply the downloaded changes to the provider - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: running merge"); - } - mProvider.merge(syncContext, serverDiffs, - null /* don't return client diffs */, mResult); - if (mIsCanceled) return; - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: result: " + mResult); - } - - // if the server has no more changes then break out of the loop - if (!mResult.moreRecordsToGet) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: fetched all data, moving on"); - } - break; - } - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: more data to fetch, looping"); - } - } - } - - /** - * This loop repeatedly calls ContentProvider.merge() followed - * by SyncAdapter.merge() until either indicate that there is - * no more work to do by returning null. - * <p> - * The initial ContentProvider.merge() returns a temporary - * ContentProvider that contains any local changes that need - * to be committed to the server. - * <p> - * The SyncAdapter.merge() calls upload the changes to the server - * and populates temporary provider (the serverDiffs) with the - * result. - * <p> - * Subsequent calls to ContentProvider.merge() incoporate the - * result of previous SyncAdapter.merge() calls into the - * real ContentProvider and again return a temporary - * ContentProvider that contains any local changes that need - * to be committed to the server. - */ - loopCount = 0; - boolean readOnly = isReadOnly(); - long previousNumModifications = 0; - if (serverDiffs != null) { - serverDiffs.close(); - serverDiffs = null; - } - - // If we are discarding local deletions then we need to redownload all the items - // again (since some of them might have been deleted). We do this by deleting the - // sync data for the current account by writing in a null one. - if (discardLocalDeletions) { - serverDiffs = mProvider.getTemporaryInstance(); - initTempProvider(serverDiffs); - writeSyncData(null, serverDiffs); - } - - while (!mIsCanceled) { - if (Config.LOGV) { - Log.v(TAG, "runSyncLoop: Merging diffs from server to client"); - } - if (result.tempContentProvider != null) { - result.tempContentProvider.close(); - result.tempContentProvider = null; - } - mResult.clear(); - mProvider.merge(syncContext, serverDiffs, readOnly ? null : result, - mResult); - if (mIsCanceled) return; - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: result: " + mResult); - } - - SyncableContentProvider clientDiffs = - readOnly ? null : result.tempContentProvider; - if (clientDiffs == null) { - // Nothing to commit back to the server - if (Config.LOGV) Log.v(TAG, "runSyncLoop: No client diffs"); - break; - } - - long numModifications = mResult.stats.numUpdates - + mResult.stats.numDeletes - + mResult.stats.numInserts; - - // as long as we are making progress keep resetting the loop count - if (numModifications < previousNumModifications) { - loopCount = 0; - } - previousNumModifications = numModifications; - - // Don't let a bad sync go forever - if (loopCount++ >= MAX_UPLOAD_CHANGES_LOOP_COUNT) { - Log.e(TAG, "runSyncLoop: Hit max loop count while syncing " - + getClass().getName()); - mResult.tooManyRetries = true; - break; - } - - if (!overrideTooManyDeletions && !discardLocalDeletions - && hasTooManyDeletions(mResult.stats)) { - if (Config.LOGD) { - Log.d(TAG, "runSyncLoop: Too many deletions were found in provider " - + getClass().getName() + ", not doing any more updates"); - } - long numDeletes = mResult.stats.numDeletes; - mResult.stats.clear(); - mResult.tooManyDeletions = true; - mResult.stats.numDeletes = numDeletes; - break; - } - - if (Config.LOGV) Log.v(TAG, "runSyncLoop: Merging diffs from client to server"); - if (serverDiffs != null) serverDiffs.close(); - serverDiffs = clientDiffs.getTemporaryInstance(); - initTempProvider(serverDiffs); - mResult.clear(); - sendClientDiffs(syncContext, clientDiffs, serverDiffs, mResult, - discardLocalDeletions); - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: result: " + mResult); - } - - if (!mResult.madeSomeProgress()) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: No data from client diffs merge"); - } - break; - } - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: made some progress, looping"); - } - } - - // add in any status codes that we saved from earlier - mResult.tooManyRetries |= tooManyGetServerDiffsAttempts; - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "runSyncLoop: final result: " + mResult); - } - } finally { - // do this in the finally block to guarantee that is is set and not overwritten - if (discardLocalDeletions) { - mResult.fullSyncRequested = true; - } - if (serverDiffs != null) serverDiffs.close(); - if (result.tempContentProvider != null) result.tempContentProvider.close(); - syncTimer.addSplit("stop"); - syncTimer.dumpToLog(); - } - } - } - - /** - * Logs details on the sync. - * Normally this will be overridden by a subclass that will provide - * provider-specific details. - * - * @param bytesSent number of bytes the sync sent over the network - * @param bytesReceived number of bytes the sync received over the network - * @param result The SyncResult object holding info on the sync - */ - protected void logSyncDetails(long bytesSent, long bytesReceived, SyncResult result) { - EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, ""); - } - - public void startSync(SyncContext syncContext, String account, Bundle extras) { - if (mSyncThread != null) { - syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS); - return; - } - - mSyncThread = new SyncThread(syncContext, account, extras); - mSyncThread.start(); - } - - public void cancelSync() { - if (mSyncThread != null) { - mSyncThread.cancelSync(); - } - } - - protected boolean hasTooManyDeletions(SyncStats stats) { - long numEntries = stats.numEntries; - long numDeletedEntries = stats.numDeletes; - - long percentDeleted = (numDeletedEntries == 0) - ? 0 - : (100 * numDeletedEntries / - (numEntries + numDeletedEntries)); - boolean tooManyDeletions = - (numDeletedEntries > NUM_ALLOWED_SIMULTANEOUS_DELETIONS) - && (percentDeleted > PERCENT_ALLOWED_SIMULTANEOUS_DELETIONS); - return tooManyDeletions; - } -} |