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; 21f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintanaimport android.os.IBinder; 221719a39a4c0ff3afbf9c9e5f03f20ba50f490902Ken Shirriffimport android.os.Process; 23e7424ffdafb0c18f753f383ebfb121ea5ebf582bFred Quintanaimport android.os.RemoteException; 2409b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadlerimport android.os.Trace; 2521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 260c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintanaimport java.util.HashMap; 2721bb0deb36af32339521038cdbd827f74468df4aFred Quintanaimport java.util.concurrent.atomic.AtomicInteger; 2821bb0deb36af32339521038cdbd827f74468df4aFred Quintana 2921bb0deb36af32339521038cdbd827f74468df4aFred Quintana/** 3021bb0deb36af32339521038cdbd827f74468df4aFred Quintana * An abstract implementation of a SyncAdapter that spawns a thread to invoke a sync operation. 3121bb0deb36af32339521038cdbd827f74468df4aFred Quintana * If a sync operation is already in progress when a startSync() request is received then an error 3221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * will be returned to the new request and the existing request will be allowed to continue. 3321bb0deb36af32339521038cdbd827f74468df4aFred Quintana * When a startSync() is received and there is no sync operation in progress then a thread 34f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * will be started to run the operation and {@link #onPerformSync} will be invoked on that thread. 3521bb0deb36af32339521038cdbd827f74468df4aFred Quintana * If a cancelSync() is received that matches an existing sync operation then the thread 3621bb0deb36af32339521038cdbd827f74468df4aFred Quintana * that is running that sync operation will be interrupted, which will indicate to the thread 3721bb0deb36af32339521038cdbd827f74468df4aFred Quintana * that the sync has been canceled. 38e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <p> 39e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * In order to be a sync adapter one must extend this class, provide implementations for the 40e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * abstract methods and write a service that returns the result of {@link #getSyncAdapterBinder()} 41e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * in the service's {@link android.app.Service#onBind(android.content.Intent)} when invoked 42e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * with an intent with action <code>android.content.SyncAdapter</code>. This service 43e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * must specify the following intent filter and metadata tags in its AndroidManifest.xml file 44e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <pre> 45e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <intent-filter> 46e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <action android:name="android.content.SyncAdapter" /> 47e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * </intent-filter> 48e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <meta-data android:name="android.content.SyncAdapter" 49e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * android:resource="@xml/syncadapter" /> 50e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * </pre> 51e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * The <code>android:resource</code> attribute must point to a resource that looks like: 52e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <pre> 53e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" 54e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * android:contentAuthority="authority" 55e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * android:accountType="accountType" 56e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * android:userVisible="true|false" 57e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * android:supportsUploading="true|false" 58e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * android:allowParallelSyncs="true|false" 59e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * android:isAlwaysSyncable="true|false" 60e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * android:syncAdapterSettingsAction="ACTION_OF_SETTINGS_ACTIVITY" 61e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * /> 62e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * </pre> 63e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <ul> 64e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <li>The <code>android:contentAuthority</code> and <code>android:accountType</code> attributes 65e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * indicate which content authority and for which account types this sync adapter serves. 66e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <li><code>android:userVisible</code> defaults to true and controls whether or not this sync 67e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * adapter shows up in the Sync Settings screen. 68e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <li><code>android:supportsUploading</code> defaults 69e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * to true and if true an upload-only sync will be requested for all syncadapters associated 70e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * with an authority whenever that authority's content provider does a 71e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)} 72e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * with syncToNetwork set to true. 73e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <li><code>android:allowParallelSyncs</code> defaults to false and if true indicates that 74e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * the sync adapter can handle syncs for multiple accounts at the same time. Otherwise 75e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * the SyncManager will wait until the sync adapter is not in use before requesting that 76e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * it sync an account's data. 77e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <li><code>android:isAlwaysSyncable</code> defaults to false and if true tells the SyncManager 78e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * to intialize the isSyncable state to 1 for that sync adapter for each account that is added. 79e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * <li><code>android:syncAdapterSettingsAction</code> defaults to null and if supplied it 80e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * specifies an Intent action of an activity that can be used to adjust the sync adapter's 81e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * sync settings. The activity must live in the same package as the sync adapter. 82e6d60ecdf668499f003a81274f18cb57075eb65bFred Quintana * </ul> 8321bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 8421bb0deb36af32339521038cdbd827f74468df4aFred Quintanapublic abstract class AbstractThreadedSyncAdapter { 8597ef7637c6799e72956db8e08192539f1b1942f6Fred Quintana /** 8697ef7637c6799e72956db8e08192539f1b1942f6Fred Quintana * Kernel event log tag. Also listed in data/etc/event-log-tags. 87d3ad696b1daaa6c92d8fa268c81ce220ed1d9ffcJoe Onorato * @deprecated Private constant. May go away in the next release. 8897ef7637c6799e72956db8e08192539f1b1942f6Fred Quintana */ 89d3ad696b1daaa6c92d8fa268c81ce220ed1d9ffcJoe Onorato @Deprecated 9097ef7637c6799e72956db8e08192539f1b1942f6Fred Quintana public static final int LOG_SYNC_DETAILS = 2743; 9197ef7637c6799e72956db8e08192539f1b1942f6Fred Quintana 9221bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Context mContext; 9321bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final AtomicInteger mNumSyncStarts; 9421bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final ISyncAdapterImpl mISyncAdapterImpl; 9521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 963cff76aaa893049d02467a231d477e86a0f80daaFred Quintana // all accesses to this member variable must be synchronized on mSyncThreadLock 970c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana private final HashMap<Account, SyncThread> mSyncThreads = new HashMap<Account, SyncThread>(); 983cff76aaa893049d02467a231d477e86a0f80daaFred Quintana private final Object mSyncThreadLock = new Object(); 9921bb0deb36af32339521038cdbd827f74468df4aFred Quintana 1004a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana private final boolean mAutoInitialize; 1010c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana private boolean mAllowParallelSyncs; 10221bb0deb36af32339521038cdbd827f74468df4aFred Quintana 10321bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 10421bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Creates an {@link AbstractThreadedSyncAdapter}. 1054a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * @param context the {@link android.content.Context} that this is running within. 1064a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * @param autoInitialize if true then sync requests that have 1074a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by 1084a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link AbstractThreadedSyncAdapter} by calling 1094a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it 1104a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * is currently set to <0. 11121bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 1124a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana public AbstractThreadedSyncAdapter(Context context, boolean autoInitialize) { 1130c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana this(context, autoInitialize, false /* allowParallelSyncs */); 1140c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } 1150c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana 1160c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana /** 1170c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * Creates an {@link AbstractThreadedSyncAdapter}. 1180c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * @param context the {@link android.content.Context} that this is running within. 1190c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * @param autoInitialize if true then sync requests that have 1200c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by 1210c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * {@link AbstractThreadedSyncAdapter} by calling 1220c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it 1230c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * is currently set to <0. 1240c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * @param allowParallelSyncs if true then allow syncs for different accounts to run 1250c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * at the same time, each in their own thread. This must be consistent with the setting 1260c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * in the SyncAdapter's configuration file. 1270c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana */ 1280c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana public AbstractThreadedSyncAdapter(Context context, 1290c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana boolean autoInitialize, boolean allowParallelSyncs) { 13021bb0deb36af32339521038cdbd827f74468df4aFred Quintana mContext = context; 13121bb0deb36af32339521038cdbd827f74468df4aFred Quintana mISyncAdapterImpl = new ISyncAdapterImpl(); 13221bb0deb36af32339521038cdbd827f74468df4aFred Quintana mNumSyncStarts = new AtomicInteger(0); 1334a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana mAutoInitialize = autoInitialize; 1340c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana mAllowParallelSyncs = allowParallelSyncs; 13521bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 13621bb0deb36af32339521038cdbd827f74468df4aFred Quintana 137c298a8518a8fd73a303132c7db241f10eb46c5b6Fred Quintana public Context getContext() { 138c298a8518a8fd73a303132c7db241f10eb46c5b6Fred Quintana return mContext; 139c298a8518a8fd73a303132c7db241f10eb46c5b6Fred Quintana } 140c298a8518a8fd73a303132c7db241f10eb46c5b6Fred Quintana 1410c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana private Account toSyncKey(Account account) { 1420c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana if (mAllowParallelSyncs) { 1430c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana return account; 1440c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } else { 1450c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana return null; 1460c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } 1470c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } 1480c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana 149f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana private class ISyncAdapterImpl extends ISyncAdapter.Stub { 150fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams @Override 15121bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void startSync(ISyncContext syncContext, String authority, Account account, 15221bb0deb36af32339521038cdbd827f74468df4aFred Quintana Bundle extras) { 15321bb0deb36af32339521038cdbd827f74468df4aFred Quintana final SyncContext syncContextClient = new SyncContext(syncContext); 15421bb0deb36af32339521038cdbd827f74468df4aFred Quintana 15521bb0deb36af32339521038cdbd827f74468df4aFred Quintana boolean alreadyInProgress; 1560c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana // synchronize to make sure that mSyncThreads doesn't change between when we 15721bb0deb36af32339521038cdbd827f74468df4aFred Quintana // check it and when we use it 1580c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana final Account threadsKey = toSyncKey(account); 1593cff76aaa893049d02467a231d477e86a0f80daaFred Quintana synchronized (mSyncThreadLock) { 1600c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana if (!mSyncThreads.containsKey(threadsKey)) { 1614a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana if (mAutoInitialize 1624a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana && extras != null 1634a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) { 1648014cbffad1e74814ddd0a98ee5954d8bf3a6c03Daniel Karlberg try { 1658014cbffad1e74814ddd0a98ee5954d8bf3a6c03Daniel Karlberg if (ContentResolver.getIsSyncable(account, authority) < 0) { 1668014cbffad1e74814ddd0a98ee5954d8bf3a6c03Daniel Karlberg ContentResolver.setIsSyncable(account, authority, 1); 1678014cbffad1e74814ddd0a98ee5954d8bf3a6c03Daniel Karlberg } 1688014cbffad1e74814ddd0a98ee5954d8bf3a6c03Daniel Karlberg } finally { 1698014cbffad1e74814ddd0a98ee5954d8bf3a6c03Daniel Karlberg syncContextClient.onFinished(new SyncResult()); 1704a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana } 1714a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana return; 1724a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana } 1730c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana SyncThread syncThread = new SyncThread( 17421bb0deb36af32339521038cdbd827f74468df4aFred Quintana "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), 17521bb0deb36af32339521038cdbd827f74468df4aFred Quintana syncContextClient, authority, account, extras); 1760c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana mSyncThreads.put(threadsKey, syncThread); 1770c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana syncThread.start(); 17821bb0deb36af32339521038cdbd827f74468df4aFred Quintana alreadyInProgress = false; 17921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } else { 18021bb0deb36af32339521038cdbd827f74468df4aFred Quintana alreadyInProgress = true; 18121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 18221bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 18321bb0deb36af32339521038cdbd827f74468df4aFred Quintana 18421bb0deb36af32339521038cdbd827f74468df4aFred Quintana // do this outside since we don't want to call back into the syncContext while 18521bb0deb36af32339521038cdbd827f74468df4aFred Quintana // holding the synchronization lock 18621bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (alreadyInProgress) { 18721bb0deb36af32339521038cdbd827f74468df4aFred Quintana syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS); 18821bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 18921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 19021bb0deb36af32339521038cdbd827f74468df4aFred Quintana 191fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams @Override 19221bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void cancelSync(ISyncContext syncContext) { 1930c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana // synchronize to make sure that mSyncThreads doesn't change between when we 19421bb0deb36af32339521038cdbd827f74468df4aFred Quintana // check it and when we use it 1950c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana SyncThread info = null; 1963cff76aaa893049d02467a231d477e86a0f80daaFred Quintana synchronized (mSyncThreadLock) { 1970c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana for (SyncThread current : mSyncThreads.values()) { 1980c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana if (current.mSyncContext.getSyncContextBinder() == syncContext.asBinder()) { 1990c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana info = current; 2000c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana break; 2010c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } 2020c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } 203d5e4fdc8a4743abc0d9fe3cb952a78f9ad078c6bFred Quintana } 2040c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana if (info != null) { 2050c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana if (mAllowParallelSyncs) { 2060c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana onSyncCanceled(info); 2070c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } else { 2080c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana onSyncCanceled(); 2090c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } 21021bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 21121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 212e7424ffdafb0c18f753f383ebfb121ea5ebf582bFred Quintana 213e7424ffdafb0c18f753f383ebfb121ea5ebf582bFred Quintana public void initialize(Account account, String authority) throws RemoteException { 214e7424ffdafb0c18f753f383ebfb121ea5ebf582bFred Quintana Bundle extras = new Bundle(); 215e7424ffdafb0c18f753f383ebfb121ea5ebf582bFred Quintana extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); 216e7424ffdafb0c18f753f383ebfb121ea5ebf582bFred Quintana startSync(null, authority, account, extras); 217e7424ffdafb0c18f753f383ebfb121ea5ebf582bFred Quintana } 21821bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 21921bb0deb36af32339521038cdbd827f74468df4aFred Quintana 22021bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 221f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * The thread that invokes {@link AbstractThreadedSyncAdapter#onPerformSync}. It also acquires 222f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * the provider for this sync before calling onPerformSync and releases it afterwards. Cancel 223f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * this thread in order to cancel the sync. 22421bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 22521bb0deb36af32339521038cdbd827f74468df4aFred Quintana private class SyncThread extends Thread { 22621bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final SyncContext mSyncContext; 22721bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final String mAuthority; 22821bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Account mAccount; 22921bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Bundle mExtras; 2300c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana private final Account mThreadsKey; 23121bb0deb36af32339521038cdbd827f74468df4aFred Quintana 23221bb0deb36af32339521038cdbd827f74468df4aFred Quintana private SyncThread(String name, SyncContext syncContext, String authority, 23321bb0deb36af32339521038cdbd827f74468df4aFred Quintana Account account, Bundle extras) { 23421bb0deb36af32339521038cdbd827f74468df4aFred Quintana super(name); 23521bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncContext = syncContext; 23621bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAuthority = authority; 23721bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAccount = account; 23821bb0deb36af32339521038cdbd827f74468df4aFred Quintana mExtras = extras; 2390c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana mThreadsKey = toSyncKey(account); 24021bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 24121bb0deb36af32339521038cdbd827f74468df4aFred Quintana 24209b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadler @Override 24321bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void run() { 24475d797c2e78d53f49d05b518adb14fd57e0c785cFred Quintana Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 24575d797c2e78d53f49d05b518adb14fd57e0c785cFred Quintana 24609b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadler // Trace this sync instance. Note, conceptually this should be in 24709b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadler // SyncStorageEngine.insertStartSyncEvent(), but the trace functions require unique 24809b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadler // threads in order to track overlapping operations, so we'll do it here for now. 24909b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadler Trace.traceBegin(Trace.TRACE_TAG_SYNC_MANAGER, mAuthority); 25009b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadler 25121bb0deb36af32339521038cdbd827f74468df4aFred Quintana SyncResult syncResult = new SyncResult(); 25221bb0deb36af32339521038cdbd827f74468df4aFred Quintana ContentProviderClient provider = null; 25321bb0deb36af32339521038cdbd827f74468df4aFred Quintana try { 2549257ec05639ac1a529c81ba94cc631b1fa5f49d9Alon Albert if (isCanceled()) { 2559257ec05639ac1a529c81ba94cc631b1fa5f49d9Alon Albert return; 2569257ec05639ac1a529c81ba94cc631b1fa5f49d9Alon Albert } 25721bb0deb36af32339521038cdbd827f74468df4aFred Quintana provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority); 25821bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (provider != null) { 259f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana AbstractThreadedSyncAdapter.this.onPerformSync(mAccount, mExtras, 26021bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAuthority, provider, syncResult); 26121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } else { 262f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana syncResult.databaseError = true; 26321bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 26421bb0deb36af32339521038cdbd827f74468df4aFred Quintana } finally { 26509b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadler Trace.traceEnd(Trace.TRACE_TAG_SYNC_MANAGER); 26609b45a3ad96379b4181d32f8391f63e9c57dc316Andy Stadler 26721bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (provider != null) { 26821bb0deb36af32339521038cdbd827f74468df4aFred Quintana provider.release(); 26921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 27021bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (!isCanceled()) { 27121bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncContext.onFinished(syncResult); 27221bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 27321bb0deb36af32339521038cdbd827f74468df4aFred Quintana // synchronize so that the assignment will be seen by other threads 2740c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana // that also synchronize accesses to mSyncThreads 2753cff76aaa893049d02467a231d477e86a0f80daaFred Quintana synchronized (mSyncThreadLock) { 2760c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana mSyncThreads.remove(mThreadsKey); 27721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 27821bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 27921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 28021bb0deb36af32339521038cdbd827f74468df4aFred Quintana 28121bb0deb36af32339521038cdbd827f74468df4aFred Quintana private boolean isCanceled() { 28221bb0deb36af32339521038cdbd827f74468df4aFred Quintana return Thread.currentThread().isInterrupted(); 28321bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 28421bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 28521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 28621bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 287f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * @return a reference to the IBinder of the SyncAdapter service. 28821bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 289f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana public final IBinder getSyncAdapterBinder() { 290f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana return mISyncAdapterImpl.asBinder(); 29121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 29221bb0deb36af32339521038cdbd827f74468df4aFred Quintana 29321bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 29421bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Perform a sync for this account. SyncAdapter-specific parameters may 29521bb0deb36af32339521038cdbd827f74468df4aFred Quintana * be specified in extras, which is guaranteed to not be null. Invocations 29621bb0deb36af32339521038cdbd827f74468df4aFred Quintana * of this method are guaranteed to be serialized. 29721bb0deb36af32339521038cdbd827f74468df4aFred Quintana * 29821bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param account the account that should be synced 29921bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param extras SyncAdapter-specific parameters 30021bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param authority the authority of this sync request 30121bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param provider a ContentProviderClient that points to the ContentProvider for this 30221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * authority 30321bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param syncResult SyncAdapter-specific parameters 30421bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 305f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana public abstract void onPerformSync(Account account, Bundle extras, 30621bb0deb36af32339521038cdbd827f74468df4aFred Quintana String authority, ContentProviderClient provider, SyncResult syncResult); 307274dc9d35fdf5d0464f74071a9a8f14e497d4d5fFred Quintana 308274dc9d35fdf5d0464f74071a9a8f14e497d4d5fFred Quintana /** 309274dc9d35fdf5d0464f74071a9a8f14e497d4d5fFred Quintana * Indicates that a sync operation has been canceled. This will be invoked on a separate 310274dc9d35fdf5d0464f74071a9a8f14e497d4d5fFred Quintana * thread than the sync thread and so you must consider the multi-threaded implications 311274dc9d35fdf5d0464f74071a9a8f14e497d4d5fFred Quintana * of the work that you do in this method. 3120c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * <p> 3130c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * This will only be invoked when the SyncAdapter indicates that it doesn't support 3140c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * parallel syncs. 315274dc9d35fdf5d0464f74071a9a8f14e497d4d5fFred Quintana */ 316d5e4fdc8a4743abc0d9fe3cb952a78f9ad078c6bFred Quintana public void onSyncCanceled() { 317d5e4fdc8a4743abc0d9fe3cb952a78f9ad078c6bFred Quintana final SyncThread syncThread; 318d5e4fdc8a4743abc0d9fe3cb952a78f9ad078c6bFred Quintana synchronized (mSyncThreadLock) { 3190c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana syncThread = mSyncThreads.get(null); 320d5e4fdc8a4743abc0d9fe3cb952a78f9ad078c6bFred Quintana } 321d5e4fdc8a4743abc0d9fe3cb952a78f9ad078c6bFred Quintana if (syncThread != null) { 322d5e4fdc8a4743abc0d9fe3cb952a78f9ad078c6bFred Quintana syncThread.interrupt(); 323d5e4fdc8a4743abc0d9fe3cb952a78f9ad078c6bFred Quintana } 324274dc9d35fdf5d0464f74071a9a8f14e497d4d5fFred Quintana } 3250c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana 3260c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana /** 3270c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * Indicates that a sync operation has been canceled. This will be invoked on a separate 3280c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * thread than the sync thread and so you must consider the multi-threaded implications 3290c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * of the work that you do in this method. 3300c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * <p> 3310c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * This will only be invoked when the SyncAdapter indicates that it does support 3320c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * parallel syncs. 3330c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana * @param thread the Thread of the sync that is to be canceled. 3340c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana */ 3350c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana public void onSyncCanceled(Thread thread) { 3360c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana thread.interrupt(); 3370c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana } 338f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana} 339