diff options
author | Fred Quintana <fredq@google.com> | 2009-06-16 10:24:58 -0700 |
---|---|---|
committer | Fred Quintana <fredq@google.com> | 2009-06-16 15:25:24 -0700 |
commit | 21bb0deb36af32339521038cdbd827f74468df4a (patch) | |
tree | e8f8d47fd40cda7233e2a3fd7efe355613030500 /core/java/android | |
parent | d638d8d6305bf5861736045e0215099d2fb693f1 (diff) | |
download | frameworks_base-21bb0deb36af32339521038cdbd827f74468df4a.zip frameworks_base-21bb0deb36af32339521038cdbd827f74468df4a.tar.gz frameworks_base-21bb0deb36af32339521038cdbd827f74468df4a.tar.bz2 |
beef up the syncadapter API
Diffstat (limited to 'core/java/android')
-rw-r--r-- | core/java/android/content/AbstractThreadedSyncAdapter.java | 176 | ||||
-rw-r--r-- | core/java/android/content/ISyncAdapter.aidl | 7 | ||||
-rw-r--r-- | core/java/android/content/SyncAdapter.java | 4 | ||||
-rw-r--r-- | core/java/android/content/SyncAdapterNew.java | 135 | ||||
-rw-r--r-- | core/java/android/content/SyncManager.java | 15 |
5 files changed, 187 insertions, 150 deletions
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java new file mode 100644 index 0000000..f15a902 --- /dev/null +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content; + +import android.accounts.Account; +import android.os.Bundle; +import android.os.Process; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * An abstract implementation of a SyncAdapter that spawns a thread to invoke a sync operation. + * If a sync operation is already in progress when a startSync() request is received then an error + * will be returned to the new request and the existing request will be allowed to continue. + * When a startSync() is received and there is no sync operation in progress then a thread + * will be started to run the operation and {@link #performSync} will be invoked on that thread. + * If a cancelSync() is received that matches an existing sync operation then the thread + * that is running that sync operation will be interrupted, which will indicate to the thread + * that the sync has been canceled. + * + * @hide + */ +public abstract class AbstractThreadedSyncAdapter { + private final Context mContext; + private final AtomicInteger mNumSyncStarts; + private final ISyncAdapterImpl mISyncAdapterImpl; + + // all accesses to this member variable must be synchronized on "this" + private SyncThread mSyncThread; + + /** Kernel event log tag. Also listed in data/etc/event-log-tags. */ + public static final int LOG_SYNC_DETAILS = 2743; + + /** + * Creates an {@link AbstractThreadedSyncAdapter}. + * @param context the {@link Context} that this is running within. + */ + public AbstractThreadedSyncAdapter(Context context) { + mContext = context; + mISyncAdapterImpl = new ISyncAdapterImpl(); + mNumSyncStarts = new AtomicInteger(0); + mSyncThread = null; + } + + class ISyncAdapterImpl extends ISyncAdapter.Stub { + public void startSync(ISyncContext syncContext, String authority, Account account, + Bundle extras) { + final SyncContext syncContextClient = new SyncContext(syncContext); + + boolean alreadyInProgress; + // synchronize to make sure that mSyncThread doesn't change between when we + // check it and when we use it + synchronized (this) { + if (mSyncThread == null) { + mSyncThread = new SyncThread( + "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), + syncContextClient, authority, account, extras); + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + mSyncThread.start(); + alreadyInProgress = false; + } else { + alreadyInProgress = true; + } + } + + // do this outside since we don't want to call back into the syncContext while + // holding the synchronization lock + if (alreadyInProgress) { + syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS); + } + } + + public void cancelSync(ISyncContext syncContext) { + // synchronize to make sure that mSyncThread doesn't change between when we + // check it and when we use it + synchronized (this) { + if (mSyncThread != null + && mSyncThread.mSyncContext.getISyncContext() == syncContext) { + mSyncThread.interrupt(); + } + } + } + } + + /** + * The thread that invokes performSync(). It also acquires the provider for this sync + * before calling performSync and releases it afterwards. Cancel this thread in order to + * cancel the sync. + */ + private class SyncThread extends Thread { + private final SyncContext mSyncContext; + private final String mAuthority; + private final Account mAccount; + private final Bundle mExtras; + + private SyncThread(String name, SyncContext syncContext, String authority, + Account account, Bundle extras) { + super(name); + mSyncContext = syncContext; + mAuthority = authority; + mAccount = account; + mExtras = extras; + } + + public void run() { + if (isCanceled()) { + return; + } + + SyncResult syncResult = new SyncResult(); + ContentProviderClient provider = null; + try { + provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority); + if (provider != null) { + AbstractThreadedSyncAdapter.this.performSync(mAccount, mExtras, + mAuthority, provider, syncResult); + } else { + // TODO(fredq) update the syncResults to indicate that we were unable to + // find the provider. maybe with a ProviderError? + } + } finally { + if (provider != null) { + provider.release(); + } + if (!isCanceled()) { + mSyncContext.onFinished(syncResult); + } + // synchronize so that the assignment will be seen by other threads + // that also synchronize accesses to mSyncThread + synchronized (this) { + mSyncThread = null; + } + } + } + + private boolean isCanceled() { + return Thread.currentThread().isInterrupted(); + } + } + + /** + * @return a reference to the ISyncAdapter interface into this SyncAdapter implementation. + */ + public final ISyncAdapter getISyncAdapter() { + return mISyncAdapterImpl; + } + + /** + * Perform a sync for this account. SyncAdapter-specific parameters may + * be specified in extras, which is guaranteed to not be null. Invocations + * of this method are guaranteed to be serialized. + * + * @param account the account that should be synced + * @param extras SyncAdapter-specific parameters + * @param authority the authority of this sync request + * @param provider a ContentProviderClient that points to the ContentProvider for this + * authority + * @param syncResult SyncAdapter-specific parameters + */ + public abstract void performSync(Account account, Bundle extras, + String authority, ContentProviderClient provider, SyncResult syncResult); +}
\ No newline at end of file diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl index d228605..4660527 100644 --- a/core/java/android/content/ISyncAdapter.aidl +++ b/core/java/android/content/ISyncAdapter.aidl @@ -31,14 +31,17 @@ oneway interface ISyncAdapter { * * @param syncContext the ISyncContext used to indicate the progress of the sync. When * the sync is finished (successfully or not) ISyncContext.onFinished() must be called. + * @param authority the authority that should be synced * @param account the account that should be synced * @param extras SyncAdapter-specific parameters */ - void startSync(ISyncContext syncContext, in Account account, in Bundle extras); + void startSync(ISyncContext syncContext, String authority, + in Account account, in Bundle extras); /** * Cancel the most recently initiated sync. Due to race conditions, this may arrive * after the ISyncContext.onFinished() for that sync was called. + * @param syncContext the ISyncContext that was passed to {@link #startSync} */ - void cancelSync(); + void cancelSync(ISyncContext syncContext); } diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java index c658fb7..1d5ade1 100644 --- a/core/java/android/content/SyncAdapter.java +++ b/core/java/android/content/SyncAdapter.java @@ -30,12 +30,12 @@ public abstract class SyncAdapter { public static final int LOG_SYNC_DETAILS = 2743; class Transport extends ISyncAdapter.Stub { - public void startSync(ISyncContext syncContext, Account account, + public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) throws RemoteException { SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras); } - public void cancelSync() throws RemoteException { + public void cancelSync(ISyncContext syncContext) throws RemoteException { SyncAdapter.this.cancelSync(); } } diff --git a/core/java/android/content/SyncAdapterNew.java b/core/java/android/content/SyncAdapterNew.java deleted file mode 100644 index 5b23395..0000000 --- a/core/java/android/content/SyncAdapterNew.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content; - -import android.os.*; -import android.os.Process; -import android.accounts.Account; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * @hide - */ -public abstract class SyncAdapterNew { - private static final String TAG = "SyncAdapter"; - private final Context mContext; - private final String mAuthority; - - /** Kernel event log tag. Also listed in data/etc/event-log-tags. */ - public static final int LOG_SYNC_DETAILS = 2743; - - public SyncAdapterNew(Context context, String authority) { - mContext = context; - mAuthority = authority; - } - - class Transport extends ISyncAdapter.Stub { - private final AtomicInteger mNumSyncStarts = new AtomicInteger(0); - private volatile Thread mSyncThread; - - public void startSync(ISyncContext syncContext, Account account, Bundle extras) { - boolean alreadyInProgress; - synchronized (this) { - if (mSyncThread == null) { - mSyncThread = new Thread( - new SyncRunnable(new SyncContext(syncContext), account, extras), - "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet()); - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - mSyncThread.start(); - alreadyInProgress = false; - } else { - alreadyInProgress = true; - } - } - - if (alreadyInProgress) { - try { - syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS); - } catch (RemoteException e) { - // don't care if the caller is no longer around - } - } - } - - public void cancelSync() { - synchronized (this) { - if (mSyncThread != null) { - mSyncThread.interrupt(); - } - } - } - - private class SyncRunnable implements Runnable { - private final SyncContext mSyncContext; - private final Account mAccount; - private final Bundle mExtras; - - private SyncRunnable(SyncContext syncContext, Account account, Bundle extras) { - mSyncContext = syncContext; - mAccount = account; - mExtras = extras; - } - - public void run() { - if (isCanceled()) { - return; - } - - SyncResult syncResult = new SyncResult(); - ContentProviderClient provider = mAuthority != null - ? mContext.getContentResolver().acquireContentProviderClient(mAuthority) - : null; - try { - SyncAdapterNew.this.performSync(mAccount, mExtras, provider, syncResult); - } finally { - if (provider != null) { - provider.release(); - } - if (!isCanceled()) { - mSyncContext.onFinished(syncResult); - } - mSyncThread = null; - } - } - - private boolean isCanceled() { - return Thread.currentThread().isInterrupted(); - } - } - } - - Transport mTransport = new Transport(); - - /** - * Get the Transport object. - */ - public final ISyncAdapter getISyncAdapter() { - return mTransport; - } - - /** - * Perform a sync for this account. SyncAdapter-specific parameters may - * be specified in extras, which is guaranteed to not be null. Invocations - * of this method are guaranteed to be serialized. - * - * @param account the account that should be synced - * @param extras SyncAdapter-specific parameters - */ - public abstract void performSync(Account account, Bundle extras, - ContentProviderClient provider, SyncResult syncResult); -}
\ No newline at end of file diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index cba02aa..c7954a5 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -33,8 +33,6 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.RegisteredServicesCache; -import android.database.Cursor; -import android.database.DatabaseUtils; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; @@ -50,10 +48,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.provider.Sync; import android.provider.Settings; -import android.provider.Sync.History; -import android.text.TextUtils; import android.text.format.DateUtils; import android.text.format.Time; import android.util.Config; @@ -77,8 +72,6 @@ import java.util.List; import java.util.Map; import java.util.PriorityQueue; import java.util.Random; -import java.util.Observer; -import java.util.Observable; import java.util.Set; /** @@ -1435,7 +1428,7 @@ class SyncManager implements OnAccountsUpdatedListener { // outstanding if (mActiveSyncContext.mSyncAdapter != null) { try { - mActiveSyncContext.mSyncAdapter.cancelSync(); + mActiveSyncContext.mSyncAdapter.cancelSync(mActiveSyncContext); } catch (RemoteException e) { // we don't need to retry this in this case } @@ -1678,8 +1671,8 @@ class SyncManager implements OnAccountsUpdatedListener { mActiveSyncContext.mSyncAdapter = syncAdapter; final SyncOperation syncOperation = mActiveSyncContext.mSyncOperation; try { - syncAdapter.startSync(mActiveSyncContext, syncOperation.account, - syncOperation.extras); + syncAdapter.startSync(mActiveSyncContext, syncOperation.authority, + syncOperation.account, syncOperation.extras); } catch (RemoteException remoteExc) { if (Config.LOGD) { Log.d(TAG, "runStateIdle: caught a RemoteException, rescheduling", remoteExc); @@ -1742,7 +1735,7 @@ class SyncManager implements OnAccountsUpdatedListener { } if (activeSyncContext.mSyncAdapter != null) { try { - activeSyncContext.mSyncAdapter.cancelSync(); + activeSyncContext.mSyncAdapter.cancelSync(activeSyncContext); } catch (RemoteException e) { // we don't need to retry this in this case } |