AbstractThreadedSyncAdapter.java revision f038004f4a5e4fab18df9c87573ba1e82790c30f
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; 226fd7385f56b129b49164f606d23771a39507f772Ken Shirriffimport android.os.NetStat; 23f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintanaimport android.os.IBinder; 246fd7385f56b129b49164f606d23771a39507f772Ken Shirriffimport android.util.EventLog; 2521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 2621bb0deb36af32339521038cdbd827f74468df4aFred Quintanaimport java.util.concurrent.atomic.AtomicInteger; 2721bb0deb36af32339521038cdbd827f74468df4aFred Quintana 2821bb0deb36af32339521038cdbd827f74468df4aFred Quintana/** 2921bb0deb36af32339521038cdbd827f74468df4aFred Quintana * An abstract implementation of a SyncAdapter that spawns a thread to invoke a sync operation. 3021bb0deb36af32339521038cdbd827f74468df4aFred Quintana * If a sync operation is already in progress when a startSync() request is received then an error 3121bb0deb36af32339521038cdbd827f74468df4aFred Quintana * will be returned to the new request and the existing request will be allowed to continue. 3221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * When a startSync() is received and there is no sync operation in progress then a thread 33f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * will be started to run the operation and {@link #onPerformSync} will be invoked on that thread. 3421bb0deb36af32339521038cdbd827f74468df4aFred Quintana * If a cancelSync() is received that matches an existing sync operation then the thread 3521bb0deb36af32339521038cdbd827f74468df4aFred Quintana * that is running that sync operation will be interrupted, which will indicate to the thread 3621bb0deb36af32339521038cdbd827f74468df4aFred Quintana * that the sync has been canceled. 3721bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 3821bb0deb36af32339521038cdbd827f74468df4aFred Quintanapublic abstract class AbstractThreadedSyncAdapter { 3921bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Context mContext; 4021bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final AtomicInteger mNumSyncStarts; 4121bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final ISyncAdapterImpl mISyncAdapterImpl; 4221bb0deb36af32339521038cdbd827f74468df4aFred Quintana 433cff76aaa893049d02467a231d477e86a0f80daaFred Quintana // all accesses to this member variable must be synchronized on mSyncThreadLock 4421bb0deb36af32339521038cdbd827f74468df4aFred Quintana private SyncThread mSyncThread; 453cff76aaa893049d02467a231d477e86a0f80daaFred Quintana private final Object mSyncThreadLock = new Object(); 4621bb0deb36af32339521038cdbd827f74468df4aFred Quintana 4721bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** Kernel event log tag. Also listed in data/etc/event-log-tags. */ 4821bb0deb36af32339521038cdbd827f74468df4aFred Quintana public static final int LOG_SYNC_DETAILS = 2743; 496fd7385f56b129b49164f606d23771a39507f772Ken Shirriff private static final String TAG = "Sync"; 504a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana private final boolean mAutoInitialize; 5121bb0deb36af32339521038cdbd827f74468df4aFred Quintana 5221bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 5321bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Creates an {@link AbstractThreadedSyncAdapter}. 544a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * @param context the {@link android.content.Context} that this is running within. 554a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * @param autoInitialize if true then sync requests that have 564a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by 574a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link AbstractThreadedSyncAdapter} by calling 584a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it 594a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana * is currently set to <0. 6021bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 614a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana public AbstractThreadedSyncAdapter(Context context, boolean autoInitialize) { 6221bb0deb36af32339521038cdbd827f74468df4aFred Quintana mContext = context; 6321bb0deb36af32339521038cdbd827f74468df4aFred Quintana mISyncAdapterImpl = new ISyncAdapterImpl(); 6421bb0deb36af32339521038cdbd827f74468df4aFred Quintana mNumSyncStarts = new AtomicInteger(0); 6521bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread = null; 664a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana mAutoInitialize = autoInitialize; 6721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 6821bb0deb36af32339521038cdbd827f74468df4aFred Quintana 69c298a8518a8fd73a303132c7db241f10eb46c5b6Fred Quintana public Context getContext() { 70c298a8518a8fd73a303132c7db241f10eb46c5b6Fred Quintana return mContext; 71c298a8518a8fd73a303132c7db241f10eb46c5b6Fred Quintana } 72c298a8518a8fd73a303132c7db241f10eb46c5b6Fred Quintana 73f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana private class ISyncAdapterImpl extends ISyncAdapter.Stub { 7421bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void startSync(ISyncContext syncContext, String authority, Account account, 7521bb0deb36af32339521038cdbd827f74468df4aFred Quintana Bundle extras) { 7621bb0deb36af32339521038cdbd827f74468df4aFred Quintana final SyncContext syncContextClient = new SyncContext(syncContext); 7721bb0deb36af32339521038cdbd827f74468df4aFred Quintana 7821bb0deb36af32339521038cdbd827f74468df4aFred Quintana boolean alreadyInProgress; 7921bb0deb36af32339521038cdbd827f74468df4aFred Quintana // synchronize to make sure that mSyncThread doesn't change between when we 8021bb0deb36af32339521038cdbd827f74468df4aFred Quintana // check it and when we use it 813cff76aaa893049d02467a231d477e86a0f80daaFred Quintana synchronized (mSyncThreadLock) { 8221bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (mSyncThread == null) { 834a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana if (mAutoInitialize 844a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana && extras != null 854a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) { 864a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana if (ContentResolver.getIsSyncable(account, authority) < 0) { 874a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana ContentResolver.setIsSyncable(account, authority, 1); 884a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana } 894a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana syncContextClient.onFinished(new SyncResult()); 904a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana return; 914a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana } 9221bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread = new SyncThread( 9321bb0deb36af32339521038cdbd827f74468df4aFred Quintana "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), 9421bb0deb36af32339521038cdbd827f74468df4aFred Quintana syncContextClient, authority, account, extras); 9521bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread.start(); 9621bb0deb36af32339521038cdbd827f74468df4aFred Quintana alreadyInProgress = false; 9721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } else { 9821bb0deb36af32339521038cdbd827f74468df4aFred Quintana alreadyInProgress = true; 9921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 10021bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 10121bb0deb36af32339521038cdbd827f74468df4aFred Quintana 10221bb0deb36af32339521038cdbd827f74468df4aFred Quintana // do this outside since we don't want to call back into the syncContext while 10321bb0deb36af32339521038cdbd827f74468df4aFred Quintana // holding the synchronization lock 10421bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (alreadyInProgress) { 10521bb0deb36af32339521038cdbd827f74468df4aFred Quintana syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS); 10621bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 10721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 10821bb0deb36af32339521038cdbd827f74468df4aFred Quintana 10921bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void cancelSync(ISyncContext syncContext) { 11021bb0deb36af32339521038cdbd827f74468df4aFred Quintana // synchronize to make sure that mSyncThread doesn't change between when we 11121bb0deb36af32339521038cdbd827f74468df4aFred Quintana // check it and when we use it 1123cff76aaa893049d02467a231d477e86a0f80daaFred Quintana synchronized (mSyncThreadLock) { 11321bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (mSyncThread != null 114f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana && mSyncThread.mSyncContext.getSyncContextBinder() 115b19b4c711f51ef63f16727026b31216f9b4d5818Fred Quintana == syncContext.asBinder()) { 116fcb14322f4afaf87b816ee120ad1e2f217b1350eFred Quintana mSyncThread.interrupt(); 11721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 11821bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 11921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 12021bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 12121bb0deb36af32339521038cdbd827f74468df4aFred Quintana 12221bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 123f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * The thread that invokes {@link AbstractThreadedSyncAdapter#onPerformSync}. It also acquires 124f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * the provider for this sync before calling onPerformSync and releases it afterwards. Cancel 125f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * this thread in order to cancel the sync. 12621bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 12721bb0deb36af32339521038cdbd827f74468df4aFred Quintana private class SyncThread extends Thread { 12821bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final SyncContext mSyncContext; 12921bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final String mAuthority; 13021bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Account mAccount; 13121bb0deb36af32339521038cdbd827f74468df4aFred Quintana private final Bundle mExtras; 1326fd7385f56b129b49164f606d23771a39507f772Ken Shirriff private long mInitialTxBytes; 1336fd7385f56b129b49164f606d23771a39507f772Ken Shirriff private long mInitialRxBytes; 13421bb0deb36af32339521038cdbd827f74468df4aFred Quintana 13521bb0deb36af32339521038cdbd827f74468df4aFred Quintana private SyncThread(String name, SyncContext syncContext, String authority, 13621bb0deb36af32339521038cdbd827f74468df4aFred Quintana Account account, Bundle extras) { 13721bb0deb36af32339521038cdbd827f74468df4aFred Quintana super(name); 13821bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncContext = syncContext; 13921bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAuthority = authority; 14021bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAccount = account; 14121bb0deb36af32339521038cdbd827f74468df4aFred Quintana mExtras = extras; 14221bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 14321bb0deb36af32339521038cdbd827f74468df4aFred Quintana 14421bb0deb36af32339521038cdbd827f74468df4aFred Quintana public void run() { 14575d797c2e78d53f49d05b518adb14fd57e0c785cFred Quintana Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 14675d797c2e78d53f49d05b518adb14fd57e0c785cFred Quintana 14721bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (isCanceled()) { 14821bb0deb36af32339521038cdbd827f74468df4aFred Quintana return; 14921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 15021bb0deb36af32339521038cdbd827f74468df4aFred Quintana 15121bb0deb36af32339521038cdbd827f74468df4aFred Quintana SyncResult syncResult = new SyncResult(); 1526fd7385f56b129b49164f606d23771a39507f772Ken Shirriff int uid = Process.myUid(); 1536fd7385f56b129b49164f606d23771a39507f772Ken Shirriff mInitialTxBytes = NetStat.getUidTxBytes(uid); 1546fd7385f56b129b49164f606d23771a39507f772Ken Shirriff mInitialRxBytes = NetStat.getUidRxBytes(uid); 15521bb0deb36af32339521038cdbd827f74468df4aFred Quintana ContentProviderClient provider = null; 15621bb0deb36af32339521038cdbd827f74468df4aFred Quintana try { 15721bb0deb36af32339521038cdbd827f74468df4aFred Quintana provider = mContext.getContentResolver().acquireContentProviderClient(mAuthority); 15821bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (provider != null) { 159f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana AbstractThreadedSyncAdapter.this.onPerformSync(mAccount, mExtras, 16021bb0deb36af32339521038cdbd827f74468df4aFred Quintana mAuthority, provider, syncResult); 16121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } else { 162f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana syncResult.databaseError = true; 16321bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 16421bb0deb36af32339521038cdbd827f74468df4aFred Quintana } finally { 16521bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (provider != null) { 16621bb0deb36af32339521038cdbd827f74468df4aFred Quintana provider.release(); 16721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 16821bb0deb36af32339521038cdbd827f74468df4aFred Quintana if (!isCanceled()) { 16921bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncContext.onFinished(syncResult); 17021bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 171f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana onLogSyncDetails(NetStat.getUidTxBytes(uid) - mInitialTxBytes, 1726fd7385f56b129b49164f606d23771a39507f772Ken Shirriff NetStat.getUidRxBytes(uid) - mInitialRxBytes, syncResult); 17321bb0deb36af32339521038cdbd827f74468df4aFred Quintana // synchronize so that the assignment will be seen by other threads 17421bb0deb36af32339521038cdbd827f74468df4aFred Quintana // that also synchronize accesses to mSyncThread 1753cff76aaa893049d02467a231d477e86a0f80daaFred Quintana synchronized (mSyncThreadLock) { 17621bb0deb36af32339521038cdbd827f74468df4aFred Quintana mSyncThread = null; 17721bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 17821bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 17921bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 18021bb0deb36af32339521038cdbd827f74468df4aFred Quintana 18121bb0deb36af32339521038cdbd827f74468df4aFred Quintana private boolean isCanceled() { 18221bb0deb36af32339521038cdbd827f74468df4aFred Quintana return Thread.currentThread().isInterrupted(); 18321bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 18421bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 18521bb0deb36af32339521038cdbd827f74468df4aFred Quintana 18621bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 187f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * @return a reference to the IBinder of the SyncAdapter service. 18821bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 189f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana public final IBinder getSyncAdapterBinder() { 190f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana return mISyncAdapterImpl.asBinder(); 19121bb0deb36af32339521038cdbd827f74468df4aFred Quintana } 19221bb0deb36af32339521038cdbd827f74468df4aFred Quintana 19321bb0deb36af32339521038cdbd827f74468df4aFred Quintana /** 19421bb0deb36af32339521038cdbd827f74468df4aFred Quintana * Perform a sync for this account. SyncAdapter-specific parameters may 19521bb0deb36af32339521038cdbd827f74468df4aFred Quintana * be specified in extras, which is guaranteed to not be null. Invocations 19621bb0deb36af32339521038cdbd827f74468df4aFred Quintana * of this method are guaranteed to be serialized. 19721bb0deb36af32339521038cdbd827f74468df4aFred Quintana * 19821bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param account the account that should be synced 19921bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param extras SyncAdapter-specific parameters 20021bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param authority the authority of this sync request 20121bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param provider a ContentProviderClient that points to the ContentProvider for this 20221bb0deb36af32339521038cdbd827f74468df4aFred Quintana * authority 20321bb0deb36af32339521038cdbd827f74468df4aFred Quintana * @param syncResult SyncAdapter-specific parameters 20421bb0deb36af32339521038cdbd827f74468df4aFred Quintana */ 205f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana public abstract void onPerformSync(Account account, Bundle extras, 20621bb0deb36af32339521038cdbd827f74468df4aFred Quintana String authority, ContentProviderClient provider, SyncResult syncResult); 2076fd7385f56b129b49164f606d23771a39507f772Ken Shirriff 2086fd7385f56b129b49164f606d23771a39507f772Ken Shirriff /** 2096fd7385f56b129b49164f606d23771a39507f772Ken Shirriff * Logs details on the sync. 2106fd7385f56b129b49164f606d23771a39507f772Ken Shirriff * Normally this will be overridden by a subclass that will provide 2116fd7385f56b129b49164f606d23771a39507f772Ken Shirriff * provider-specific details. 2126fd7385f56b129b49164f606d23771a39507f772Ken Shirriff * 2136fd7385f56b129b49164f606d23771a39507f772Ken Shirriff * @param bytesSent number of bytes the sync sent over the network 2146fd7385f56b129b49164f606d23771a39507f772Ken Shirriff * @param bytesReceived number of bytes the sync received over the network 2156fd7385f56b129b49164f606d23771a39507f772Ken Shirriff * @param result The SyncResult object holding info on the sync 216f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana * @hide 2176fd7385f56b129b49164f606d23771a39507f772Ken Shirriff */ 218f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana protected void onLogSyncDetails(long bytesSent, long bytesReceived, SyncResult result) { 2196fd7385f56b129b49164f606d23771a39507f772Ken Shirriff EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, ""); 2206fd7385f56b129b49164f606d23771a39507f772Ken Shirriff } 221f038004f4a5e4fab18df9c87573ba1e82790c30fFred Quintana} 222