读书人

阅读材料。 暂存放着读一上。

发布时间: 2012-08-25 10:06:20 作者: rapoo

阅读材料。。 暂存,放着读一下。。

http://hi-android.info/src/android/content/SyncManager.java.html

?

??SyncManager.java?
/* * Copyright (C) 2008 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 com.android.internal.R;import com.android.internal.util.ArrayUtils;import android.accounts.Account;import android.accounts.AccountManager;import android.accounts.OnAccountsUpdateListener;import android.app.AlarmManager;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.content.pm.ApplicationInfo;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.content.pm.RegisteredServicesCache;import android.content.pm.ProviderInfo;import android.content.pm.RegisteredServicesCacheListener;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.os.IBinder;import android.os.Looper;import android.os.Message;import android.os.PowerManager;import android.os.Process;import android.os.RemoteException;import android.os.SystemClock;import android.os.SystemProperties;import android.os.WorkSource;import android.provider.Settings;import android.text.format.DateUtils;import android.text.format.Time;import android.util.EventLog;import android.util.Log;import android.util.Pair;import java.io.FileDescriptor;import java.io.PrintWriter;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Random;import java.util.Collection;import java.util.concurrent.CountDownLatch;/** * @hide */public class SyncManager implements OnAccountsUpdateListener {    private static final String TAG = "SyncManager";    /** Delay a sync due to local changes this long. In milliseconds */    private static final long LOCAL_SYNC_DELAY;    /**     * If a sync takes longer than this and the sync queue is not empty then we will     * cancel it and add it back to the end of the sync queue. In milliseconds.     */    private static final long MAX_TIME_PER_SYNC;    static {        String localSyncDelayString = SystemProperties.get("sync.local_sync_delay");        long localSyncDelay = 30 * 1000; // 30 seconds        if (localSyncDelayString != null) {            try {                localSyncDelay = Long.parseLong(localSyncDelayString);            } catch (NumberFormatException nfe) {                // ignore, use default            }        }        LOCAL_SYNC_DELAY = localSyncDelay;        String maxTimePerSyncString = SystemProperties.get("sync.max_time_per_sync");        long maxTimePerSync = 5 * 60 * 1000; // 5 minutes        if (maxTimePerSyncString != null) {            try {                maxTimePerSync = Long.parseLong(maxTimePerSyncString);            } catch (NumberFormatException nfe) {                // ignore, use default            }        }        MAX_TIME_PER_SYNC = maxTimePerSync;    }    private static final long SYNC_NOTIFICATION_DELAY = 30 * 1000; // 30 seconds    /**     * When retrying a sync for the first time use this delay. After that     * the retry time will double until it reached MAX_SYNC_RETRY_TIME.     * In milliseconds.     */    private static final long INITIAL_SYNC_RETRY_TIME_IN_MS = 30 * 1000; // 30 seconds    /**     * Default the max sync retry time to this value.     */    private static final long DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60; // one hour    /**     * How long to wait before retrying a sync that failed due to one already being in progress.     */    private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;    /**     * An error notification is sent if sync of any of the providers has been failing for this long.     */    private static final long ERROR_NOTIFICATION_DELAY_MS = 1000 * 60 * 10; // 10 minutes    private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000;    private static final String SYNC_WAKE_LOCK = "*sync*";    private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";    private Context mContext;    private volatile Account[] mAccounts = INITIAL_ACCOUNTS_ARRAY;    volatile private PowerManager.WakeLock mSyncWakeLock;    volatile private PowerManager.WakeLock mHandleAlarmWakeLock;    volatile private boolean mDataConnectionIsConnected = false;    volatile private boolean mStorageIsLow = false;    private final NotificationManager mNotificationMgr;    private AlarmManager mAlarmService = null;    private final SyncStorageEngine mSyncStorageEngine;    public final SyncQueue mSyncQueue;    private ActiveSyncContext mActiveSyncContext = null;    // set if the sync error indicator should be reported.    private boolean mNeedSyncErrorNotification = false;    // set if the sync active indicator should be reported    private boolean mNeedSyncActiveNotification = false;    private final PendingIntent mSyncAlarmIntent;    // Synchronized on "this". Instead of using this directly one should instead call    // its accessor, getConnManager().    private ConnectivityManager mConnManagerDoNotUseDirectly;    private final SyncAdaptersCache mSyncAdapters;    private BroadcastReceiver mStorageIntentReceiver =            new BroadcastReceiver() {                public void onReceive(Context context, Intent intent) {                    String action = intent.getAction();                    if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {                        if (Log.isLoggable(TAG, Log.VERBOSE)) {                            Log.v(TAG, "Internal storage is low.");                        }                        mStorageIsLow = true;                        cancelActiveSync(null /* any account */, null /* any authority */);                    } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {                        if (Log.isLoggable(TAG, Log.VERBOSE)) {                            Log.v(TAG, "Internal storage is ok.");                        }                        mStorageIsLow = false;                        sendCheckAlarmsMessage();                    }                }            };    private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {        public void onReceive(Context context, Intent intent) {            mSyncHandler.onBootCompleted();        }    };    private BroadcastReceiver mBackgroundDataSettingChanged = new BroadcastReceiver() {        public void onReceive(Context context, Intent intent) {            if (getConnectivityManager().getBackgroundDataSetting()) {                scheduleSync(null /* account */, null /* authority */, new Bundle(), 0 /* delay */,                        false /* onlyThoseWithUnknownSyncableState */);            }        }    };    private static final Account[] INITIAL_ACCOUNTS_ARRAY = new Account[0];    public void onAccountsUpdated(Account[] accounts) {        // remember if this was the first time this was called after an update        final boolean justBootedUp = mAccounts == INITIAL_ACCOUNTS_ARRAY;        mAccounts = accounts;        // if a sync is in progress yet it is no longer in the accounts list,        // cancel it        ActiveSyncContext activeSyncContext = mActiveSyncContext;        if (activeSyncContext != null) {            if (!ArrayUtils.contains(accounts, activeSyncContext.mSyncOperation.account)) {                Log.d(TAG, "canceling sync since the account has been removed");                sendSyncFinishedOrCanceledMessage(activeSyncContext,                        null /* no result since this is a cancel */);            }        }        // we must do this since we don't bother scheduling alarms when        // the accounts are not set yet        sendCheckAlarmsMessage();        if (mBootCompleted) {            mSyncStorageEngine.doDatabaseCleanup(accounts);        }        if (accounts.length > 0) {            // If this is the first time this was called after a bootup then            // the accounts haven't really changed, instead they were just loaded            // from the AccountManager. Otherwise at least one of the accounts            // has a change.            //            // If there was a real account change then force a sync of all accounts.            // This is a bit of overkill, but at least it will end up retrying syncs            // that failed due to an authentication failure and thus will recover if the            // account change was a password update.            //            // If this was the bootup case then don't sync everything, instead only            // sync those that have an unknown syncable state, which will give them            // a chance to set their syncable state.            boolean onlyThoseWithUnkownSyncableState = justBootedUp;            scheduleSync(null, null, null, 0 /* no delay */, onlyThoseWithUnkownSyncableState);        }    }    private BroadcastReceiver mConnectivityIntentReceiver =            new BroadcastReceiver() {        public void onReceive(Context context, Intent intent) {            NetworkInfo networkInfo =                    intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);            NetworkInfo.State state = (networkInfo == null ? NetworkInfo.State.UNKNOWN :                    networkInfo.getState());            if (Log.isLoggable(TAG, Log.VERBOSE)) {                Log.v(TAG, "received connectivity action.  network info: " + networkInfo);            }            // only pay attention to the CONNECTED and DISCONNECTED states.            // if connected, we are connected.            // if disconnected, we may not be connected.  in some cases, we may be connected on            // a different network.            // e.g., if switching from GPRS to WiFi, we may receive the CONNECTED to WiFi and            // DISCONNECTED for GPRS in any order.  if we receive the CONNECTED first, and then            // a DISCONNECTED, we want to make sure we set mDataConnectionIsConnected to true            // since we still have a WiFi connection.            switch (state) {                case CONNECTED:                    mDataConnectionIsConnected = true;                    break;                case DISCONNECTED:                    if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {                        mDataConnectionIsConnected = false;                    } else {                        mDataConnectionIsConnected = true;                    }                    break;                default:                    // ignore the rest of the states -- leave our boolean alone.            }            if (mDataConnectionIsConnected) {                sendCheckAlarmsMessage();            }        }    };    private BroadcastReceiver mShutdownIntentReceiver =            new BroadcastReceiver() {        public void onReceive(Context context, Intent intent) {            Log.w(TAG, "Writing sync state before shutdown...");            getSyncStorageEngine().writeAllState();        }    };    private static final String ACTION_SYNC_ALARM = "android.content.syncmanager.SYNC_ALARM";    private final SyncHandler mSyncHandler;    private final Handler mMainHandler;    private volatile boolean mBootCompleted = false;    private ConnectivityManager getConnectivityManager() {        synchronized (this) {            if (mConnManagerDoNotUseDirectly == null) {                mConnManagerDoNotUseDirectly = (ConnectivityManager)mContext.getSystemService(                        Context.CONNECTIVITY_SERVICE);            }            return mConnManagerDoNotUseDirectly;        }    }    public SyncManager(Context context, boolean factoryTest) {        // Initialize the SyncStorageEngine first, before registering observers        // and creating threads and so on; it may fail if the disk is full.        SyncStorageEngine.init(context);        mSyncStorageEngine = SyncStorageEngine.getSingleton();        mSyncQueue = new SyncQueue(mSyncStorageEngine);        mContext = context;        HandlerThread syncThread = new HandlerThread("SyncHandlerThread",                Process.THREAD_PRIORITY_BACKGROUND);        syncThread.start();        mSyncHandler = new SyncHandler(syncThread.getLooper());        mMainHandler = new Handler(mContext.getMainLooper());        mSyncAdapters = new SyncAdaptersCache(mContext);        mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {            public void onServiceChanged(SyncAdapterType type, boolean removed) {                if (!removed) {                    scheduleSync(null, type.authority, null, 0 /* no delay */,                            false /* onlyThoseWithUnkownSyncableState */);                }            }        }, mSyncHandler);        mSyncAlarmIntent = PendingIntent.getBroadcast(                mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);        IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);        context.registerReceiver(mConnectivityIntentReceiver, intentFilter);        if (!factoryTest) {            intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);            context.registerReceiver(mBootCompletedReceiver, intentFilter);        }        intentFilter = new IntentFilter(ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);        context.registerReceiver(mBackgroundDataSettingChanged, intentFilter);        intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);        intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);        context.registerReceiver(mStorageIntentReceiver, intentFilter);        intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);        intentFilter.setPriority(100);        context.registerReceiver(mShutdownIntentReceiver, intentFilter);        if (!factoryTest) {            mNotificationMgr = (NotificationManager)                context.getSystemService(Context.NOTIFICATION_SERVICE);            context.registerReceiver(new SyncAlarmIntentReceiver(),                    new IntentFilter(ACTION_SYNC_ALARM));        } else {            mNotificationMgr = null;        }        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);        mSyncWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, SYNC_WAKE_LOCK);        mSyncWakeLock.setReferenceCounted(false);        // This WakeLock is used to ensure that we stay awake between the time that we receive        // a sync alarm notification and when we finish processing it. We need to do this        // because we don't do the work in the alarm handler, rather we do it in a message        // handler.        mHandleAlarmWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,                HANDLE_SYNC_ALARM_WAKE_LOCK);        mHandleAlarmWakeLock.setReferenceCounted(false);        mSyncStorageEngine.addStatusChangeListener(                ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() {            public void onStatusChanged(int which) {                // force the sync loop to run if the settings change                sendCheckAlarmsMessage();            }        });        if (!factoryTest) {            AccountManager.get(mContext).addOnAccountsUpdatedListener(SyncManager.this,                mSyncHandler, false /* updateImmediately */);            // do this synchronously to ensure we have the accounts before this call returns            onAccountsUpdated(AccountManager.get(mContext).getAccounts());        }    }    /**     * Return a random value v that satisfies minValue <= v < maxValue. The difference between     * maxValue and minValue must be less than Integer.MAX_VALUE.     */    private long jitterize(long minValue, long maxValue) {        Random random = new Random(SystemClock.elapsedRealtime());        long spread = maxValue - minValue;        if (spread > Integer.MAX_VALUE) {            throw new IllegalArgumentException("the difference between the maxValue and the "                    + "minValue must be less than " + Integer.MAX_VALUE);        }        return minValue + random.nextInt((int)spread);    }    public SyncStorageEngine getSyncStorageEngine() {        return mSyncStorageEngine;    }    private void ensureAlarmService() {        if (mAlarmService == null) {            mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);        }    }    private void initializeSyncAdapter(Account account, String authority) {        if (Log.isLoggable(TAG, Log.VERBOSE)) {            Log.v(TAG, "initializeSyncAdapter: " + account + ", authority " + authority);        }        SyncAdapterType syncAdapterType = SyncAdapterType.newKey(authority, account.type);        RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =                mSyncAdapters.getServiceInfo(syncAdapterType);        if (syncAdapterInfo == null) {            Log.w(TAG, "can't find a sync adapter for " + syncAdapterType + ", removing");            mSyncStorageEngine.removeAuthority(account, authority);            return;        }        Intent intent = new Intent();        intent.setAction("android.content.SyncAdapter");        intent.setComponent(syncAdapterInfo.componentName);        if (!mContext.bindService(intent, new InitializerServiceConnection(account, authority, mContext,                mMainHandler),                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND)) {            Log.w(TAG, "initializeSyncAdapter: failed to bind to " + intent);        }    }    private static class InitializerServiceConnection implements ServiceConnection {        private final Account mAccount;        private final String mAuthority;        private final Handler mHandler;        private volatile Context mContext;        private volatile boolean mInitialized;        public InitializerServiceConnection(Account account, String authority, Context context,                Handler handler) {            mAccount = account;            mAuthority = authority;            mContext = context;            mHandler = handler;            mInitialized = false;        }        public void onServiceConnected(ComponentName name, IBinder service) {            try {                if (!mInitialized) {                    mInitialized = true;                    if (Log.isLoggable(TAG, Log.VERBOSE)) {                        Log.v(TAG, "calling initialize: " + mAccount + ", authority " + mAuthority);                    }                    ISyncAdapter.Stub.asInterface(service).initialize(mAccount, mAuthority);                }            } catch (RemoteException e) {                // doesn't matter, we will retry again later                Log.d(TAG, "error while initializing: " + mAccount + ", authority " + mAuthority,                        e);            } finally {                // give the sync adapter time to initialize before unbinding from it                // TODO: change this API to not rely on this timing, http://b/2500805                mHandler.postDelayed(new Runnable() {                    public void run() {                        if (mContext != null) {                            mContext.unbindService(InitializerServiceConnection.this);                            mContext = null;                        }                    }                }, INITIALIZATION_UNBIND_DELAY_MS);            }        }        public void onServiceDisconnected(ComponentName name) {            if (mContext != null) {                mContext.unbindService(InitializerServiceConnection.this);                mContext = null;            }        }    }    /**     * Initiate a sync. This can start a sync for all providers     * (pass null to url, set onlyTicklable to false), only those     * providers that are marked as ticklable (pass null to url,     * set onlyTicklable to true), or a specific provider (set url     * to the content url of the provider).     *     * <p>If the ContentResolver.SYNC_EXTRAS_UPLOAD boolean in extras is     * true then initiate a sync that just checks for local changes to send     * to the server, otherwise initiate a sync that first gets any     * changes from the server before sending local changes back to     * the server.     *     * <p>If a specific provider is being synced (the url is non-null)     * then the extras can contain SyncAdapter-specific information     * to control what gets synced (e.g. which specific feed to sync).     *     * <p>You'll start getting callbacks after this.     *     * @param requestedAccount the account to sync, may be null to signify all accounts     * @param requestedAuthority the authority to sync, may be null to indicate all authorities     * @param extras a Map of SyncAdapter-specific information to control*          syncs of a specific provider. Can be null. Is ignored*          if the url is null.     * @param delay how many milliseconds in the future to wait before performing this     * @param onlyThoseWithUnkownSyncableState     */    public void scheduleSync(Account requestedAccount, String requestedAuthority,            Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) {        boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);        final boolean backgroundDataUsageAllowed = !mBootCompleted ||                getConnectivityManager().getBackgroundDataSetting();        if (extras == null) extras = new Bundle();        Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);        if (expedited) {            delay = -1; // this means schedule at the front of the queue        }        Account[] accounts;        if (requestedAccount != null) {            accounts = new Account[]{requestedAccount};        } else {            // if the accounts aren't configured yet then we can't support an account-less            // sync request            accounts = mAccounts;            if (accounts.length == 0) {                if (isLoggable) {                    Log.v(TAG, "scheduleSync: no accounts configured, dropping");                }                return;            }        }        final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);        final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);        if (manualSync) {            extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);            extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);        }        final boolean ignoreSettings =                extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);        int source;        if (uploadOnly) {            source = SyncStorageEngine.SOURCE_LOCAL;        } else if (manualSync) {            source = SyncStorageEngine.SOURCE_USER;        } else if (requestedAuthority == null) {            source = SyncStorageEngine.SOURCE_POLL;        } else {            // this isn't strictly server, since arbitrary callers can (and do) request            // a non-forced two-way sync on a specific url            source = SyncStorageEngine.SOURCE_SERVER;        }        // Compile a list of authorities that have sync adapters.        // For each authority sync each account that matches a sync adapter.        final HashSet<String> syncableAuthorities = new HashSet<String>();        for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :                mSyncAdapters.getAllServices()) {            syncableAuthorities.add(syncAdapter.type.authority);        }        // if the url was specified then replace the list of authorities with just this authority        // or clear it if this authority isn't syncable        fo 

读书人网 >移动开发

热点推荐