AbstractThreadedSyncAdapter.java revision 4a6679b97e0285c5b65ec5c0d9080ff90d3e9e81
121bb0deb36af32339521038cdbd827f74468df4aFred Quintana/* 221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Copyright (C) 2009 The Android Open Source Project 321bb0deb36af32339521038cdbd827f74468df4aFred Quintana * 421bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Licensed under the Apache License, Version 2.0 (the "License"); 521bb0deb36af32339521038cdbd827f74468df4aFred Quintana * you may not use this file except in compliance with the License. 621bb0deb36af32339521038cdbd827f74468df4aFred Quintana * You may obtain a copy of the License at 721bb0deb36af32339521038cdbd827f74468df4aFred Quintana * 821bb0deb36af32339521038cdbd827f74468df4aFred Quintana * http://www.apache.org/licenses/LICENSE-2.0 921bb0deb36af32339521038cdbd827f74468df4aFred Quintana * 1021bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Unless required by applicable law or agreed to in writing, software 1121bb0deb36af32339521038cdbd827f74468df4aFred Quintana * distributed under the License is distributed on an "AS IS" BASIS, 1221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1321bb0deb36af32339521038cdbd827f74468df4aFred Quintana * See the License for the specific language governing permissions and 1421bb0deb36af32339521038cdbd827f74468df4aFred Quintana * limitations under the License. 1521bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 1621bb0deb36af32339521038cdbd827f74468df4aFred Quintana 1721bb0deb36af32339521038cdbd827f74468df4aFred Quintanapackage android.content; 1821bb0deb36af32339521038cdbd827f74468df4aFred Quintana 1921bb0deb36af32339521038cdbd827f74468df4aFred Quintanaimport android.accounts.Account; 2021bb0deb36af32339521038cdbd827f74468df4aFred Quintanaimport android.os.Bundle; 2121bb0deb36af32339521038cdbd827f74468df4aFred Quintanaimport android.os.Process; 2221bb0deb36af32339521038cdbd827f74468df4aFred Quintana 2321bb0deb36af32339521038cdbd827f74468df4aFred Quintanaimport java.util.concurrent.atomic.AtomicInteger; 2421bb0deb36af32339521038cdbd827f74468df4aFred Quintana 2521bb0deb36af32339521038cdbd827f74468df4aFred Quintana/** 2621bb0deb36af32339521038cdbd827f74468df4aFred Quintana * An abstract implementation of a SyncAdapter that spawns a thread to invoke a sync operation. 2721bb0deb36af32339521038cdbd827f74468df4aFred Quintana * If a sync operation is already in progress when a startSync() request is received then an error 2821bb0deb36af32339521038cdbd827f74468df4aFred Quintana * will be returned to the new request and the existing request will be allowed to continue. 2921bb0deb36af32339521038cdbd827f74468df4aFred Quintana * When a startSync() is received and there is no sync operation in progress then a thread 3021bb0deb36af32339521038cdbd827f74468df4aFred Quintana * will be started to run the operation and {@link #performSync} will be invoked on that thread. 3121bb0deb36af32339521038cdbd827f74468df4aFred Quintana * If a cancelSync() is received that matches an existing sync operation then the thread 3221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * that is running that sync operation will be interrupted, which will indicate to the thread 3321bb0deb36af32339521038cdbd827f74468df4aFred Quintana * that the sync has been canceled. 3421bb0deb36af32339521038cdbd827f74468df4aFred Quintana * 3521bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @hide 3621bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 3721bb0deb36af32339521038cdbd827f74468df4aFred Quintanapublic abstract class AbstractThreadedSyncAdapter { 3821bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Context mContext; 3921bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final AtomicInteger mNumSyncStarts; 4021bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final ISyncAdapterImpl mISyncAdapterImpl; 4121bb0deb36af32339521038cdbd827f74468df4aFred Quintana 4221bb0deb36af32339521038cdbd827f74468df4aFred Quintana // all accesses to this member variable must be synchronized on "this" 4321bb0deb36af32339521038cdbd827f74468df4aFred Quintana private SyncThread mSyncThread; 4421bb0deb36af32339521038cdbd827f74468df4aFred Quintana 4521bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** Kernel event log tag. Also listed in data/etc/event-log-tags. */ 4621bb0deb36af32339521038cdbd827f74468df4aFred Quintana public static final int LOG_SYNC_DETAILS = 2743; 474a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana private final boolean mAutoInitialize; 4821bb0deb36af32339521038cdbd827f74468df4aFred Quintana 4921bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 5021bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Creates an {@link AbstractThreadedSyncAdapter}. 514a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * @param context the {@link android.content.Context} that this is running within. 524a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * @param autoInitialize if true then sync requests that have 534a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by 544a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link AbstractThreadedSyncAdapter} by calling 554a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it 564a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * is currently set to <0. 5721bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 584a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana public AbstractThreadedSyncAdapter(Context context, boolean autoInitialize) { 5921bb0deb36af32339521038cdbd827f74468df4aFred Quintana mContext = context; 6021bb0deb36af32339521038cdbd827f74468df4aFred Quintana mISyncAdapterImpl = new ISyncAdapterImpl(); 6121bb0deb36af32339521038cdbd827f74468df4aFred Quintana mNumSyncStarts = new AtomicInteger(0); 6221bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread = null; 634a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana mAutoInitialize = autoInitialize; 6421bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 6521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 6621bb0deb36af32339521038cdbd827f74468df4aFred Quintana class ISyncAdapterImpl extends ISyncAdapter.Stub { 6721bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void startSync(ISyncContext syncContext, String authority, Account account, 6821bb0deb36af32339521038cdbd827f74468df4aFred Quintana Bundle extras) { 6921bb0deb36af32339521038cdbd827f74468df4aFred Quintana final SyncContext syncContextClient = new SyncContext(syncContext); 7021bb0deb36af32339521038cdbd827f74468df4aFred Quintana 7121bb0deb36af32339521038cdbd827f74468df4aFred Quintana boolean alreadyInProgress; 7221bb0deb36af32339521038cdbd827f74468df4aFred Quintana // synchronize to make sure that mSyncThread doesn't change between when we 7321bb0deb36af32339521038cdbd827f74468df4aFred Quintana // check it and when we use it 7421bb0deb36af32339521038cdbd827f74468df4aFred Quintana synchronized (this) { 7521bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (mSyncThread == null) { 764a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana if (mAutoInitialize 774a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana && extras != null 784a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) { 794a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana if (ContentResolver.getIsSyncable(account, authority) < 0) { 804a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana ContentResolver.setIsSyncable(account, authority, 1); 814a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana } 824a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana syncContextClient.onFinished(new SyncResult()); 834a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana return; 844a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana } 8521bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread = new SyncThread( 8621bb0deb36af32339521038cdbd827f74468df4aFred Quintana "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), 8721bb0deb36af32339521038cdbd827f74468df4aFred Quintana syncContextClient, authority, account, extras); 8821bb0deb36af32339521038cdbd827f74468df4aFred Quintana Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 8921bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread.start(); 9021bb0deb36af32339521038cdbd827f74468df4aFred Quintana alreadyInProgress = false; 9121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } else { 9221bb0deb36af32339521038cdbd827f74468df4aFred Quintana alreadyInProgress = true; 9321bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 9421bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 9521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 9621bb0deb36af32339521038cdbd827f74468df4aFred Quintana // do this outside since we don't want to call back into the syncContext while 9721bb0deb36af32339521038cdbd827f74468df4aFred Quintana // holding the synchronization lock 9821bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (alreadyInProgress) { 9921bb0deb36af32339521038cdbd827f74468df4aFred Quintana syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS); 10021bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 10121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 10221bb0deb36af32339521038cdbd827f74468df4aFred Quintana 10321bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void cancelSync(ISyncContext syncContext) { 10421bb0deb36af32339521038cdbd827f74468df4aFred Quintana // synchronize to make sure that mSyncThread doesn't change between when we 10521bb0deb36af32339521038cdbd827f74468df4aFred Quintana // check it and when we use it 10621bb0deb36af32339521038cdbd827f74468df4aFred Quintana synchronized (this) { 10721bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (mSyncThread != null 10821bb0deb36af32339521038cdbd827f74468df4aFred Quintana && mSyncThread.mSyncContext.getISyncContext() == syncContext) { 10921bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread.interrupt(); 11021bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 11121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 11221bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 11321bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 11421bb0deb36af32339521038cdbd827f74468df4aFred Quintana 11521bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 11621bb0deb36af32339521038cdbd827f74468df4aFred Quintana * The thread that invokes performSync(). It also acquires the provider for this sync 11721bb0deb36af32339521038cdbd827f74468df4aFred Quintana * before calling performSync and releases it afterwards. Cancel this thread in order to 11821bb0deb36af32339521038cdbd827f74468df4aFred Quintana * cancel the sync. 11921bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 12021bb0deb36af32339521038cdbd827f74468df4aFred Quintana private class SyncThread extends Thread { 12121bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final SyncContext mSyncContext; 12221bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final String mAuthority; 12321bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Account mAccount; 12421bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Bundle mExtras; 12521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 12621bb0deb36af32339521038cdbd827f74468df4aFred Quintana private SyncThread(String name, SyncContext syncContext, String authority, 12721bb0deb36af32339521038cdbd827f74468df4aFred Quintana Account account, Bundle extras) { 12821bb0deb36af32339521038cdbd827f74468df4aFred Quintana super(name); 12921bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncContext = syncContext; 13021bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAuthority = authority; 13121bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAccount = account; 13221bb0deb36af32339521038cdbd827f74468df4aFred Quintana mExtras = extras; 13321bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 13421bb0deb36af32339521038cdbd827f74468df4aFred Quintana 13521bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void run() { 13621bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (isCanceled()) { 13721bb0deb36af32339521038cdbd827f74468df4aFred Quintana return; 13821bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 13921bb0deb36af32339521038cdbd827f74468df4aFred Quintana 14021bb0deb36af32339521038cdbd827f74468df4aFred Quintana SyncResult syncResult = new SyncResult(); 14121bb0deb36af32339521038cdbd827f74468df4aFred Quintana ContentProviderClient provider = null; 14221bb0deb36af32339521038cdbd827f74468df4aFred Quintana try { 14321bb0deb36af32339521038cdbd827f74468df4aFred Quintana provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority); 14421bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (provider != null) { 14521bb0deb36af32339521038cdbd827f74468df4aFred Quintana AbstractThreadedSyncAdapter.this.performSync(mAccount, mExtras, 14621bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAuthority, provider, syncResult); 14721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } else { 14821bb0deb36af32339521038cdbd827f74468df4aFred Quintana // TODO(fredq) update the syncResults to indicate that we were unable to 14921bb0deb36af32339521038cdbd827f74468df4aFred Quintana // find the provider. maybe with a ProviderError? 15021bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 15121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } finally { 15221bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (provider != null) { 15321bb0deb36af32339521038cdbd827f74468df4aFred Quintana provider.release(); 15421bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 15521bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (!isCanceled()) { 15621bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncContext.onFinished(syncResult); 15721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 15821bb0deb36af32339521038cdbd827f74468df4aFred Quintana // synchronize so that the assignment will be seen by other threads 15921bb0deb36af32339521038cdbd827f74468df4aFred Quintana // that also synchronize accesses to mSyncThread 16021bb0deb36af32339521038cdbd827f74468df4aFred Quintana synchronized (this) { 16121bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread = null; 16221bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 16321bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 16421bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 16521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 16621bb0deb36af32339521038cdbd827f74468df4aFred Quintana private boolean isCanceled() { 16721bb0deb36af32339521038cdbd827f74468df4aFred Quintana return Thread.currentThread().isInterrupted(); 16821bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 16921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 17021bb0deb36af32339521038cdbd827f74468df4aFred Quintana 17121bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 17221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @return a reference to the ISyncAdapter interface into this SyncAdapter implementation. 17321bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 17421bb0deb36af32339521038cdbd827f74468df4aFred Quintana public final ISyncAdapter getISyncAdapter() { 17521bb0deb36af32339521038cdbd827f74468df4aFred Quintana return mISyncAdapterImpl; 17621bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 17721bb0deb36af32339521038cdbd827f74468df4aFred Quintana 17821bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 17921bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Perform a sync for this account. SyncAdapter-specific parameters may 18021bb0deb36af32339521038cdbd827f74468df4aFred Quintana * be specified in extras, which is guaranteed to not be null. Invocations 18121bb0deb36af32339521038cdbd827f74468df4aFred Quintana * of this method are guaranteed to be serialized. 18221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * 18321bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param account the account that should be synced 18421bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param extras SyncAdapter-specific parameters 18521bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param authority the authority of this sync request 18621bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param provider a ContentProviderClient that points to the ContentProvider for this 18721bb0deb36af32339521038cdbd827f74468df4aFred Quintana * authority 18821bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param syncResult SyncAdapter-specific parameters 18921bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 19021bb0deb36af32339521038cdbd827f74468df4aFred Quintana public abstract void performSync(Account account, Bundle extras, 19121bb0deb36af32339521038cdbd827f74468df4aFred Quintana String authority, ContentProviderClient provider, SyncResult syncResult); 19221bb0deb36af32339521038cdbd827f74468df4aFred Quintana}