Loading core/java/android/content/SyncAdapterNew.java→core/java/android/content/AbstractThreadedSyncAdapter.java +176 −0 Original line number Diff line number Diff line /* * Copyright (C) 2006 The Android Open Source Project * 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. Loading @@ -16,39 +16,59 @@ package android.content; import android.os.*; import android.os.Process; 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 SyncAdapterNew { private static final String TAG = "SyncAdapter"; public abstract class AbstractThreadedSyncAdapter { private final Context mContext; private final String mAuthority; 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; public SyncAdapterNew(Context context, String authority) { /** * Creates an {@link AbstractThreadedSyncAdapter}. * @param context the {@link Context} that this is running within. */ public AbstractThreadedSyncAdapter(Context context) { mContext = context; mAuthority = authority; mISyncAdapterImpl = new ISyncAdapterImpl(); mNumSyncStarts = new AtomicInteger(0); mSyncThread = null; } class Transport extends ISyncAdapter.Stub { private final AtomicInteger mNumSyncStarts = new AtomicInteger(0); private volatile Thread mSyncThread; class ISyncAdapterImpl extends ISyncAdapter.Stub { public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) { final SyncContext syncContextClient = new SyncContext(syncContext); public void startSync(ISyncContext syncContext, Account account, Bundle extras) { 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 Thread( new SyncRunnable(new SyncContext(syncContext), account, extras), "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet()); mSyncThread = new SyncThread( "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), syncContextClient, authority, account, extras); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mSyncThread.start(); alreadyInProgress = false; Loading @@ -57,30 +77,41 @@ public abstract class SyncAdapterNew { } } // do this outside since we don't want to call back into the syncContext while // holding the synchronization lock if (alreadyInProgress) { try { syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS); } catch (RemoteException e) { // don't care if the caller is no longer around } syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS); } } public void cancelSync() { 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) { if (mSyncThread != null && mSyncThread.mSyncContext.getISyncContext() == syncContext) { mSyncThread.interrupt(); } } } } private class SyncRunnable implements Runnable { /** * 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 SyncRunnable(SyncContext syncContext, Account account, Bundle extras) { private SyncThread(String name, SyncContext syncContext, String authority, Account account, Bundle extras) { super(name); mSyncContext = syncContext; mAuthority = authority; mAccount = account; mExtras = extras; } Loading @@ -91,11 +122,16 @@ public abstract class SyncAdapterNew { } SyncResult syncResult = new SyncResult(); ContentProviderClient provider = mAuthority != null ? mContext.getContentResolver().acquireContentProviderClient(mAuthority) : null; ContentProviderClient provider = null; try { SyncAdapterNew.this.performSync(mAccount, mExtras, provider, syncResult); 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(); Loading @@ -103,23 +139,24 @@ public abstract class SyncAdapterNew { 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(); } } } Transport mTransport = new Transport(); /** * Get the Transport object. * @return a reference to the ISyncAdapter interface into this SyncAdapter implementation. */ public final ISyncAdapter getISyncAdapter() { return mTransport; return mISyncAdapterImpl; } /** Loading @@ -129,7 +166,11 @@ public abstract class SyncAdapterNew { * * @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, ContentProviderClient provider, SyncResult syncResult); String authority, ContentProviderClient provider, SyncResult syncResult); } No newline at end of file core/java/android/content/ISyncAdapter.aidl +5 −2 Original line number Diff line number Diff line Loading @@ -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); } core/java/android/content/SyncAdapter.java +2 −2 Original line number Diff line number Diff line Loading @@ -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(); } } Loading core/java/android/content/SyncManager.java +4 −11 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; /** Loading Loading @@ -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 } Loading Loading @@ -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); Loading Loading @@ -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 } Loading Loading
core/java/android/content/SyncAdapterNew.java→core/java/android/content/AbstractThreadedSyncAdapter.java +176 −0 Original line number Diff line number Diff line /* * Copyright (C) 2006 The Android Open Source Project * 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. Loading @@ -16,39 +16,59 @@ package android.content; import android.os.*; import android.os.Process; 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 SyncAdapterNew { private static final String TAG = "SyncAdapter"; public abstract class AbstractThreadedSyncAdapter { private final Context mContext; private final String mAuthority; 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; public SyncAdapterNew(Context context, String authority) { /** * Creates an {@link AbstractThreadedSyncAdapter}. * @param context the {@link Context} that this is running within. */ public AbstractThreadedSyncAdapter(Context context) { mContext = context; mAuthority = authority; mISyncAdapterImpl = new ISyncAdapterImpl(); mNumSyncStarts = new AtomicInteger(0); mSyncThread = null; } class Transport extends ISyncAdapter.Stub { private final AtomicInteger mNumSyncStarts = new AtomicInteger(0); private volatile Thread mSyncThread; class ISyncAdapterImpl extends ISyncAdapter.Stub { public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) { final SyncContext syncContextClient = new SyncContext(syncContext); public void startSync(ISyncContext syncContext, Account account, Bundle extras) { 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 Thread( new SyncRunnable(new SyncContext(syncContext), account, extras), "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet()); mSyncThread = new SyncThread( "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), syncContextClient, authority, account, extras); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); mSyncThread.start(); alreadyInProgress = false; Loading @@ -57,30 +77,41 @@ public abstract class SyncAdapterNew { } } // do this outside since we don't want to call back into the syncContext while // holding the synchronization lock if (alreadyInProgress) { try { syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS); } catch (RemoteException e) { // don't care if the caller is no longer around } syncContextClient.onFinished(SyncResult.ALREADY_IN_PROGRESS); } } public void cancelSync() { 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) { if (mSyncThread != null && mSyncThread.mSyncContext.getISyncContext() == syncContext) { mSyncThread.interrupt(); } } } } private class SyncRunnable implements Runnable { /** * 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 SyncRunnable(SyncContext syncContext, Account account, Bundle extras) { private SyncThread(String name, SyncContext syncContext, String authority, Account account, Bundle extras) { super(name); mSyncContext = syncContext; mAuthority = authority; mAccount = account; mExtras = extras; } Loading @@ -91,11 +122,16 @@ public abstract class SyncAdapterNew { } SyncResult syncResult = new SyncResult(); ContentProviderClient provider = mAuthority != null ? mContext.getContentResolver().acquireContentProviderClient(mAuthority) : null; ContentProviderClient provider = null; try { SyncAdapterNew.this.performSync(mAccount, mExtras, provider, syncResult); 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(); Loading @@ -103,23 +139,24 @@ public abstract class SyncAdapterNew { 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(); } } } Transport mTransport = new Transport(); /** * Get the Transport object. * @return a reference to the ISyncAdapter interface into this SyncAdapter implementation. */ public final ISyncAdapter getISyncAdapter() { return mTransport; return mISyncAdapterImpl; } /** Loading @@ -129,7 +166,11 @@ public abstract class SyncAdapterNew { * * @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, ContentProviderClient provider, SyncResult syncResult); String authority, ContentProviderClient provider, SyncResult syncResult); } No newline at end of file
core/java/android/content/ISyncAdapter.aidl +5 −2 Original line number Diff line number Diff line Loading @@ -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); }
core/java/android/content/SyncAdapter.java +2 −2 Original line number Diff line number Diff line Loading @@ -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(); } } Loading
core/java/android/content/SyncManager.java +4 −11 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; /** Loading Loading @@ -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 } Loading Loading @@ -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); Loading Loading @@ -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 } Loading