19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.content;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport android.accounts.Account;
20f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasaniimport android.accounts.AccountAndUser;
21d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintanaimport android.accounts.AccountManager;
2204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport android.accounts.AccountManagerService;
2333e446941722b0e31a453399e92e0e82697f05aaFred Quintanaimport android.app.ActivityManager;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.AlarmManager;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.Notification;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.NotificationManager;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.PendingIntent;
2804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport android.content.SyncStorageEngine.OnSyncRequestListener;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.ApplicationInfo;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
31c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintanaimport android.content.pm.ProviderInfo;
32e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.content.pm.RegisteredServicesCache;
3344037e6c41f8167bf5ac51fcb684ad28b20073ceFred Quintanaimport android.content.pm.RegisteredServicesCacheListener;
34e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.content.pm.ResolveInfo;
3504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport android.content.pm.UserInfo;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.ConnectivityManager;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.NetworkInfo;
38e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.Bundle;
39e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.Handler;
40e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.HandlerThread;
41e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.IBinder;
42e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.Looper;
43e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.Message;
44e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.PowerManager;
45e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.Process;
46e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.RemoteException;
47e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.SystemClock;
48e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport android.os.SystemProperties;
49f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
50258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport android.os.UserManager;
517e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackbornimport android.os.WorkSource;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.format.DateUtils;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.format.Time;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.EventLog;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
57307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintanaimport android.util.Pair;
58e4996bbd519a088927180c2eed2941fe59a4cd40Jeff Sharkeyimport android.util.Slog;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
608e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albertimport com.android.internal.R;
618b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
626ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport com.android.internal.util.IndentingPrintWriter;
638e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albertimport com.google.android.collect.Lists;
648e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albertimport com.google.android.collect.Maps;
658e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albertimport com.google.android.collect.Sets;
668e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
70e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport java.util.Arrays;
71918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintanaimport java.util.Collection;
72918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintanaimport java.util.Collections;
73e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport java.util.Comparator;
74b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintanaimport java.util.HashMap;
75231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackbornimport java.util.HashSet;
76918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintanaimport java.util.Iterator;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
78e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albertimport java.util.Map;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Random;
808e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albertimport java.util.Set;
81e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintanaimport java.util.concurrent.CountDownLatch;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
866ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeypublic class SyncManager {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "SyncManager";
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Delay a sync due to local changes this long. In milliseconds */
9044ee0f03f99b3eea8bf3d3e7f63ad0553623f426Debajit Ghosh    private static final long LOCAL_SYNC_DELAY;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If a sync takes longer than this and the sync queue is not empty then we will
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * cancel it and add it back to the end of the sync queue. In milliseconds.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9644ee0f03f99b3eea8bf3d3e7f63ad0553623f426Debajit Ghosh    private static final long MAX_TIME_PER_SYNC;
9744ee0f03f99b3eea8bf3d3e7f63ad0553623f426Debajit Ghosh
9844ee0f03f99b3eea8bf3d3e7f63ad0553623f426Debajit Ghosh    static {
9933e446941722b0e31a453399e92e0e82697f05aaFred Quintana        final boolean isLargeRAM = ActivityManager.isLargeRAM();
10033e446941722b0e31a453399e92e0e82697f05aaFred Quintana        int defaultMaxInitSyncs = isLargeRAM ? 5 : 2;
10133e446941722b0e31a453399e92e0e82697f05aaFred Quintana        int defaultMaxRegularSyncs = isLargeRAM ? 2 : 1;
10233e446941722b0e31a453399e92e0e82697f05aaFred Quintana        MAX_SIMULTANEOUS_INITIALIZATION_SYNCS =
10333e446941722b0e31a453399e92e0e82697f05aaFred Quintana                SystemProperties.getInt("sync.max_init_syncs", defaultMaxInitSyncs);
10433e446941722b0e31a453399e92e0e82697f05aaFred Quintana        MAX_SIMULTANEOUS_REGULAR_SYNCS =
10533e446941722b0e31a453399e92e0e82697f05aaFred Quintana                SystemProperties.getInt("sync.max_regular_syncs", defaultMaxRegularSyncs);
106918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        LOCAL_SYNC_DELAY =
107918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                SystemProperties.getLong("sync.local_sync_delay", 30 * 1000 /* 30 seconds */);
108918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        MAX_TIME_PER_SYNC =
109918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                SystemProperties.getLong("sync.max_time_per_sync", 5 * 60 * 1000 /* 5 minutes */);
110918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        SYNC_NOTIFICATION_DELAY =
111918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                SystemProperties.getLong("sync.notification_delay", 30 * 1000 /* 30 seconds */);
11244ee0f03f99b3eea8bf3d3e7f63ad0553623f426Debajit Ghosh    }
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
114918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    private static final long SYNC_NOTIFICATION_DELAY;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * When retrying a sync for the first time use this delay. After that
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the retry time will double until it reached MAX_SYNC_RETRY_TIME.
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * In milliseconds.
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long INITIAL_SYNC_RETRY_TIME_IN_MS = 30 * 1000; // 30 seconds
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Default the max sync retry time to this value.
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS = 60 * 60; // one hour
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1298570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana     * How long to wait before retrying a sync that failed due to one already being in progress.
1308570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana     */
1318570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana    private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
1328570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana
1333ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana    private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000;
1343ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana
135e746f03c6c8b8d0897d322ab524d545ace200fcdDianne Hackborn    private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*";
1367e9f4eb2608148436cef36c9969bf8a599b39e72Dianne Hackborn    private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
137918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
138918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
139918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    private static final int MAX_SIMULTANEOUS_REGULAR_SYNCS;
140918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    private static final int MAX_SIMULTANEOUS_INITIALIZATION_SYNCS;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
14504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
1466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    // TODO: add better locking around mRunningAccounts
1476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    private volatile AccountAndUser[] mRunningAccounts = INITIAL_ACCOUNTS_ARRAY;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
150918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    volatile private PowerManager.WakeLock mSyncManagerWakeLock;
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    volatile private boolean mDataConnectionIsConnected = false;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    volatile private boolean mStorageIsLow = false;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final NotificationManager mNotificationMgr;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AlarmManager mAlarmService = null;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1570c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana    private SyncStorageEngine mSyncStorageEngine;
158a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey
1598b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @GuardedBy("mSyncQueue")
160a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey    private final SyncQueue mSyncQueue;
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1620c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana    protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList();
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // set if the sync active indicator should be reported
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mNeedSyncActiveNotification = false;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final PendingIntent mSyncAlarmIntent;
168f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana    // Synchronized on "this". Instead of using this directly one should instead call
169f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana    // its accessor, getConnManager().
170f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana    private ConnectivityManager mConnManagerDoNotUseDirectly;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1720c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana    protected SyncAdaptersCache mSyncAdapters;
173718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BroadcastReceiver mStorageIntentReceiver =
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            new BroadcastReceiver() {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                public void onReceive(Context context, Intent intent) {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    String action = intent.getAction();
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Log.v(TAG, "Internal storage is low.");
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mStorageIsLow = true;
183f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn                        cancelActiveSync(null /* any account */, UserHandle.USER_ALL,
18404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                null /* any authority */);
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Log.v(TAG, "Internal storage is ok.");
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mStorageIsLow = false;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sendCheckAlarmsMessage();
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            };
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
195603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
196603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onReceive(Context context, Intent intent) {
197e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            mSyncHandler.onBootCompleted();
198d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        }
199d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    };
200603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
201600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana    private BroadcastReceiver mBackgroundDataSettingChanged = new BroadcastReceiver() {
202600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana        public void onReceive(Context context, Intent intent) {
203600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana            if (getConnectivityManager().getBackgroundDataSetting()) {
204f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn                scheduleSync(null /* account */, UserHandle.USER_ALL, null /* authority */,
20504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        new Bundle(), 0 /* delay */,
206600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana                        false /* onlyThoseWithUnknownSyncableState */);
207600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana            }
208600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana        }
209600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana    };
210600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana
211d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani    private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
212d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani        public void onReceive(Context context, Intent intent) {
2136ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            updateRunningAccounts();
2146ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
2156ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            // Kick off sync for everyone, since this was a radical account change
2166ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            scheduleSync(null, UserHandle.USER_ALL, null, null, 0 /* no delay */, false);
217d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani        }
218d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani    };
219d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani
220b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana    private final PowerManager mPowerManager;
221b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana
22269d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma    // Use this as a random offset to seed all periodic syncs
22369d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma    private int mSyncRandomOffsetMillis;
22469d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma
2259535c915b61c43d7b4bdb2b35d53774cfb16bfbbAmith Yamasani    private final UserManager mUserManager;
226258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani
227918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    private static final long SYNC_ALARM_TIMEOUT_MIN = 30 * 1000; // 30 seconds
228918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    private static final long SYNC_ALARM_TIMEOUT_MAX = 2 * 60 * 60 * 1000; // two hours
229918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
230258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani    private List<UserInfo> getAllUsers() {
2319535c915b61c43d7b4bdb2b35d53774cfb16bfbbAmith Yamasani        return mUserManager.getUsers();
23204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
23304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
23404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private boolean containsAccountAndUser(AccountAndUser[] accounts, Account account, int userId) {
23504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        boolean found = false;
23604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        for (int i = 0; i < accounts.length; i++) {
23704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            if (accounts[i].userId == userId
23804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    && accounts[i].account.equals(account)) {
23904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                found = true;
24004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                break;
24104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
24204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
24304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        return found;
24404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
24504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
2466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    public void updateRunningAccounts() {
2476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
24804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
2498f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey        if (mBootCompleted) {
2508f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey            doDatabaseCleanup();
2518f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey        }
2528f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey
253918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
2546ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            if (!containsAccountAndUser(mRunningAccounts,
25504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    currentSyncContext.mSyncOperation.account,
25604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    currentSyncContext.mSyncOperation.userId)) {
2576ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                Log.d(TAG, "canceling sync since the account is no longer running");
258918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                sendSyncFinishedOrCanceledMessage(currentSyncContext,
259d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana                        null /* no result since this is a cancel */);
260603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
261603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
262d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana
263d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        // we must do this since we don't bother scheduling alarms when
264d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        // the accounts are not set yet
265d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        sendCheckAlarmsMessage();
266d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana    }
267603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
2688f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey    private void doDatabaseCleanup() {
269db6a14cc85cede0769735fdac4da70766989a3ceAmith Yamasani        for (UserInfo user : mUserManager.getUsers(true)) {
270db6a14cc85cede0769735fdac4da70766989a3ceAmith Yamasani            // Skip any partially created/removed users
271db6a14cc85cede0769735fdac4da70766989a3ceAmith Yamasani            if (user.partial) continue;
2728f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey            Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(user.id);
2738f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey            mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
2748f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey        }
2758f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey    }
2768f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BroadcastReceiver mConnectivityIntentReceiver =
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            new BroadcastReceiver() {
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
280ed1d253573a238fd53d27def24d298314f24d425Alon Albert            final boolean wasConnected = mDataConnectionIsConnected;
281ed1d253573a238fd53d27def24d298314f24d425Alon Albert
282ed1d253573a238fd53d27def24d298314f24d425Alon Albert            // don't use the intent to figure out if network is connected, just check
283ed1d253573a238fd53d27def24d298314f24d425Alon Albert            // ConnectivityManager directly.
2841bad83adf011ff4e6a6474c62b287d119ba43b3eAlon Albert            mDataConnectionIsConnected = readDataConnectionState();
285ed1d253573a238fd53d27def24d298314f24d425Alon Albert            if (mDataConnectionIsConnected) {
286ed1d253573a238fd53d27def24d298314f24d425Alon Albert                if (!wasConnected) {
287ed1d253573a238fd53d27def24d298314f24d425Alon Albert                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
288ed1d253573a238fd53d27def24d298314f24d425Alon Albert                        Log.v(TAG, "Reconnection detected: clearing all backoffs");
289ed1d253573a238fd53d27def24d298314f24d425Alon Albert                    }
290ed1d253573a238fd53d27def24d298314f24d425Alon Albert                    mSyncStorageEngine.clearAllBackoffs(mSyncQueue);
291ed1d253573a238fd53d27def24d298314f24d425Alon Albert                }
292ed1d253573a238fd53d27def24d298314f24d425Alon Albert                sendCheckAlarmsMessage();
293ed1d253573a238fd53d27def24d298314f24d425Alon Albert            }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2971bad83adf011ff4e6a6474c62b287d119ba43b3eAlon Albert    private boolean readDataConnectionState() {
298ed1d253573a238fd53d27def24d298314f24d425Alon Albert        NetworkInfo networkInfo = getConnectivityManager().getActiveNetworkInfo();
299ed1d253573a238fd53d27def24d298314f24d425Alon Albert        return (networkInfo != null) && networkInfo.isConnected();
300ed1d253573a238fd53d27def24d298314f24d425Alon Albert    }
301ed1d253573a238fd53d27def24d298314f24d425Alon Albert
30255280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn    private BroadcastReceiver mShutdownIntentReceiver =
30355280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn            new BroadcastReceiver() {
30455280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn        public void onReceive(Context context, Intent intent) {
30555280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn            Log.w(TAG, "Writing sync state before shutdown...");
30655280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn            getSyncStorageEngine().writeAllState();
30755280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn        }
30855280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn    };
30955280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn
310135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
311135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        @Override
312135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        public void onReceive(Context context, Intent intent) {
3138e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert            String action = intent.getAction();
3146ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
3156ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            if (userId == UserHandle.USER_NULL) return;
3166ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
3178e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert            if (Intent.ACTION_USER_REMOVED.equals(action)) {
3186ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                onUserRemoved(userId);
3196ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            } else if (Intent.ACTION_USER_STARTING.equals(action)) {
3206ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                onUserStarting(userId);
3216ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
3226ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                onUserStopping(userId);
3238e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert            }
324135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
325135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    };
326135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ACTION_SYNC_ALARM = "android.content.syncmanager.SYNC_ALARM";
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final SyncHandler mSyncHandler;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3304f9cfc5c52c8b40975c1bc2829efa46b4bddb03fFred Quintana    private volatile boolean mBootCompleted = false;
3314f9cfc5c52c8b40975c1bc2829efa46b4bddb03fFred Quintana
332f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana    private ConnectivityManager getConnectivityManager() {
333f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana        synchronized (this) {
334f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana            if (mConnManagerDoNotUseDirectly == null) {
335f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana                mConnManagerDoNotUseDirectly = (ConnectivityManager)mContext.getSystemService(
336f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana                        Context.CONNECTIVITY_SERVICE);
337f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana            }
338f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana            return mConnManagerDoNotUseDirectly;
339f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana        }
340f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana    }
341f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana
342e4996bbd519a088927180c2eed2941fe59a4cd40Jeff Sharkey    /**
343e4996bbd519a088927180c2eed2941fe59a4cd40Jeff Sharkey     * Should only be created after {@link ContentService#systemReady()} so that
344e4996bbd519a088927180c2eed2941fe59a4cd40Jeff Sharkey     * {@link PackageManager} is ready to query.
345e4996bbd519a088927180c2eed2941fe59a4cd40Jeff Sharkey     */
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public SyncManager(Context context, boolean factoryTest) {
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Initialize the SyncStorageEngine first, before registering observers
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // and creating threads and so on; it may fail if the disk is full.
3490c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana        mContext = context;
3509535c915b61c43d7b4bdb2b35d53774cfb16bfbbAmith Yamasani
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SyncStorageEngine.init(context);
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSyncStorageEngine = SyncStorageEngine.getSingleton();
35304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
35404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            public void onSyncRequest(Account account, int userId, String authority,
35504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    Bundle extras) {
35604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                scheduleSync(account, userId, authority, extras, 0, false);
35704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
35804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        });
35904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
3600c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana        mSyncAdapters = new SyncAdaptersCache(mContext);
3610c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana        mSyncQueue = new SyncQueue(mSyncStorageEngine, mSyncAdapters);
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
363307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        HandlerThread syncThread = new HandlerThread("SyncHandlerThread",
364307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                Process.THREAD_PRIORITY_BACKGROUND);
365307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        syncThread.start();
366307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        mSyncHandler = new SyncHandler(syncThread.getLooper());
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36844037e6c41f8167bf5ac51fcb684ad28b20073ceFred Quintana        mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
3696ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            @Override
3706ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
37144037e6c41f8167bf5ac51fcb684ad28b20073ceFred Quintana                if (!removed) {
372f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn                    scheduleSync(null, UserHandle.USER_ALL, type.authority, null, 0 /* no delay */,
37344037e6c41f8167bf5ac51fcb684ad28b20073ceFred Quintana                            false /* onlyThoseWithUnkownSyncableState */);
37444037e6c41f8167bf5ac51fcb684ad28b20073ceFred Quintana                }
37544037e6c41f8167bf5ac51fcb684ad28b20073ceFred Quintana            }
37644037e6c41f8167bf5ac51fcb684ad28b20073ceFred Quintana        }, mSyncHandler);
377718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSyncAlarmIntent = PendingIntent.getBroadcast(
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
384e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        if (!factoryTest) {
385e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
386e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            context.registerReceiver(mBootCompletedReceiver, intentFilter);
387e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        }
388603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
389600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana        intentFilter = new IntentFilter(ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
390600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana        context.registerReceiver(mBackgroundDataSettingChanged, intentFilter);
391600dde04ee07b740dc119c879cf096b5d697ec32Fred Quintana
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        context.registerReceiver(mStorageIntentReceiver, intentFilter);
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39655280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn        intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
39755280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn        intentFilter.setPriority(100);
39855280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn        context.registerReceiver(mShutdownIntentReceiver, intentFilter);
39955280a91884b9256e8db6af6a09f28b3feeaa9d8Dianne Hackborn
400135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        intentFilter = new IntentFilter();
401135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
4026ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        intentFilter.addAction(Intent.ACTION_USER_STARTING);
4036ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        intentFilter.addAction(Intent.ACTION_USER_STOPPING);
4048e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert        mContext.registerReceiverAsUser(
4058e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
406135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!factoryTest) {
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNotificationMgr = (NotificationManager)
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                context.getSystemService(Context.NOTIFICATION_SERVICE);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            context.registerReceiver(new SyncAlarmIntentReceiver(),
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    new IntentFilter(ACTION_SYNC_ALARM));
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNotificationMgr = null;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
415b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana        mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
4169535c915b61c43d7b4bdb2b35d53774cfb16bfbbAmith Yamasani        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This WakeLock is used to ensure that we stay awake between the time that we receive
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // a sync alarm notification and when we finish processing it. We need to do this
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // because we don't do the work in the alarm handler, rather we do it in a message
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // handler.
422b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana        mHandleAlarmWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                HANDLE_SYNC_ALARM_WAKE_LOCK);
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandleAlarmWakeLock.setReferenceCounted(false);
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
426918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        // This WakeLock is used to ensure that we stay awake while running the sync loop
427918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        // message handler. Normally we will hold a sync adapter wake lock while it is being
428918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        // synced but during the execution of the sync loop it might finish a sync for
429918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        // one sync adapter before starting the sync for the other sync adapter and we
430918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        // don't want the device to go to sleep during that window.
431918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        mSyncManagerWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
432918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                SYNC_LOOP_WAKE_LOCK);
433918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        mSyncManagerWakeLock.setReferenceCounted(false);
434918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
435231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mSyncStorageEngine.addStatusChangeListener(
436ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, new ISyncStatusObserver.Stub() {
437231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            public void onStatusChanged(int which) {
438231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                // force the sync loop to run if the settings change
439231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                sendCheckAlarmsMessage();
440231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
441231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        });
442e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana
443e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        if (!factoryTest) {
444d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani            // Register for account list updates for all users
445d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani            mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
446d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani                    UserHandle.ALL,
447d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani                    new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
448d648a605e8249219ce60ac93e074758ebb6fc4abAmith Yamasani                    null, null);
449e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        }
45069d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma
45169d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma        // Pick a random second in a day to seed all periodic syncs
45269d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma        mSyncRandomOffsetMillis = mSyncStorageEngine.getSyncRandomOffset() * 1000;
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return a random value v that satisfies minValue <= v < maxValue. The difference between
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * maxValue and minValue must be less than Integer.MAX_VALUE.
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long jitterize(long minValue, long maxValue) {
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Random random = new Random(SystemClock.elapsedRealtime());
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long spread = maxValue - minValue;
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (spread > Integer.MAX_VALUE) {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("the difference between the maxValue and the "
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + "minValue must be less than " + Integer.MAX_VALUE);
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return minValue + random.nextInt((int)spread);
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
469231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    public SyncStorageEngine getSyncStorageEngine() {
470231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return mSyncStorageEngine;
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
47244f574781545781c31db3dcf495ed08763073f75Doug Zongker
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureAlarmService() {
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mAlarmService == null) {
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Initiate a sync. This can start a sync for all providers
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (pass null to url, set onlyTicklable to false), only those
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * providers that are marked as ticklable (pass null to url,
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * set onlyTicklable to true), or a specific provider (set url
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to the content url of the provider).
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>If the ContentResolver.SYNC_EXTRAS_UPLOAD boolean in extras is
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * true then initiate a sync that just checks for local changes to send
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to the server, otherwise initiate a sync that first gets any
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * changes from the server before sending local changes back to
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the server.
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>If a specific provider is being synced (the url is non-null)
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * then the extras can contain SyncAdapter-specific information
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to control what gets synced (e.g. which specific feed to sync).
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>You'll start getting callbacks after this.
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
498ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param requestedAccount the account to sync, may be null to signify all accounts
49904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani     * @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
50004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani     *          then all users' accounts are considered.
501ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param requestedAuthority the authority to sync, may be null to indicate all authorities
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param extras a Map of SyncAdapter-specific information to control
503918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana     *          syncs of a specific provider. Can be null. Is ignored
504918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana     *          if the url is null.
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param delay how many milliseconds in the future to wait before performing this
5064a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana     * @param onlyThoseWithUnkownSyncableState
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
50804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    public void scheduleSync(Account requestedAccount, int userId, String requestedAuthority,
5094a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana            Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) {
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
512e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        final boolean backgroundDataUsageAllowed = !mBootCompleted ||
513d2a3a8a7ba869247e6d1a8e3f72780e4841b39d6Jim Miller                getConnectivityManager().getBackgroundDataSetting();
514f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (extras == null) extras = new Bundle();
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (expedited) {
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            delay = -1; // this means schedule at the front of the queue
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
52204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        AccountAndUser[] accounts;
523f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        if (requestedAccount != null && userId != UserHandle.USER_ALL) {
52404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // if the accounts aren't configured yet then we can't support an account-less
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // sync request
5286ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            accounts = mRunningAccounts;
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (accounts.length == 0) {
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isLoggable) {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.v(TAG, "scheduleSync: no accounts configured, dropping");
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
538ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
53953bd2522ca7767f46646606123b6e2689b811850Fred Quintana        if (manualSync) {
54053bd2522ca7767f46646606123b6e2689b811850Fred Quintana            extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
54153bd2522ca7767f46646606123b6e2689b811850Fred Quintana            extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
54253bd2522ca7767f46646606123b6e2689b811850Fred Quintana        }
54353bd2522ca7767f46646606123b6e2689b811850Fred Quintana        final boolean ignoreSettings =
54453bd2522ca7767f46646606123b6e2689b811850Fred Quintana                extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int source;
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (uploadOnly) {
548231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            source = SyncStorageEngine.SOURCE_LOCAL;
549ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        } else if (manualSync) {
550231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            source = SyncStorageEngine.SOURCE_USER;
551ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        } else if (requestedAuthority == null) {
552231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            source = SyncStorageEngine.SOURCE_POLL;
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // this isn't strictly server, since arbitrary callers can (and do) request
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a non-forced two-way sync on a specific url
556231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            source = SyncStorageEngine.SOURCE_SERVER;
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5596ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        for (AccountAndUser account : accounts) {
5606ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            // Compile a list of authorities that have sync adapters.
5616ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            // For each authority sync each account that matches a sync adapter.
5626ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            final HashSet<String> syncableAuthorities = new HashSet<String>();
5636ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
5646ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                    mSyncAdapters.getAllServices(account.userId)) {
5656ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                syncableAuthorities.add(syncAdapter.type.authority);
5666ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5686ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            // if the url was specified then replace the list of authorities
5696ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            // with just this authority or clear it if this authority isn't
5706ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            // syncable
5716ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            if (requestedAuthority != null) {
5726ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
5736ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                syncableAuthorities.clear();
5746ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
5756ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            }
576718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
5776ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            for (String authority : syncableAuthorities) {
57804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                int isSyncable = mSyncStorageEngine.getIsSyncable(account.account, account.userId,
57904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        authority);
5804a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana                if (isSyncable == 0) {
5815e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                    continue;
5825e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                }
5836ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
5846ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                syncAdapterInfo = mSyncAdapters.getServiceInfo(
5856ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                        SyncAdapterType.newKey(authority, account.account.type), account.userId);
5860c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                if (syncAdapterInfo == null) {
5870c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    continue;
5880c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                }
5890c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
5900c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
5910c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                if (isSyncable < 0 && isAlwaysSyncable) {
59204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    mSyncStorageEngine.setIsSyncable(account.account, account.userId, authority, 1);
5930c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    isSyncable = 1;
5940c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                }
5950c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) {
5960c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    continue;
5970c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                }
5980c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
5990c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    continue;
6000c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                }
601f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana
6020c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                // always allow if the isSyncable state is unknown
6030c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                boolean syncAllowed =
6040c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        (isSyncable < 0)
6050c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        || ignoreSettings
60604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        || (backgroundDataUsageAllowed
60704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                && mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
60804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                && mSyncStorageEngine.getSyncAutomatically(account.account,
60904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                        account.userId, authority));
6100c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                if (!syncAllowed) {
6110c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    if (isLoggable) {
6120c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
6130c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + " is not allowed, dropping request");
6144a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana                    }
6150c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    continue;
6160c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                }
617e7424ffdafb0c18f753f383ebfb121ea5ebf582bFred Quintana
61804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                Pair<Long, Long> backoff = mSyncStorageEngine
61904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        .getBackoff(account.account, account.userId, authority);
62004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                long delayUntil = mSyncStorageEngine.getDelayUntilTime(account.account,
62104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account.userId, authority);
6220c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                final long backoffTime = backoff != null ? backoff.first : 0;
6230c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                if (isSyncable < 0) {
6240c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    Bundle newExtras = new Bundle();
6250c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
6260c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    if (isLoggable) {
6270c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        Log.v(TAG, "scheduleSync:"
6280c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + " delay " + delay
6290c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + ", source " + source
6300c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + ", account " + account
6310c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + ", authority " + authority
6320c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + ", extras " + newExtras);
633918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
6340c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    scheduleSyncOperation(
63504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            new SyncOperation(account.account, account.userId, source, authority,
63604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                    newExtras, 0, backoffTime, delayUntil, allowParallelSyncs));
6370c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                }
6380c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                if (!onlyThoseWithUnkownSyncableState) {
6390c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    if (isLoggable) {
6400c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        Log.v(TAG, "scheduleSync:"
6410c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + " delay " + delay
6420c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + ", source " + source
6430c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + ", account " + account
6440c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + ", authority " + authority
6450c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                + ", extras " + extras);
646e0616ffb741b64e3bc7a1e3ad9def3d50eee53fdFred Quintana                    }
6470c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    scheduleSyncOperation(
64804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            new SyncOperation(account.account, account.userId, source, authority,
64904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                    extras, delay, backoffTime, delayUntil, allowParallelSyncs));
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
65504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    public void scheduleLocalSync(Account account, int userId, String authority) {
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Bundle extras = new Bundle();
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
65804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        scheduleSync(account, userId, authority, extras, LOCAL_SYNC_DELAY,
6594a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana                false /* onlyThoseWithUnkownSyncableState */);
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6626ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    public SyncAdapterType[] getSyncAdapterTypes(int userId) {
6636ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
6646ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        serviceInfos = mSyncAdapters.getAllServices(userId);
665ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
666ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        int i = 0;
667ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
668ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            types[i] = serviceInfo.type;
669ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            ++i;
670ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        }
671ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        return types;
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendSyncAlarmMessage() {
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_SYNC_ALARM");
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSyncHandler.sendEmptyMessage(SyncHandler.MESSAGE_SYNC_ALARM);
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendCheckAlarmsMessage() {
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_CHECK_ALARMS");
68169d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma        mSyncHandler.removeMessages(SyncHandler.MESSAGE_CHECK_ALARMS);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSyncHandler.sendEmptyMessage(SyncHandler.MESSAGE_CHECK_ALARMS);
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SyncResult syncResult) {
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_SYNC_FINISHED");
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Message msg = mSyncHandler.obtainMessage();
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg.obj = new SyncHandlerMessagePayload(syncContext, syncResult);
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSyncHandler.sendMessage(msg);
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
69404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void sendCancelSyncsMessage(final Account account, final int userId,
69504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final String authority) {
696918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_CANCEL");
697918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        Message msg = mSyncHandler.obtainMessage();
698918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        msg.what = SyncHandler.MESSAGE_CANCEL;
699918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        msg.obj = Pair.create(account, authority);
70004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        msg.arg1 = userId;
701918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        mSyncHandler.sendMessage(msg);
702918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    }
703918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class SyncHandlerMessagePayload {
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final ActiveSyncContext activeSyncContext;
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final SyncResult syncResult;
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SyncHandlerMessagePayload(ActiveSyncContext syncContext, SyncResult syncResult) {
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.activeSyncContext = syncContext;
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.syncResult = syncResult;
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class SyncAlarmIntentReceiver extends BroadcastReceiver {
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHandleAlarmWakeLock.acquire();
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sendSyncAlarmMessage();
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7216e079a32bceb85a44da3b396f8d37e718d1421d5Alon Albert    private void clearBackoffSetting(SyncOperation op) {
72204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        mSyncStorageEngine.setBackoff(op.account, op.userId, op.authority,
7236e079a32bceb85a44da3b396f8d37e718d1421d5Alon Albert                SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
7246e079a32bceb85a44da3b396f8d37e718d1421d5Alon Albert        synchronized (mSyncQueue) {
72504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            mSyncQueue.onBackoffChanged(op.account, op.userId, op.authority, 0);
7266e079a32bceb85a44da3b396f8d37e718d1421d5Alon Albert        }
7276e079a32bceb85a44da3b396f8d37e718d1421d5Alon Albert    }
7286e079a32bceb85a44da3b396f8d37e718d1421d5Alon Albert
729307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    private void increaseBackoffSetting(SyncOperation op) {
73069d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma        // TODO: Use this function to align it to an already scheduled sync
73169d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma        //       operation in the specified window
732307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        final long now = SystemClock.elapsedRealtime();
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
734307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        final Pair<Long, Long> previousSettings =
73504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                mSyncStorageEngine.getBackoff(op.account, op.userId, op.authority);
736aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert        long newDelayInMs = -1;
737aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert        if (previousSettings != null) {
738aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert            // don't increase backoff before current backoff is expired. This will happen for op's
739aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert            // with ignoreBackoff set.
740aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert            if (now < previousSettings.first) {
741aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert                if (Log.isLoggable(TAG, Log.VERBOSE)) {
742aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert                    Log.v(TAG, "Still in backoff, do not increase it. "
743aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert                        + "Remaining: " + ((previousSettings.first - now) / 1000) + " seconds.");
744aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert                }
745aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert                return;
746aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert            }
747aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert            // Subsequent delays are the double of the previous delay
748aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert            newDelayInMs = previousSettings.second * 2;
749aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert        }
750aeeb620906d037902d0c111a2272b6efd97f377aAlon Albert        if (newDelayInMs <= 0) {
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // The initial delay is the jitterized INITIAL_SYNC_RETRY_TIME_IN_MS
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            newDelayInMs = jitterize(INITIAL_SYNC_RETRY_TIME_IN_MS,
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (long)(INITIAL_SYNC_RETRY_TIME_IN_MS * 1.1));
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Cap the delay
757625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey        long maxSyncRetryTimeInSeconds = Settings.Global.getLong(mContext.getContentResolver(),
758625239a05401bbf18b04d9874cea3f82da7c29a1Jeff Sharkey                Settings.Global.SYNC_MAX_RETRY_DELAY_IN_SECONDS,
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                DEFAULT_MAX_SYNC_RETRY_TIME_IN_SECONDS);
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
764c1ac7769d884ad54a320ab3ec6d8406801cfb420Alon Albert        final long backoff = now + newDelayInMs;
765c1ac7769d884ad54a320ab3ec6d8406801cfb420Alon Albert
76604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        mSyncStorageEngine.setBackoff(op.account, op.userId, op.authority,
767c1ac7769d884ad54a320ab3ec6d8406801cfb420Alon Albert                backoff, newDelayInMs);
768c1ac7769d884ad54a320ab3ec6d8406801cfb420Alon Albert
769c1ac7769d884ad54a320ab3ec6d8406801cfb420Alon Albert        op.backoff = backoff;
770c1ac7769d884ad54a320ab3ec6d8406801cfb420Alon Albert        op.updateEffectiveRunTime();
771c1ac7769d884ad54a320ab3ec6d8406801cfb420Alon Albert
772918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        synchronized (mSyncQueue) {
77304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            mSyncQueue.onBackoffChanged(op.account, op.userId, op.authority, backoff);
774918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        }
775307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    }
776307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
777307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    private void setDelayUntilTime(SyncOperation op, long delayUntilSeconds) {
778307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        final long delayUntil = delayUntilSeconds * 1000;
779307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        final long absoluteNow = System.currentTimeMillis();
780307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        long newDelayUntilTime;
781307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        if (delayUntil > absoluteNow) {
782307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            newDelayUntilTime = SystemClock.elapsedRealtime() + (delayUntil - absoluteNow);
783307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        } else {
784307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            newDelayUntilTime = 0;
785307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        }
78604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        mSyncStorageEngine
78704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                .setDelayUntilTime(op.account, op.userId, op.authority, newDelayUntilTime);
788918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        synchronized (mSyncQueue) {
789918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            mSyncQueue.onDelayUntilTimeChanged(op.account, op.authority, newDelayUntilTime);
790918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        }
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
794ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * Cancel the active sync if it matches the authority and account.
795ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param account limit the cancelations to syncs with this account, if non-null
796ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param authority limit the cancelations to syncs with this authority, if non-null
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
79804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    public void cancelActiveSync(Account account, int userId, String authority) {
79904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        sendCancelSyncsMessage(account, userId, authority);
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create and schedule a SyncOperation.
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param syncOperation the SyncOperation to schedule
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void scheduleSyncOperation(SyncOperation syncOperation) {
808307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        boolean queueChanged;
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mSyncQueue) {
810307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            queueChanged = mSyncQueue.add(syncOperation);
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
813307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        if (queueChanged) {
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Log.isLoggable(TAG, Log.VERBOSE)) {
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.v(TAG, "scheduleSyncOperation: enqueued " + syncOperation);
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sendCheckAlarmsMessage();
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Log.isLoggable(TAG, Log.VERBOSE)) {
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.v(TAG, "scheduleSyncOperation: dropping duplicate sync operation "
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + syncOperation);
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
827ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * Remove scheduled sync operations.
828ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param account limit the removals to operations with this account, if non-null
829ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param authority limit the removals to operations with this authority, if non-null
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
83104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    public void clearScheduledSyncOperations(Account account, int userId, String authority) {
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mSyncQueue) {
83304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            mSyncQueue.remove(account, userId, authority);
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
83504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        mSyncStorageEngine.setBackoff(account, userId, authority,
836918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
839307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana    void maybeRescheduleSync(SyncResult syncResult, SyncOperation operation) {
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isLoggable) {
842307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
84553bd2522ca7767f46646606123b6e2689b811850Fred Quintana        operation = new SyncOperation(operation);
84653bd2522ca7767f46646606123b6e2689b811850Fred Quintana
84753bd2522ca7767f46646606123b6e2689b811850Fred Quintana        // The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
84853bd2522ca7767f46646606123b6e2689b811850Fred Quintana        // request. Retries of the request will always honor the backoff, so clear the
84953bd2522ca7767f46646606123b6e2689b811850Fred Quintana        // flag in case we retry this request.
85053bd2522ca7767f46646606123b6e2689b811850Fred Quintana        if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
85153bd2522ca7767f46646606123b6e2689b811850Fred Quintana            operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
85253bd2522ca7767f46646606123b6e2689b811850Fred Quintana        }
85353bd2522ca7767f46646606123b6e2689b811850Fred Quintana
854aa7edda4719dc0accbc29ff917b4280f6b600675Fred Quintana        // If this sync aborted because the internal sync loop retried too many times then
855aa7edda4719dc0accbc29ff917b4280f6b600675Fred Quintana        //   don't reschedule. Otherwise we risk getting into a retry loop.
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If the operation succeeded to some extent then retry immediately.
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If this was a two-way sync then retry soft errors with an exponential backoff.
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If this was an upward sync then schedule a two-way sync immediately.
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Otherwise do not reschedule.
86053bd2522ca7767f46646606123b6e2689b811850Fred Quintana        if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)) {
86153bd2522ca7767f46646606123b6e2689b811850Fred Quintana            Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
862307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    + operation);
863918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        } else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)
864918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                && !syncResult.syncAlreadyInProgress) {
86553bd2522ca7767f46646606123b6e2689b811850Fred Quintana            operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
866307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
867307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    + "encountered an error: " + operation);
86853bd2522ca7767f46646606123b6e2689b811850Fred Quintana            scheduleSyncOperation(operation);
869307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana        } else if (syncResult.tooManyRetries) {
870aa7edda4719dc0accbc29ff917b4280f6b600675Fred Quintana            Log.d(TAG, "not retrying sync operation because it retried too many times: "
871307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    + operation);
872aa7edda4719dc0accbc29ff917b4280f6b600675Fred Quintana        } else if (syncResult.madeSomeProgress()) {
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isLoggable) {
874307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                Log.d(TAG, "retrying sync operation because even though it had an error "
875307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                        + "it achieved some success");
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
87753bd2522ca7767f46646606123b6e2689b811850Fred Quintana            scheduleSyncOperation(operation);
8788570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana        } else if (syncResult.syncAlreadyInProgress) {
8798570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            if (isLoggable) {
8808570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                Log.d(TAG, "retrying sync operation that failed because there was already a "
8818570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        + "sync in progress: " + operation);
8828570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            }
88304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            scheduleSyncOperation(new SyncOperation(operation.account, operation.userId,
88404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    operation.syncSource,
8858570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    operation.authority, operation.extras,
886918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000,
8870c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                    operation.backoff, operation.delayUntil, operation.allowParallelSyncs));
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (syncResult.hasSoftError()) {
889307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            if (isLoggable) {
890307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                Log.d(TAG, "retrying sync operation because it encountered a soft error: "
891307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                        + operation);
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
89353bd2522ca7767f46646606123b6e2689b811850Fred Quintana            scheduleSyncOperation(operation);
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
895307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            Log.d(TAG, "not retrying sync operation because the error is a hard error: "
896307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    + operation);
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9006ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    private void onUserStarting(int userId) {
9016eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        // Make sure that accounts we're about to use are valid
9026eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        AccountManagerService.getSingleton().validateAccounts(userId);
9036eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey
9046ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        mSyncAdapters.invalidateCache(userId);
9056ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
9066ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        updateRunningAccounts();
9076ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
908a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey        synchronized (mSyncQueue) {
909a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey            mSyncQueue.addPendingOperations(userId);
910a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey        }
9116ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
9126ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        // Schedule sync for any accounts under started user
9138f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey        final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId);
9146ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        for (Account account : accounts) {
9156ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            scheduleSync(account, userId, null, null, 0 /* no delay */,
9166ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                    true /* onlyThoseWithUnknownSyncableState */);
9176ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        }
9186ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
9196ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        sendCheckAlarmsMessage();
9206ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    }
9216ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
9226ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    private void onUserStopping(int userId) {
9236ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        updateRunningAccounts();
9246ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
9256ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        cancelActiveSync(
9266ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                null /* any account */,
9276ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                userId,
9286ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                null /* any authority */);
9298e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert    }
930135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
9316ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    private void onUserRemoved(int userId) {
9326ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        updateRunningAccounts();
9336ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
934135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        // Clean up the storage engine database
935135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
936135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        synchronized (mSyncQueue) {
937135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            mSyncQueue.removeUser(userId);
938135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
939135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    }
940135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
944eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert    class ActiveSyncContext extends ISyncContext.Stub
945eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert            implements ServiceConnection, IBinder.DeathRecipient {
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final SyncOperation mSyncOperation;
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long mHistoryRowId;
948718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        ISyncAdapter mSyncAdapter;
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long mStartTime;
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long mTimeoutStartTime;
9513ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana        boolean mBound;
952918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        final PowerManager.WakeLock mSyncWakeLock;
953918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        final int mSyncAdapterUid;
954918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        SyncInfo mSyncInfo;
955eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert        boolean mIsLinkedToDeath = false;
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
957918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        /**
958918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * Create an ActiveSyncContext for an impending sync and grab the wakelock for that
959918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * sync adapter. Since this grabs the wakelock you need to be sure to call
960918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * close() when you are done with this ActiveSyncContext, whether the sync succeeded
961918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * or not.
962918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * @param syncOperation the SyncOperation we are about to sync
963918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * @param historyRowId the row in which to record the history info for this sync
964918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * @param syncAdapterUid the UID of the application that contains the sync adapter
965918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * for this sync. This is used to attribute the wakelock hold to that application.
966918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         */
967918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
968918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                int syncAdapterUid) {
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super();
970918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            mSyncAdapterUid = syncAdapterUid;
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSyncOperation = syncOperation;
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHistoryRowId = historyRowId;
973718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            mSyncAdapter = null;
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStartTime = SystemClock.elapsedRealtime();
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTimeoutStartTime = mStartTime;
976918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            mSyncWakeLock = mSyncHandler.getSyncWakeLock(
977fdb2dca4546742803617c370c2fb823b0ab63a07Fred Quintana                    mSyncOperation.account, mSyncOperation.authority);
978918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
979918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            mSyncWakeLock.acquire();
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void sendHeartbeat() {
983307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana            // heartbeats are no longer used
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onFinished(SyncResult result) {
987918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "onFinished: " + this);
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // include "this" in the message so that the handler can ignore it if this
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ActiveSyncContext is no longer the mActiveSyncContext at message handling
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // time
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sendSyncFinishedOrCanceledMessage(this, result);
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void toString(StringBuilder sb) {
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append("startTime ").append(mStartTime)
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .append(", mTimeoutStartTime ").append(mTimeoutStartTime)
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .append(", mHistoryRowId ").append(mHistoryRowId)
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .append(", syncOperation ").append(mSyncOperation);
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1001718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        public void onServiceConnected(ComponentName name, IBinder service) {
1002718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            Message msg = mSyncHandler.obtainMessage();
1003718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
1004718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            msg.obj = new ServiceConnectionData(this, ISyncAdapter.Stub.asInterface(service));
1005718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            mSyncHandler.sendMessage(msg);
1006718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        }
1007718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
1008718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        public void onServiceDisconnected(ComponentName name) {
1009718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            Message msg = mSyncHandler.obtainMessage();
1010718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            msg.what = SyncHandler.MESSAGE_SERVICE_DISCONNECTED;
1011718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            msg.obj = new ServiceConnectionData(this, null);
1012718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            mSyncHandler.sendMessage(msg);
1013718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        }
1014718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
10154120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn        boolean bindToSyncAdapter(RegisteredServicesCache.ServiceInfo info, int userId) {
1016718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1017718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                Log.d(TAG, "bindToSyncAdapter: " + info.componentName + ", connection " + this);
1018718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            }
1019718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            Intent intent = new Intent();
1020718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            intent.setAction("android.content.SyncAdapter");
1021718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            intent.setComponent(info.componentName);
1022dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn            intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1023dd9b82c283815747b75fe4434c65e4b6c9c9b54fDianne Hackborn                    com.android.internal.R.string.sync_binding_label);
10244120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
10254120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                    mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0,
10264120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                    null, new UserHandle(userId)));
10273ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana            mBound = true;
10283ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana            final boolean bindResult = mContext.bindService(intent, this,
1029e02c88af7935c72fb90a478375e61e4a94465587Dianne Hackborn                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
103004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    | Context.BIND_ALLOW_OOM_MANAGEMENT,
103104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    mSyncOperation.userId);
10323ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana            if (!bindResult) {
10333ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana                mBound = false;
10343ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana            }
10353ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana            return bindResult;
1036718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        }
1037718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
1038918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        /**
1039918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * Performs the required cleanup, which is the releasing of the wakelock and
1040918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         * unbinding from the sync adapter (if actually bound).
1041918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana         */
10423ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana        protected void close() {
1043718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1044718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                Log.d(TAG, "unBindFromSyncAdapter: connection " + this);
1045718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            }
10463ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana            if (mBound) {
10473ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana                mBound = false;
10483ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana                mContext.unbindService(this);
10493ec4730e375689b8ad9a03fcf98ff7773d726ddaFred Quintana            }
1050918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            mSyncWakeLock.release();
1051c24ab866b0d46685f6ddd340b9c84375cf8d6831Dianne Hackborn            mSyncWakeLock.setWorkSource(null);
1052718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        }
1053718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            StringBuilder sb = new StringBuilder();
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            toString(sb);
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return sb.toString();
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1060eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert
1061eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert        @Override
1062eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert        public void binderDied() {
1063eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert            sendSyncFinishedOrCanceledMessage(this, null);
1064eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert        }
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw) {
10686ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
10696ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        dumpSyncState(ipw);
10706ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        dumpSyncHistory(ipw);
10716ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        dumpSyncAdapters(ipw);
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1074231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    static String formatTime(long time) {
1075231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        Time tobj = new Time();
1076231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        tobj.set(time);
1077231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return tobj.format("%Y-%m-%d %H:%M:%S");
1078231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
107944f574781545781c31db3dcf495ed08763073f75Doug Zongker
1080e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    protected void dumpSyncState(PrintWriter pw) {
1081231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
108204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        pw.print("auto sync: ");
108304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        List<UserInfo> users = getAllUsers();
108404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        if (users != null) {
108504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            for (UserInfo user : users) {
108604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                pw.print("u" + user.id + "="
10876ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                        + mSyncStorageEngine.getMasterSyncAutomatically(user.id) + " ");
108804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
108904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            pw.println();
109004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
1091231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print("memory low: "); pw.println(mStorageIsLow);
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10936eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
109404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
10956eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        pw.print("accounts: ");
109653bd2522ca7767f46646606123b6e2689b811850Fred Quintana        if (accounts != INITIAL_ACCOUNTS_ARRAY) {
1097231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.println(accounts.length);
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
109953bd2522ca7767f46646606123b6e2689b811850Fred Quintana            pw.println("not known yet");
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long now = SystemClock.elapsedRealtime();
1102c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        pw.print("now: "); pw.print(now);
1103c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
110469d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma        pw.print("offset: "); pw.print(DateUtils.formatElapsedTime(mSyncRandomOffsetMillis/1000));
110569d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma        pw.println(" (HH:MM:SS)");
1106231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print("uptime: "); pw.print(DateUtils.formatElapsedTime(now/1000));
1107231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                pw.println(" (HH:MM:SS)");
1108231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print("time spent syncing: ");
1109231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                pw.print(DateUtils.formatElapsedTime(
1110231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                        mSyncHandler.mSyncTimeTracker.timeSpentSyncing() / 1000));
1111231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                pw.print(" (HH:MM:SS), sync ");
1112231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                pw.print(mSyncHandler.mSyncTimeTracker.mLastWasSyncing ? "" : "not ");
1113231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                pw.println("in progress");
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSyncHandler.mAlarmScheduleTime != null) {
1115231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.print("next alarm time: "); pw.print(mSyncHandler.mAlarmScheduleTime);
1116231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    pw.print(" (");
1117231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    pw.print(DateUtils.formatElapsedTime((mSyncHandler.mAlarmScheduleTime-now)/1000));
1118231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    pw.println(" (HH:MM:SS) from now)");
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1120231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.println("no alarm is scheduled (there had better not be any pending syncs)");
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1123231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print("notification info: ");
1124e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        final StringBuilder sb = new StringBuilder();
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSyncHandler.mSyncNotificationInfo.toString(sb);
1126231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.println(sb.toString());
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1128918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        pw.println();
1129918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        pw.println("Active Syncs: " + mActiveSyncContexts.size());
1130918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        for (SyncManager.ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
1131918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            final long durationInSeconds = (now - activeSyncContext.mStartTime) / 1000;
1132918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            pw.print("  ");
1133918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            pw.print(DateUtils.formatElapsedTime(durationInSeconds));
1134918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            pw.print(" - ");
1135918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            pw.print(activeSyncContext.mSyncOperation.dump(false));
1136918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            pw.println();
1137918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        }
1138918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mSyncQueue) {
1140231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            sb.setLength(0);
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSyncQueue.dump(sb);
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1143918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        pw.println();
1144918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        pw.print(sb.toString());
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1146c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        // join the installed sync adapter with the accounts list and emit for everything
1147c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        pw.println();
1148c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        pw.println("Sync Status");
114904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        for (AccountAndUser account : accounts) {
115004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            pw.print("  Account "); pw.print(account.account.name);
115104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    pw.print(" u"); pw.print(account.userId);
115204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    pw.print(" "); pw.print(account.account.type);
1153c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.println(":");
1154c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType :
11556ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                    mSyncAdapters.getAllServices(account.userId)) {
115604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                if (!syncAdapterType.type.accountType.equals(account.account.type)) {
1157c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    continue;
1158c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                }
115944f574781545781c31db3dcf495ed08763073f75Doug Zongker
116004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                SyncStorageEngine.AuthorityInfo settings =
116104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        mSyncStorageEngine.getOrCreateAuthority(
116204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                account.account, account.userId, syncAdapterType.type.authority);
1163c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(settings);
1164c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print("    "); pw.print(settings.authority);
1165c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.println(":");
1166c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print("      settings:");
1167c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print(" " + (settings.syncable > 0
1168c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                        ? "syncable"
1169c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                        : (settings.syncable == 0 ? "not syncable" : "not initialized")));
1170c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print(", " + (settings.enabled ? "enabled" : "disabled"));
1171c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                if (settings.delayUntil > now) {
1172c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(", delay for "
1173c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                            + ((settings.delayUntil - now) / 1000) + " sec");
1174c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                }
1175c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                if (settings.backoffTime > now) {
1176c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(", backoff for "
1177c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                            + ((settings.backoffTime - now) / 1000) + " sec");
1178c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                }
1179c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                if (settings.backoffDelay > 0) {
1180c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(", the backoff increment is " + settings.backoffDelay / 1000
1181c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                                + " sec");
1182c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                }
1183c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.println();
1184c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                for (int periodicIndex = 0;
1185c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                        periodicIndex < settings.periodicSyncs.size();
1186c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                        periodicIndex++) {
1187c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    Pair<Bundle, Long> info = settings.periodicSyncs.get(periodicIndex);
1188c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    long lastPeriodicTime = status.getPeriodicSyncTime(periodicIndex);
1189c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    long nextPeriodicTime = lastPeriodicTime + info.second * 1000;
1190c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.println("      periodic period=" + info.second
1191c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                            + ", extras=" + info.first
1192c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                            + ", next=" + formatTime(nextPeriodicTime));
1193c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                }
1194c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print("      count: local="); pw.print(status.numSourceLocal);
1195c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print(" poll="); pw.print(status.numSourcePoll);
1196c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print(" periodic="); pw.print(status.numSourcePeriodic);
1197c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print(" server="); pw.print(status.numSourceServer);
1198c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print(" user="); pw.print(status.numSourceUser);
1199c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print(" total="); pw.print(status.numSyncs);
1200c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.println();
1201c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.print("      total duration: ");
1202c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                pw.println(DateUtils.formatElapsedTime(status.totalElapsedTime/1000));
1203c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                if (status.lastSuccessTime != 0) {
1204c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print("      SUCCESS: source=");
1205c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(SyncStorageEngine.SOURCES[status.lastSuccessSource]);
1206c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(" time=");
1207c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.println(formatTime(status.lastSuccessTime));
1208c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                }
1209c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                if (status.lastFailureTime != 0) {
1210c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print("      FAILURE: source=");
1211c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(SyncStorageEngine.SOURCES[
1212c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                            status.lastFailureSource]);
1213c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(" initialTime=");
1214c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(formatTime(status.initialFailureTime));
1215c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.print(" lastTime=");
1216c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    pw.println(formatTime(status.lastFailureTime));
1217dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                    int errCode = status.getLastFailureMesgAsInt(0);
1218dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                    pw.print("      message: "); pw.println(
1219dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                            getLastFailureMessage(errCode) + " (" + errCode + ")");
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1225dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio    private String getLastFailureMessage(int code) {
1226dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio        switch (code) {
1227dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            case ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS:
1228dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "sync already in progress";
1229dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1230dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            case ContentResolver.SYNC_ERROR_AUTHENTICATION:
1231dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "authentication error";
1232dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1233dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            case ContentResolver.SYNC_ERROR_IO:
1234dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "I/O error";
1235dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1236dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            case ContentResolver.SYNC_ERROR_PARSE:
1237dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "parse error";
1238dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1239dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            case ContentResolver.SYNC_ERROR_CONFLICT:
1240dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "conflict error";
1241dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1242dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            case ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS:
1243dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "too many deletions error";
1244dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1245dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            case ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES:
1246dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "too many retries error";
1247dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1248dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            case ContentResolver.SYNC_ERROR_INTERNAL:
1249dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "internal error";
1250dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1251dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio            default:
1252dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio                return "unknown";
1253dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio        }
1254dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio    }
1255dc2dd88249f5e3df672fc3c7e18f3ddfb08e02b5Fabrice Di Meglio
1256231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    private void dumpTimeSec(PrintWriter pw, long time) {
1257231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print(time/1000); pw.print('.'); pw.print((time/100)%10);
1258231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print('s');
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
126044f574781545781c31db3dcf495ed08763073f75Doug Zongker
1261231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    private void dumpDayStatistic(PrintWriter pw, SyncStorageEngine.DayStats ds) {
1262231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print("Success ("); pw.print(ds.successCount);
1263231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        if (ds.successCount > 0) {
1264231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.print(" for "); dumpTimeSec(pw, ds.successTime);
1265231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.print(" avg="); dumpTimeSec(pw, ds.successTime/ds.successCount);
1266231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
1267231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.print(") Failure ("); pw.print(ds.failureCount);
1268231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        if (ds.failureCount > 0) {
1269231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.print(" for "); dumpTimeSec(pw, ds.failureTime);
1270231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.print(" avg="); dumpTimeSec(pw, ds.failureTime/ds.failureCount);
1271231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
1272231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        pw.println(")");
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
127444f574781545781c31db3dcf495ed08763073f75Doug Zongker
1275e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    protected void dumpSyncHistory(PrintWriter pw) {
1276e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        dumpRecentHistory(pw);
1277e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        dumpDayStatistics(pw);
1278e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    }
1279e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1280e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    private void dumpRecentHistory(PrintWriter pw) {
1281e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        final ArrayList<SyncStorageEngine.SyncHistoryItem> items
1282e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                = mSyncStorageEngine.getSyncHistory();
1283e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        if (items != null && items.size() > 0) {
1284e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            final Map<String, AuthoritySyncStats> authorityMap = Maps.newHashMap();
1285e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            long totalElapsedTime = 0;
1286e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            long totalTimes = 0;
1287e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            final int N = items.size();
1288e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1289e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            int maxAuthority = 0;
1290e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            int maxAccount = 0;
1291e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            for (SyncStorageEngine.SyncHistoryItem item : items) {
1292e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                SyncStorageEngine.AuthorityInfo authority
1293e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                        = mSyncStorageEngine.getAuthority(item.authorityId);
1294e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final String authorityName;
1295e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final String accountKey;
1296e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                if (authority != null) {
1297e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    authorityName = authority.authority;
12988e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    accountKey = authority.account.name + "/" + authority.account.type
12998e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                            + " u" + authority.userId;
1300e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                } else {
1301e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    authorityName = "Unknown";
1302e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    accountKey = "Unknown";
1303e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1304e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1305e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                int length = authorityName.length();
1306e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                if (length > maxAuthority) {
1307e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    maxAuthority = length;
1308e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1309e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                length = accountKey.length();
1310e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                if (length > maxAccount) {
1311e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    maxAccount = length;
1312e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1313e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1314e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final long elapsedTime = item.elapsedTime;
1315e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                totalElapsedTime += elapsedTime;
1316e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                totalTimes++;
1317e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                AuthoritySyncStats authoritySyncStats = authorityMap.get(authorityName);
1318e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                if (authoritySyncStats == null) {
1319e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    authoritySyncStats = new AuthoritySyncStats(authorityName);
1320e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    authorityMap.put(authorityName, authoritySyncStats);
1321e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1322e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                authoritySyncStats.elapsedTime += elapsedTime;
1323e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                authoritySyncStats.times++;
1324e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final Map<String, AccountSyncStats> accountMap = authoritySyncStats.accountMap;
1325e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                AccountSyncStats accountSyncStats = accountMap.get(accountKey);
1326e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                if (accountSyncStats == null) {
1327e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    accountSyncStats = new AccountSyncStats(accountKey);
1328e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    accountMap.put(accountKey, accountSyncStats);
1329e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1330e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                accountSyncStats.elapsedTime += elapsedTime;
1331e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                accountSyncStats.times++;
1332e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1333e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            }
1334e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
133527096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert            if (totalElapsedTime > 0) {
133627096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                pw.println();
133727096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                pw.printf("Detailed Statistics (Recent history):  "
133827096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        + "%d (# of times) %ds (sync time)\n",
133927096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        totalTimes, totalElapsedTime / 1000);
134027096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert
134127096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                final List<AuthoritySyncStats> sortedAuthorities =
134227096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        new ArrayList<AuthoritySyncStats>(authorityMap.values());
134327096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                Collections.sort(sortedAuthorities, new Comparator<AuthoritySyncStats>() {
1344bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    @Override
134527096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    public int compare(AuthoritySyncStats lhs, AuthoritySyncStats rhs) {
1346bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        // reverse order
1347bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        int compare = Integer.compare(rhs.times, lhs.times);
1348bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        if (compare == 0) {
1349bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                            compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
1350e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                        }
1351bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        return compare;
1352e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    }
1353bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                });
135427096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert
135527096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                final int maxLength = Math.max(maxAuthority, maxAccount + 3);
135627096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                final int padLength = 2 + 2 + maxLength + 2 + 10 + 11;
135727096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                final char chars[] = new char[padLength];
135827096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                Arrays.fill(chars, '-');
135927096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                final String separator = new String(chars);
136027096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert
136127096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                final String authorityFormat =
136227096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        String.format("  %%-%ds: %%-9s  %%-11s\n", maxLength + 2);
136327096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                final String accountFormat =
136427096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        String.format("    %%-%ds:   %%-9s  %%-11s\n", maxLength);
136527096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert
136627096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                pw.println(separator);
136727096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                for (AuthoritySyncStats authoritySyncStats : sortedAuthorities) {
136827096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    String name = authoritySyncStats.name;
136927096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    long elapsedTime;
137027096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    int times;
137127096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    String timeStr;
137227096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    String timesStr;
137327096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert
137427096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    elapsedTime = authoritySyncStats.elapsedTime;
137527096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    times = authoritySyncStats.times;
1376bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    timeStr = String.format("%ds/%d%%",
1377bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                            elapsedTime / 1000,
1378bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                            elapsedTime * 100 / totalElapsedTime);
1379bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    timesStr = String.format("%d/%d%%",
1380bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                            times,
1381bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                            times * 100 / totalTimes);
138227096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    pw.printf(authorityFormat, name, timesStr, timeStr);
138327096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert
138427096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    final List<AccountSyncStats> sortedAccounts =
138527096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                            new ArrayList<AccountSyncStats>(
138627096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                                    authoritySyncStats.accountMap.values());
138727096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    Collections.sort(sortedAccounts, new Comparator<AccountSyncStats>() {
138827096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        @Override
138927096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        public int compare(AccountSyncStats lhs, AccountSyncStats rhs) {
139027096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                            // reverse order
139127096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                            int compare = Integer.compare(rhs.times, lhs.times);
139227096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                            if (compare == 0) {
139327096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                                compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
139427096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                            }
139527096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                            return compare;
139627096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        }
139727096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    });
139827096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    for (AccountSyncStats stats: sortedAccounts) {
139927096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        elapsedTime = stats.elapsedTime;
140027096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        times = stats.times;
140127096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        timeStr = String.format("%ds/%d%%",
140227096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                                elapsedTime / 1000,
140327096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                                elapsedTime * 100 / totalElapsedTime);
140427096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        timesStr = String.format("%d/%d%%",
140527096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                                times,
140627096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                                times * 100 / totalTimes);
140727096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                        pw.printf(accountFormat, stats.name, timesStr, timeStr);
140827096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    }
140927096822e2da828e0f41c0337cf6f0f11e5bace5Alon Albert                    pw.println(separator);
1410e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1411e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            }
1412e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1413e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            pw.println();
1414e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            pw.println("Recent Sync History");
1415e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            final String format = "  %-" + maxAccount + "s  %s\n";
1416bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert            final Map<String, Long> lastTimeMap = Maps.newHashMap();
1417bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert
1418e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            for (int i = 0; i < N; i++) {
1419e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                SyncStorageEngine.SyncHistoryItem item = items.get(i);
1420e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                SyncStorageEngine.AuthorityInfo authority
1421e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                        = mSyncStorageEngine.getAuthority(item.authorityId);
1422e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final String authorityName;
1423e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final String accountKey;
1424e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                if (authority != null) {
1425e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    authorityName = authority.authority;
14268e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    accountKey = authority.account.name + "/" + authority.account.type
14278e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                            + " u" + authority.userId;
1428e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                } else {
1429e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    authorityName = "Unknown";
1430e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    accountKey = "Unknown";
1431e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1432e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final long elapsedTime = item.elapsedTime;
1433e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final Time time = new Time();
1434e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                final long eventTime = item.eventTime;
1435e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                time.set(eventTime);
1436e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1437bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                final String key = authorityName + "/" + accountKey;
1438bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                final Long lastEventTime = lastTimeMap.get(key);
1439bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                final String diffString;
1440bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                if (lastEventTime == null) {
1441bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    diffString = "";
1442e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                } else {
1443bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    final long diff = (lastEventTime - eventTime) / 1000;
1444bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    if (diff < 60) {
1445bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        diffString = String.valueOf(diff);
1446bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    } else if (diff < 3600) {
1447bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        diffString = String.format("%02d:%02d", diff / 60, diff % 60);
1448bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    } else {
1449bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        final long sec = diff % 3600;
1450bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        diffString = String.format("%02d:%02d:%02d",
1451bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                                diff / 3600, sec / 60, sec % 60);
1452bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                    }
1453e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1454bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                lastTimeMap.put(key, eventTime);
1455e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1456bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                pw.printf("  #%-3d: %s %8s  %5.1fs  %8s",
1457bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        i + 1,
1458bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        formatTime(eventTime),
1459bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        SyncStorageEngine.SOURCES[item.source],
1460bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        ((float) elapsedTime) / 1000,
1461bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                        diffString);
1462bf976ba6576a8ebf0e25f10eca83cb8038578510Alon Albert                pw.printf(format, accountKey, authorityName);
1463e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1464e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                if (item.event != SyncStorageEngine.EVENT_STOP
1465e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                        || item.upstreamActivity != 0
1466e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                        || item.downstreamActivity != 0) {
1467e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    pw.printf("    event=%d upstreamActivity=%d downstreamActivity=%d\n",
1468e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                            item.event,
1469e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                            item.upstreamActivity,
1470e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                            item.downstreamActivity);
1471e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1472e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                if (item.mesg != null
1473e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                        && !SyncStorageEngine.MESG_SUCCESS.equals(item.mesg)) {
1474e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                    pw.printf("    mesg=%s\n", item.mesg);
1475e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert                }
1476e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            }
1477e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        }
1478e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    }
1479e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1480e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    private void dumpDayStatistics(PrintWriter pw) {
1481231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        SyncStorageEngine.DayStats dses[] = mSyncStorageEngine.getDayStatistics();
1482231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        if (dses != null && dses[0] != null) {
1483231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.println();
1484231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.println("Sync Statistics");
1485231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            pw.print("  Today:  "); dumpDayStatistic(pw, dses[0]);
1486231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            int today = dses[0].day;
1487231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            int i;
1488231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncStorageEngine.DayStats ds;
148944f574781545781c31db3dcf495ed08763073f75Doug Zongker
1490231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            // Print each day in the current week.
1491231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            for (i=1; i<=6 && i < dses.length; i++) {
1492231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                ds = dses[i];
1493231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                if (ds == null) break;
1494231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                int delta = today-ds.day;
1495231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                if (delta > 6) break;
149644f574781545781c31db3dcf495ed08763073f75Doug Zongker
1497231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                pw.print("  Day-"); pw.print(delta); pw.print(":  ");
1498231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                dumpDayStatistic(pw, ds);
1499231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
150044f574781545781c31db3dcf495ed08763073f75Doug Zongker
1501231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            // Aggregate all following days into weeks and print totals.
1502231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            int weekDay = today;
1503231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            while (i < dses.length) {
1504231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                SyncStorageEngine.DayStats aggr = null;
1505231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                weekDay -= 7;
1506231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                while (i < dses.length) {
1507231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    ds = dses[i];
1508231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    if (ds == null) {
1509231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                        i = dses.length;
1510231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                        break;
1511231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    }
1512231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    int delta = weekDay-ds.day;
1513231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    if (delta > 6) break;
1514231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    i++;
151544f574781545781c31db3dcf495ed08763073f75Doug Zongker
1516231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    if (aggr == null) {
1517231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                        aggr = new SyncStorageEngine.DayStats(weekDay);
1518231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    }
1519231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    aggr.successCount += ds.successCount;
1520231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    aggr.successTime += ds.successTime;
1521231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    aggr.failureCount += ds.failureCount;
1522231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    aggr.failureTime += ds.failureTime;
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1524231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                if (aggr != null) {
1525231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    pw.print("  Week-"); pw.print((today-weekDay)/7); pw.print(": ");
1526231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    dumpDayStatistic(pw, aggr);
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1528231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
1529231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
1530e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    }
153144f574781545781c31db3dcf495ed08763073f75Doug Zongker
15326ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    private void dumpSyncAdapters(IndentingPrintWriter pw) {
15336ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        pw.println();
15346ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final List<UserInfo> users = getAllUsers();
15356ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        if (users != null) {
15366ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            for (UserInfo user : users) {
15376ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                pw.println("Sync adapters for " + user + ":");
15386ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                pw.increaseIndent();
15396ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                for (RegisteredServicesCache.ServiceInfo<?> info :
15406ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                        mSyncAdapters.getAllServices(user.id)) {
15416ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                    pw.println(info);
15426ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                }
15436ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                pw.decreaseIndent();
15446ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                pw.println();
15456ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            }
15466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        }
15476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    }
15486ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
1549e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    private static class AuthoritySyncStats {
1550e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        String name;
1551e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        long elapsedTime;
1552e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        int times;
1553e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        Map<String, AccountSyncStats> accountMap = Maps.newHashMap();
1554e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1555e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        private AuthoritySyncStats(String name) {
1556e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            this.name = name;
1557e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        }
1558e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    }
1559e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1560e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert    private static class AccountSyncStats {
1561e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        String name;
1562e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        long elapsedTime;
1563e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        int times;
1564e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert
1565e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert        private AccountSyncStats(String name) {
1566e0bde33e0d2b3ffb7918a5818a387773d4aa3e71Alon Albert            this.name = name;
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A helper object to keep track of the time we have spent syncing since the last boot
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class SyncTimeTracker {
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** True if a sync was in progress on the most recent call to update() */
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean mLastWasSyncing = false;
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Used to track when lastWasSyncing was last set */
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long mWhenSyncStarted = 0;
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** The cumulative time we have spent syncing */
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private long mTimeSpentSyncing;
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Call to let the tracker know that the sync state may have changed */
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void update() {
1583918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            final boolean isSyncInProgress = !mActiveSyncContexts.isEmpty();
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isSyncInProgress == mLastWasSyncing) return;
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long now = SystemClock.elapsedRealtime();
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isSyncInProgress) {
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mWhenSyncStarted = now;
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTimeSpentSyncing += now - mWhenSyncStarted;
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastWasSyncing = isSyncInProgress;
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Get how long we have been syncing, in ms */
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized long timeSpentSyncing() {
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mLastWasSyncing) return mTimeSpentSyncing;
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long now = SystemClock.elapsedRealtime();
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mTimeSpentSyncing + (now - mWhenSyncStarted);
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1603718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana    class ServiceConnectionData {
1604718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        public final ActiveSyncContext activeSyncContext;
1605718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        public final ISyncAdapter syncAdapter;
1606718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        ServiceConnectionData(ActiveSyncContext activeSyncContext, ISyncAdapter syncAdapter) {
1607718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            this.activeSyncContext = activeSyncContext;
1608718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            this.syncAdapter = syncAdapter;
1609718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        }
1610718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana    }
1611718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Handles SyncOperation Messages that are posted to the associated
16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * HandlerThread.
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class SyncHandler extends Handler {
16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Messages that can be sent on mHandler
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int MESSAGE_SYNC_FINISHED = 1;
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int MESSAGE_SYNC_ALARM = 2;
16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int MESSAGE_CHECK_ALARMS = 3;
1621718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        private static final int MESSAGE_SERVICE_CONNECTED = 4;
1622718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        private static final int MESSAGE_SERVICE_DISCONNECTED = 5;
1623918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        private static final int MESSAGE_CANCEL = 6;
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Long mAlarmScheduleTime = null;
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
1628fdb2dca4546742803617c370c2fb823b0ab63a07Fred Quintana        private final HashMap<Pair<Account, String>, PowerManager.WakeLock> mWakeLocks =
1629b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana                Maps.newHashMap();
16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1631e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        private volatile CountDownLatch mReadyToRunLatch = new CountDownLatch(1);
16326ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
1633e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        public void onBootCompleted() {
1634e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            mBootCompleted = true;
16356ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
16368f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey            doDatabaseCleanup();
16378f55d112983aa922687de7e3581f73913c06e37aJeff Sharkey
1638e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            if (mReadyToRunLatch != null) {
1639e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                mReadyToRunLatch.countDown();
1640e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            }
1641e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        }
1642e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana
1643fdb2dca4546742803617c370c2fb823b0ab63a07Fred Quintana        private PowerManager.WakeLock getSyncWakeLock(Account account, String authority) {
1644fdb2dca4546742803617c370c2fb823b0ab63a07Fred Quintana            final Pair<Account, String> wakeLockKey = Pair.create(account, authority);
1645b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana            PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
1646b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana            if (wakeLock == null) {
1647fdb2dca4546742803617c370c2fb823b0ab63a07Fred Quintana                final String name = SYNC_WAKE_LOCK_PREFIX + "_" + authority + "_" + account;
1648b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana                wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
1649b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana                wakeLock.setReferenceCounted(false);
1650b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana                mWakeLocks.put(wakeLockKey, wakeLock);
1651b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana            }
1652b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana            return wakeLock;
1653b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana        }
1654b3029c3d563cf99ea07395282b053e87d5dbbb95Fred Quintana
1655e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        private void waitUntilReadyToRun() {
1656e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            CountDownLatch latch = mReadyToRunLatch;
1657e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            if (latch != null) {
1658e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                while (true) {
1659e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                    try {
1660e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                        latch.await();
1661e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                        mReadyToRunLatch = null;
1662e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                        return;
1663e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                    } catch (InterruptedException e) {
1664e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                        Thread.currentThread().interrupt();
1665e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                    }
1666e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                }
1667e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana            }
1668e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana        }
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Used to keep track of whether a sync notification is active and who it is for.
16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        class SyncNotificationInfo {
16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // true iff the notification manager has been asked to send the notification
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public boolean isActive = false;
16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set when we transition from not running a sync to running a sync, and cleared on
16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // the opposite transition.
16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public Long startTime = null;
16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void toString(StringBuilder sb) {
1681918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                sb.append("isActive ").append(isActive).append(", startTime ").append(startTime);
16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public String toString() {
16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                StringBuilder sb = new StringBuilder();
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                toString(sb);
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return sb.toString();
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public SyncHandler(Looper looper) {
16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(looper);
16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
1697918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            long earliestFuturePollTime = Long.MAX_VALUE;
1698918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            long nextPendingSyncTime = Long.MAX_VALUE;
1699753c57bf729def69be3f3ed0bcc07b0d858b73bbSubir Jhanb
1700753c57bf729def69be3f3ed0bcc07b0d858b73bbSubir Jhanb            // Setting the value here instead of a method because we want the dumpsys logs
1701753c57bf729def69be3f3ed0bcc07b0d858b73bbSubir Jhanb            // to have the most recent value used.
17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
1703e91ebe2be9580625ff31af8583e55aaefc50474fFred Quintana                waitUntilReadyToRun();
17041bad83adf011ff4e6a6474c62b287d119ba43b3eAlon Albert                mDataConnectionIsConnected = readDataConnectionState();
1705918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                mSyncManagerWakeLock.acquire();
170677c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                // Always do this first so that we be sure that any periodic syncs that
170777c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                // are ready to run have been converted into pending syncs. This allows the
170877c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                // logic that considers the next steps to take based on the set of pending syncs
170977c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                // to also take into account the periodic syncs.
171077c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                earliestFuturePollTime = scheduleReadyPeriodicSyncs();
17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                switch (msg.what) {
1712918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    case SyncHandler.MESSAGE_CANCEL: {
1713918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        Pair<Account, String> payload = (Pair<Account, String>)msg.obj;
1714918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1715918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CANCEL: "
1716918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    + payload.first + ", " + payload.second);
1717918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        }
171804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        cancelActiveSyncLocked(payload.first, msg.arg1, payload.second);
1719918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        nextPendingSyncTime = maybeStartNextSyncLocked();
1720918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        break;
1721918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
1722918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case SyncHandler.MESSAGE_SYNC_FINISHED:
17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_SYNC_FINISHED");
17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        SyncHandlerMessagePayload payload = (SyncHandlerMessagePayload)msg.obj;
1728918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (!isSyncStillActive(payload.activeSyncContext)) {
1729918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
1730918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    + "sync is no longer active: "
1731918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    + payload.activeSyncContext);
1732918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            break;
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1734918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        runSyncFinishedOrCanceledLocked(payload.syncResult, payload.activeSyncContext);
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1736918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        // since a sync just finished check if it is time to start a new sync
1737918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        nextPendingSyncTime = maybeStartNextSyncLocked();
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1740718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
1741718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;
1742718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1743718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
1744918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    + msgData.activeSyncContext);
1745718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        }
1746718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        // check that this isn't an old message
1747918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (isSyncStillActive(msgData.activeSyncContext)) {
1748918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            runBoundToSyncAdapter(msgData.activeSyncContext, msgData.syncAdapter);
1749718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        }
1750718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        break;
1751718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    }
1752718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
1753718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
1754918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        final ActiveSyncContext currentSyncContext =
1755918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                ((ServiceConnectionData)msg.obj).activeSyncContext;
1756718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
1757718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
1758918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    + currentSyncContext);
1759718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        }
1760718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        // check that this isn't an old message
1761918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (isSyncStillActive(currentSyncContext)) {
1762718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            // cancel the sync if we have a syncadapter, which means one is
1763718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            // outstanding
1764918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            if (currentSyncContext.mSyncAdapter != null) {
1765718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                                try {
1766918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    currentSyncContext.mSyncAdapter.cancelSync(currentSyncContext);
1767718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                                } catch (RemoteException e) {
1768718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                                    // we don't need to retry this in this case
1769718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                                }
1770718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            }
1771718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
1772718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            // pretend that the sync failed with an IOException,
1773718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            // which is a soft error
1774718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            SyncResult syncResult = new SyncResult();
1775718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                            syncResult.stats.numIoExceptions++;
1776918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            runSyncFinishedOrCanceledLocked(syncResult, currentSyncContext);
1777718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
1778918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            // since a sync just finished check if it is time to start a new sync
1779918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            nextPendingSyncTime = maybeStartNextSyncLocked();
1780718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        }
1781718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
1782718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        break;
1783718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    }
1784718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case SyncHandler.MESSAGE_SYNC_ALARM: {
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (isLoggable) {
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_SYNC_ALARM");
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mAlarmScheduleTime = null;
17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
1792918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            nextPendingSyncTime = maybeStartNextSyncLocked();
17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } finally {
17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            mHandleAlarmWakeLock.release();
17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    case SyncHandler.MESSAGE_CHECK_ALARMS:
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_CHECK_ALARMS");
18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1803918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        nextPendingSyncTime = maybeStartNextSyncLocked();
18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } finally {
1807918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                manageSyncNotificationLocked();
1808918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                manageSyncAlarmLocked(earliestFuturePollTime, nextPendingSyncTime);
18099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSyncTimeTracker.update();
1810918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                mSyncManagerWakeLock.release();
18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
181477c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana        /**
181577c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana         * Turn any periodic sync operations that are ready to run into pending sync operations.
181677c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana         * @return the desired start time of the earliest future  periodic sync operation,
181777c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana         * in milliseconds since boot
181877c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana         */
1819918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        private long scheduleReadyPeriodicSyncs() {
182077c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana            final boolean backgroundDataUsageAllowed =
182177c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    getConnectivityManager().getBackgroundDataSetting();
1822918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            long earliestFuturePollTime = Long.MAX_VALUE;
182304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            if (!backgroundDataUsageAllowed) {
182477c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                return earliestFuturePollTime;
1825c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            }
182604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
18276ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            AccountAndUser[] accounts = mRunningAccounts;
182804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
182977c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana            final long nowAbsolute = System.currentTimeMillis();
183069d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma            final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis)
183169d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                                               ? (nowAbsolute  - mSyncRandomOffsetMillis) : 0;
183269d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma
183377c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana            ArrayList<SyncStorageEngine.AuthorityInfo> infos = mSyncStorageEngine.getAuthorities();
183477c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana            for (SyncStorageEngine.AuthorityInfo info : infos) {
183577c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                // skip the sync if the account of this operation no longer exists
183604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                if (!containsAccountAndUser(accounts, info.account, info.userId)) {
183777c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    continue;
183877c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                }
183977c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana
184004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                if (!mSyncStorageEngine.getMasterSyncAutomatically(info.userId)
184104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        || !mSyncStorageEngine.getSyncAutomatically(info.account, info.userId,
184204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                info.authority)) {
184377c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    continue;
184477c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                }
1845c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
184604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                if (mSyncStorageEngine.getIsSyncable(info.account, info.userId, info.authority)
184704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        == 0) {
184877c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    continue;
184977c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                }
185077c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana
185177c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(info);
185277c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                for (int i = 0, N = info.periodicSyncs.size(); i < N; i++) {
185377c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    final Bundle extras = info.periodicSyncs.get(i).first;
185469d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    final Long periodInMillis = info.periodicSyncs.get(i).second * 1000;
185577c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    // find when this periodic sync was last scheduled to run
185677c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    final long lastPollTimeAbsolute = status.getPeriodicSyncTime(i);
185769d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma
185869d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    long remainingMillis
185969d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                            = periodInMillis - (shiftedNowAbsolute % periodInMillis);
186069d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma
186169d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    /*
186269d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     * Sync scheduling strategy:
186369d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     *    Set the next periodic sync based on a random offset (in seconds).
186469d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     *
186569d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     *    Also sync right now if any of the following cases hold
186669d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     *    and mark it as having been scheduled
186769d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     *
186869d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     * Case 1:  This sync is ready to run now.
186969d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     * Case 2:  If the lastPollTimeAbsolute is in the future,
187069d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     *          sync now and reinitialize. This can happen for
187169d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     *          example if the user changed the time, synced and
187269d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     *          changed back.
187369d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     * Case 3:  If we failed to sync at the last scheduled time
187469d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                     */
187569d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    if (remainingMillis == periodInMillis  // Case 1
187669d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                            || lastPollTimeAbsolute > nowAbsolute // Case 2
187769d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                            || (nowAbsolute - lastPollTimeAbsolute
187869d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                                    >= periodInMillis)) { // Case 3
187969d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                        // Sync now
188004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
188104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                info.account, info.userId, info.authority);
18826ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                        final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
18836ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                        syncAdapterInfo = mSyncAdapters.getServiceInfo(
18846ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                                SyncAdapterType.newKey(info.authority, info.account.type),
18856ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                                info.userId);
18860c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        if (syncAdapterInfo == null) {
18870c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                            continue;
18880c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        }
188977c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                        scheduleSyncOperation(
189004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                new SyncOperation(info.account, info.userId,
189104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                        SyncStorageEngine.SOURCE_PERIODIC,
1892918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                        info.authority, extras, 0 /* delay */,
1893918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                        backoff != null ? backoff.first : 0,
1894918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                        mSyncStorageEngine.getDelayUntilTime(
189504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                                info.account, info.userId, info.authority),
18960c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                        syncAdapterInfo.type.allowParallelSyncs()));
189777c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                        status.setPeriodicSyncTime(i, nowAbsolute);
189869d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    }
189969d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    // Compute when this periodic sync should next run
190069d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    final long nextPollTimeAbsolute = nowAbsolute + remainingMillis;
190169d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma
190269d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    // remember this time if it is earlier than earliestFuturePollTime
190369d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                    if (nextPollTimeAbsolute < earliestFuturePollTime) {
190469d95de53bc82e6c23c64ad566e428fbefae0543Ashish Sharma                        earliestFuturePollTime = nextPollTimeAbsolute;
190577c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    }
190677c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                }
1907c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            }
1908c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
1909918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (earliestFuturePollTime == Long.MAX_VALUE) {
1910918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                return Long.MAX_VALUE;
1911c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            }
1912c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
191377c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana            // convert absolute time to elapsed time
191477c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana            return SystemClock.elapsedRealtime()
191577c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    + ((earliestFuturePollTime < nowAbsolute)
191677c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                      ? 0
191777c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                      : (earliestFuturePollTime - nowAbsolute));
1918c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        }
1919c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
1920918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        private long maybeStartNextSyncLocked() {
1921918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
1922918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (isLoggable) Log.v(TAG, "maybeStartNextSync");
19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If we aren't ready to run (e.g. the data connection is down), get out.
19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mDataConnectionIsConnected) {
19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isLoggable) {
1927918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "maybeStartNextSync: no data connection, skipping");
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1929918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                return Long.MAX_VALUE;
19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mStorageIsLow) {
19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isLoggable) {
1934918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "maybeStartNextSync: memory low, skipping");
19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1936918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                return Long.MAX_VALUE;
19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If the accounts aren't known yet then we aren't ready to run. We will be kicked
19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // when the account lookup request does complete.
19416ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            AccountAndUser[] accounts = mRunningAccounts;
194253bd2522ca7767f46646606123b6e2689b811850Fred Quintana            if (accounts == INITIAL_ACCOUNTS_ARRAY) {
19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isLoggable) {
1944918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "maybeStartNextSync: accounts not known, skipping");
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1946918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                return Long.MAX_VALUE;
19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Otherwise consume SyncOperations from the head of the SyncQueue until one is
19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // found that is runnable (not disabled, etc). If that one is ready to run then
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // start it, otherwise just get out.
1952f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana            final boolean backgroundDataUsageAllowed =
1953f892fb3a431e04151382d1bddc4438fd04487a6aFred Quintana                    getConnectivityManager().getBackgroundDataSetting();
195477c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana
1955918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            final long now = SystemClock.elapsedRealtime();
19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1957918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // will be set to the next time that a sync should be considered for running
1958918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            long nextReadyToRunTime = Long.MAX_VALUE;
1959918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
1960918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // order the sync queue, dropping syncs that are not allowed
1961918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            ArrayList<SyncOperation> operations = new ArrayList<SyncOperation>();
1962918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            synchronized (mSyncQueue) {
1963918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (isLoggable) {
1964918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "build the operation array, syncQueue size is "
1965a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey                        + mSyncQueue.getOperations().size());
1966918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
1967a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey                final Iterator<SyncOperation> operationIterator = mSyncQueue.getOperations()
1968a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey                        .iterator();
19698e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert
19708e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                final ActivityManager activityManager
19718e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                        = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
19728e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                final Set<Integer> removedUsers = Sets.newHashSet();
1973918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                while (operationIterator.hasNext()) {
1974918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    final SyncOperation op = operationIterator.next();
1975307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
197677c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    // drop the sync if the account of this operation no longer exists
197704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    if (!containsAccountAndUser(accounts, op.account, op.userId)) {
1978918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        operationIterator.remove();
1979918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        mSyncStorageEngine.deleteFromPending(op.pendingOperation);
198077c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                        continue;
198177c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    }
198277c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana
1983918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    // drop this sync request if it isn't syncable
198404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    int syncableState = mSyncStorageEngine.getIsSyncable(
198504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            op.account, op.userId, op.authority);
198677c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    if (syncableState == 0) {
1987918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        operationIterator.remove();
1988918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        mSyncStorageEngine.deleteFromPending(op.pendingOperation);
1989918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        continue;
1990918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
1991918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
19928e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    // if the user in not running, drop the request
19938e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    if (!activityManager.isUserRunning(op.userId)) {
19948e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                        final UserInfo userInfo = mUserManager.getUserInfo(op.userId);
19958e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                        if (userInfo == null) {
19968e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                            removedUsers.add(op.userId);
19978e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                        }
19988e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                        continue;
19998e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    }
20008e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert
2001918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    // if the next run time is in the future, meaning there are no syncs ready
2002918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    // to run, return the time
2003918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    if (op.effectiveRunTime > now) {
2004918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (nextReadyToRunTime > op.effectiveRunTime) {
2005918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            nextReadyToRunTime = op.effectiveRunTime;
2006918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        }
200777c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                        continue;
200877c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    }
200977c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana
201034821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
201134821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    syncAdapterInfo = mSyncAdapters.getServiceInfo(
20126ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                            SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
201334821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey
201434821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    // only proceed if network is connected for requesting UID
201534821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    final boolean uidNetworkConnected;
201634821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    if (syncAdapterInfo != null) {
201734821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                        final NetworkInfo networkInfo = getConnectivityManager()
201834821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                                .getActiveNetworkInfoForUid(syncAdapterInfo.uid);
201934821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                        uidNetworkConnected = networkInfo != null && networkInfo.isConnected();
202034821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    } else {
202134821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                        uidNetworkConnected = false;
202234821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    }
202334821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey
202434821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    // skip the sync if it isn't manual, and auto sync or
202534821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    // background data usage is disabled or network is
202634821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                    // disconnected for the target UID.
202777c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                    if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
202877c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                            && (syncableState > 0)
202904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            && (!mSyncStorageEngine.getMasterSyncAutomatically(op.userId)
203077c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                                || !backgroundDataUsageAllowed
203134821881c159e434a1a2c8a6ba5ebfc64376791eJeff Sharkey                                || !uidNetworkConnected
203277c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana                                || !mSyncStorageEngine.getSyncAutomatically(
203304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                       op.account, op.userId, op.authority))) {
2034918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        operationIterator.remove();
2035918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        mSyncStorageEngine.deleteFromPending(op.pendingOperation);
20369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        continue;
20379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
20389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2039918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    operations.add(op);
2040918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
20418e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                for (Integer user : removedUsers) {
20428e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    // if it's still removed
20438e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    if (mUserManager.getUserInfo(user) == null) {
20446ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                        onUserRemoved(user);
20458e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    }
20468e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                }
2047918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
2048918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2049918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // find the next operation to dispatch, if one is ready
2050918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // iterate from the top, keep issuing (while potentially cancelling existing syncs)
2051918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // until the quotas are filled.
2052918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // once the quotas are filled iterate once more to find when the next one would be
2053918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // (also considering pre-emption reasons).
2054918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (isLoggable) Log.v(TAG, "sort the candidate operations, size " + operations.size());
2055918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            Collections.sort(operations);
2056918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (isLoggable) Log.v(TAG, "dispatch all ready sync operations");
2057918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            for (int i = 0, N = operations.size(); i < N; i++) {
2058918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                final SyncOperation candidate = operations.get(i);
2059918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                final boolean candidateIsInitialization = candidate.isInitialization();
2060918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2061918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                int numInit = 0;
2062918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                int numRegular = 0;
2063918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                ActiveSyncContext conflict = null;
2064918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                ActiveSyncContext longRunning = null;
2065918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                ActiveSyncContext toReschedule = null;
2066dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                ActiveSyncContext oldestNonExpeditedRegular = null;
2067918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2068918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                for (ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
2069918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    final SyncOperation activeOp = activeSyncContext.mSyncOperation;
2070918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    if (activeOp.isInitialization()) {
2071918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        numInit++;
2072918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    } else {
2073918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        numRegular++;
2074dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                        if (!activeOp.isExpedited()) {
2075dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                            if (oldestNonExpeditedRegular == null
2076dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                                || (oldestNonExpeditedRegular.mStartTime
2077dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                                    > activeSyncContext.mStartTime)) {
2078dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                                oldestNonExpeditedRegular = activeSyncContext;
2079dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                            }
2080dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                        }
2081918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
2082918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    if (activeOp.account.type.equals(candidate.account.type)
20830c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                            && activeOp.authority.equals(candidate.authority)
208404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            && activeOp.userId == candidate.userId
20850c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                            && (!activeOp.allowParallelSyncs
20860c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                                || activeOp.account.name.equals(candidate.account.name))) {
2087918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        conflict = activeSyncContext;
2088918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        // don't break out since we want to do a full count of the varieties
2089918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    } else {
2090918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (candidateIsInitialization == activeOp.isInitialization()
2091918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                && activeSyncContext.mStartTime + MAX_TIME_PER_SYNC < now) {
2092918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            longRunning = activeSyncContext;
2093918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            // don't break out since we want to do a full count of the varieties
2094918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        }
2095918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isLoggable) {
2099918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "candidate " + (i + 1) + " of " + N + ": " + candidate);
2100918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "  numActiveInit=" + numInit + ", numActiveRegular=" + numRegular);
2101918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "  longRunning: " + longRunning);
2102918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "  conflict: " + conflict);
2103dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    Log.v(TAG, "  oldestNonExpeditedRegular: " + oldestNonExpeditedRegular);
21049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2105918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2106dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                final boolean roomAvailable = candidateIsInitialization
2107dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                        ? numInit < MAX_SIMULTANEOUS_INITIALIZATION_SYNCS
2108dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                        : numRegular < MAX_SIMULTANEOUS_REGULAR_SYNCS;
2109dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana
2110918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (conflict != null) {
2111918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    if (candidateIsInitialization && !conflict.mSyncOperation.isInitialization()
2112918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            && numInit < MAX_SIMULTANEOUS_INITIALIZATION_SYNCS) {
2113918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        toReschedule = conflict;
2114918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2115918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            Log.v(TAG, "canceling and rescheduling sync since an initialization "
2116918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    + "takes higher priority, " + conflict);
2117918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        }
2118918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    } else if (candidate.expedited && !conflict.mSyncOperation.expedited
2119918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            && (candidateIsInitialization
2120918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                == conflict.mSyncOperation.isInitialization())) {
2121918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        toReschedule = conflict;
2122918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2123918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            Log.v(TAG, "canceling and rescheduling sync since an expedited "
2124918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    + "takes higher priority, " + conflict);
2125918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        }
2126918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    } else {
2127918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        continue;
2128918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
2129dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                } else if (roomAvailable) {
2130dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    // dispatch candidate
2131dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                } else if (candidate.isExpedited() && oldestNonExpeditedRegular != null
2132dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                           && !candidateIsInitialization) {
2133dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    // We found an active, non-expedited regular sync. We also know that the
2134dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    // candidate doesn't conflict with this active sync since conflict
2135dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    // is null. Reschedule the active sync and start the candidate.
2136dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    toReschedule = oldestNonExpeditedRegular;
2137dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
2138dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                        Log.v(TAG, "canceling and rescheduling sync since an expedited is ready to run, "
2139dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                                + oldestNonExpeditedRegular);
2140918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
2141dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                } else if (longRunning != null
2142dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                        && (candidateIsInitialization
2143dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                            == longRunning.mSyncOperation.isInitialization())) {
2144dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    // We found an active, long-running sync. Reschedule the active
2145dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    // sync and start the candidate.
2146dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    toReschedule = longRunning;
2147dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
2148dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                        Log.v(TAG, "canceling and rescheduling sync since it ran roo long, "
2149dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                              + longRunning);
2150dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    }
2151dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                } else {
2152dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    // we were unable to find or make space to run this candidate, go on to
2153dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    // the next one
2154dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    continue;
2155918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
2156918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2157918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (toReschedule != null) {
2158918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    runSyncFinishedOrCanceledLocked(null, toReschedule);
2159918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    scheduleSyncOperation(toReschedule.mSyncOperation);
2160918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
2161a706e2fd0059b1bb86c487722dbc9fc0fda9c980Jeff Sharkey                synchronized (mSyncQueue) {
2162918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    mSyncQueue.remove(candidate);
2163918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
216487b146625a2daa7eaa606e1975e94a9a579af8b8Fred Quintana                dispatchSyncOperation(candidate);
21659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2167918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            return nextReadyToRunTime;
2168918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana     }
2169918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
217087b146625a2daa7eaa606e1975e94a9a579af8b8Fred Quintana        private boolean dispatchSyncOperation(SyncOperation op) {
2171918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
21720c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                Log.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
2173918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                Log.v(TAG, "num active syncs: " + mActiveSyncContexts.size());
2174918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                for (ActiveSyncContext syncContext : mActiveSyncContexts) {
2175918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, syncContext.toString());
2176918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
2177918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
2178918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2179718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            // connect to the sync adapter
21804a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana            SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);
21816ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
21826ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, op.userId);
2183718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            if (syncAdapterInfo == null) {
21847620f1ae498e01bf2df58eaa1b9b20ef1eb47fa1Fred Quintana                Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
21857620f1ae498e01bf2df58eaa1b9b20ef1eb47fa1Fred Quintana                        + ", removing settings for it");
218604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                mSyncStorageEngine.removeAuthority(op.account, op.userId, op.authority);
218787b146625a2daa7eaa606e1975e94a9a579af8b8Fred Quintana                return false;
2188718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            }
2189718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana
2190718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            ActiveSyncContext activeSyncContext =
2191918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    new ActiveSyncContext(op, insertStartSyncEvent(op), syncAdapterInfo.uid);
2192918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);
2193918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            mActiveSyncContexts.add(activeSyncContext);
2194718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
2195918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                Log.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);
2196718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana            }
21974120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn            if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo, op.userId)) {
2198718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);
2199918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                closeActiveSyncContext(activeSyncContext);
220087b146625a2daa7eaa606e1975e94a9a579af8b8Fred Quintana                return false;
22019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
220387b146625a2daa7eaa606e1975e94a9a579af8b8Fred Quintana            return true;
2204718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana        }
22059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2206eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert        private void runBoundToSyncAdapter(final ActiveSyncContext activeSyncContext,
2207918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana              ISyncAdapter syncAdapter) {
2208918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            activeSyncContext.mSyncAdapter = syncAdapter;
2209918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
22109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
2211eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert                activeSyncContext.mIsLinkedToDeath = true;
2212eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert                syncAdapter.asBinder().linkToDeath(activeSyncContext, 0);
2213eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert
2214918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                syncAdapter.startSync(activeSyncContext, syncOperation.authority,
221521bb0deb36af32339521038cdbd827f74468df4aFred Quintana                        syncOperation.account, syncOperation.extras);
22169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException remoteExc) {
2217918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);
2218918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                closeActiveSyncContext(activeSyncContext);
2219307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                increaseBackoffSetting(syncOperation);
2220307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                scheduleSyncOperation(new SyncOperation(syncOperation));
22219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RuntimeException exc) {
2222918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                closeActiveSyncContext(activeSyncContext);
2223307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                Log.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
22249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
22259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
222704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private void cancelActiveSyncLocked(Account account, int userId, String authority) {
2228918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            ArrayList<ActiveSyncContext> activeSyncs =
2229918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    new ArrayList<ActiveSyncContext>(mActiveSyncContexts);
2230918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            for (ActiveSyncContext activeSyncContext : activeSyncs) {
2231918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (activeSyncContext != null) {
22328e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    // if an account was specified then only cancel the sync if it matches
2233918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    if (account != null) {
2234918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (!account.equals(activeSyncContext.mSyncOperation.account)) {
223504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            continue;
2236918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        }
2237918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
22388e28555f6d4ea557ba79e3d411ea46e5a0788b8fAlon Albert                    // if an authority was specified then only cancel the sync if it matches
2239918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    if (authority != null) {
2240918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        if (!authority.equals(activeSyncContext.mSyncOperation.authority)) {
224104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            continue;
2242918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        }
2243918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
224404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    // check if the userid matches
2245f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn                    if (userId != UserHandle.USER_ALL
224604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            && userId != activeSyncContext.mSyncOperation.userId) {
224704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        continue;
224804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    }
2249918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    runSyncFinishedOrCanceledLocked(null /* no result since this is a cancel */,
2250918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            activeSyncContext);
2251918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
2252918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
2253918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        }
2254918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2255918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        private void runSyncFinishedOrCanceledLocked(SyncResult syncResult,
2256918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                ActiveSyncContext activeSyncContext) {
22579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
2258eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert
2259eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert            if (activeSyncContext.mIsLinkedToDeath) {
2260eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert                activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
2261eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert                activeSyncContext.mIsLinkedToDeath = false;
2262eca7511f61a6bfbb43a6646f87b5771bcc5d3fdcAlon Albert            }
2263918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            closeActiveSyncContext(activeSyncContext);
22649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
22669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
22689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String historyMessage;
22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int downstreamActivity;
22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int upstreamActivity;
22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (syncResult != null) {
22739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isLoggable) {
2274307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    Log.v(TAG, "runSyncFinishedOrCanceled [finished]: "
22759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + syncOperation + ", result " + syncResult);
22769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
22779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!syncResult.hasError()) {
2279231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                    historyMessage = SyncStorageEngine.MESG_SUCCESS;
22809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // TODO: set these correctly when the SyncResult is extended to include it
22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    downstreamActivity = 0;
22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    upstreamActivity = 0;
22836e079a32bceb85a44da3b396f8d37e718d1421d5Alon Albert                    clearBackoffSetting(syncOperation);
22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
2285307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    Log.d(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
2286307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    // the operation failed so increase the backoff time
2287307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    if (!syncResult.syncAlreadyInProgress) {
2288307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                        increaseBackoffSetting(syncOperation);
22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2290307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    // reschedule the sync if so indicated by the syncResult
2291307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    maybeRescheduleSync(syncResult, syncOperation);
22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    historyMessage = Integer.toString(syncResultToErrorNumber(syncResult));
22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // TODO: set these correctly when the SyncResult is extended to include it
22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    downstreamActivity = 0;
22959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    upstreamActivity = 0;
22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2297307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
2298307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                setDelayUntilTime(syncOperation, syncResult.delayUntil);
22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isLoggable) {
2301307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana                    Log.v(TAG, "runSyncFinishedOrCanceled [canceled]: " + syncOperation);
23029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2303718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                if (activeSyncContext.mSyncAdapter != null) {
2304718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    try {
230521bb0deb36af32339521038cdbd827f74468df4aFred Quintana                        activeSyncContext.mSyncAdapter.cancelSync(activeSyncContext);
2306718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    } catch (RemoteException e) {
2307718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                        // we don't need to retry this in this case
2308718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    }
23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2310231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                historyMessage = SyncStorageEngine.MESG_CANCELED;
23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                downstreamActivity = 0;
23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                upstreamActivity = 0;
23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    upstreamActivity, downstreamActivity, elapsedTime);
23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (syncResult != null && syncResult.tooManyDeletions) {
23199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                installHandleTooManyDeletesNotification(syncOperation.account,
23204120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                        syncOperation.authority, syncResult.stats.numDeletes,
23214120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                        syncOperation.userId);
23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
23234120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                mNotificationMgr.cancelAsUser(null,
23244120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                        syncOperation.account.hashCode() ^ syncOperation.authority.hashCode(),
23254120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                        new UserHandle(syncOperation.userId));
23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (syncResult != null && syncResult.fullSyncRequested) {
232904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                scheduleSyncOperation(new SyncOperation(syncOperation.account, syncOperation.userId,
2330918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        syncOperation.syncSource, syncOperation.authority, new Bundle(), 0,
23310c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        syncOperation.backoff, syncOperation.delayUntil,
23320c4d04ac2e8aa62560d8d767fa1c87e5361b0b08Fred Quintana                        syncOperation.allowParallelSyncs));
23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // no need to schedule an alarm, as that will be done by our caller.
23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2337918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        private void closeActiveSyncContext(ActiveSyncContext activeSyncContext) {
2338918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            activeSyncContext.close();
2339918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            mActiveSyncContexts.remove(activeSyncContext);
234004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            mSyncStorageEngine.removeActiveSync(activeSyncContext.mSyncInfo,
234104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    activeSyncContext.mSyncOperation.userId);
2342918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        }
2343918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
23449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Convert the error-containing SyncResult into the Sync.History error number. Since
23469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the SyncResult may indicate multiple errors at once, this method just returns the
23479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * most "serious" error.
23489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param syncResult the SyncResult from which to read
23499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return the most "serious" error set in the SyncResult
23509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @throws IllegalStateException if the SyncResult does not indicate any errors.
23519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *   If SyncResult.error() is true then it is safe to call this.
23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
23539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int syncResultToErrorNumber(SyncResult syncResult) {
2354231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncResult.syncAlreadyInProgress)
2355ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
2356231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncResult.stats.numAuthExceptions > 0)
2357ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return ContentResolver.SYNC_ERROR_AUTHENTICATION;
2358231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncResult.stats.numIoExceptions > 0)
2359ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return ContentResolver.SYNC_ERROR_IO;
2360231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncResult.stats.numParseExceptions > 0)
2361ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return ContentResolver.SYNC_ERROR_PARSE;
2362231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncResult.stats.numConflictDetectedExceptions > 0)
2363ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return ContentResolver.SYNC_ERROR_CONFLICT;
2364231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncResult.tooManyDeletions)
2365ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS;
2366231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncResult.tooManyRetries)
2367ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES;
2368231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncResult.databaseError)
2369ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return ContentResolver.SYNC_ERROR_INTERNAL;
23709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("we are not in an error state, " + syncResult);
23719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2373918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        private void manageSyncNotificationLocked() {
23749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean shouldCancel;
23759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean shouldInstall;
23769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2377918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (mActiveSyncContexts.isEmpty()) {
23789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSyncNotificationInfo.startTime = null;
23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we aren't syncing. if the notification is active then remember that we need
23819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // to cancel it and then clear out the info
23829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                shouldCancel = mSyncNotificationInfo.isActive;
23839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                shouldInstall = false;
23849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
23859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we are syncing
23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final long now = SystemClock.elapsedRealtime();
23879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSyncNotificationInfo.startTime == null) {
23889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mSyncNotificationInfo.startTime = now;
23899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
23909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2391918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                // there are three cases:
2392918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                // - the notification is up: do nothing
23939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // - the notification is not up but it isn't time yet: don't install
23949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // - the notification is not up and it is time: need to install
23959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSyncNotificationInfo.isActive) {
2397918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    shouldInstall = shouldCancel = false;
23989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
2399918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    // it isn't currently up, so there is nothing to cancel
2400918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    shouldCancel = false;
2401918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final boolean timeToShowNotification =
24039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            now > mSyncNotificationInfo.startTime + SYNC_NOTIFICATION_DELAY;
2404918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    if (timeToShowNotification) {
2405918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        shouldInstall = true;
2406918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    } else {
2407918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        // show the notification immediately if this is a manual sync
2408918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        shouldInstall = false;
2409918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        for (ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
2410918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            final boolean manualSync = activeSyncContext.mSyncOperation.extras
2411918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                    .getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
2412918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            if (manualSync) {
2413918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                shouldInstall = true;
2414918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                                break;
2415918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            }
2416918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        }
2417918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    }
24189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
24199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (shouldCancel && !shouldInstall) {
24229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mNeedSyncActiveNotification = false;
24239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sendSyncStateIntent();
24249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSyncNotificationInfo.isActive = false;
24259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (shouldInstall) {
24289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mNeedSyncActiveNotification = true;
24299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sendSyncStateIntent();
24309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSyncNotificationInfo.isActive = true;
24319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2434918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        private void manageSyncAlarmLocked(long nextPeriodicEventElapsedTime,
2435918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                long nextPendingEventElapsedTime) {
24369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // in each of these cases the sync loop will be kicked, which will cause this
24379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // method to be called again
24389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mDataConnectionIsConnected) return;
24399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mStorageIsLow) return;
24409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2441918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // When the status bar notification should be raised
2442918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            final long notificationTime =
2443918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    (!mSyncHandler.mSyncNotificationInfo.isActive
2444918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            && mSyncHandler.mSyncNotificationInfo.startTime != null)
2445918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            ? mSyncHandler.mSyncNotificationInfo.startTime + SYNC_NOTIFICATION_DELAY
2446918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            : Long.MAX_VALUE;
2447918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2448918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // When we should consider canceling an active sync
2449918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            long earliestTimeoutTime = Long.MAX_VALUE;
2450918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
2451918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                final long currentSyncTimeoutTime =
2452918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        currentSyncContext.mTimeoutStartTime + MAX_TIME_PER_SYNC;
2453918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
2454918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "manageSyncAlarm: active sync, mTimeoutStartTime + MAX is "
2455918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            + currentSyncTimeoutTime);
24569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2457918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (earliestTimeoutTime > currentSyncTimeoutTime) {
2458918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    earliestTimeoutTime = currentSyncTimeoutTime;
24599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
24609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2462918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
2463918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                Log.v(TAG, "manageSyncAlarm: notificationTime is " + notificationTime);
2464918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
2465918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2466918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
2467918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                Log.v(TAG, "manageSyncAlarm: earliestTimeoutTime is " + earliestTimeoutTime);
2468918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
2469918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2470918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
2471918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                Log.v(TAG, "manageSyncAlarm: nextPeriodicEventElapsedTime is "
2472918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        + nextPeriodicEventElapsedTime);
2473918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
2474918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
2475918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                Log.v(TAG, "manageSyncAlarm: nextPendingEventElapsedTime is "
2476918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                        + nextPendingEventElapsedTime);
2477918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
2478918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2479918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            long alarmTime = Math.min(notificationTime, earliestTimeoutTime);
2480918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            alarmTime = Math.min(alarmTime, nextPeriodicEventElapsedTime);
2481918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            alarmTime = Math.min(alarmTime, nextPendingEventElapsedTime);
2482918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2483918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            // Bound the alarm time.
2484918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            final long now = SystemClock.elapsedRealtime();
2485918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (alarmTime < now + SYNC_ALARM_TIMEOUT_MIN) {
2486918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
2487918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "manageSyncAlarm: the alarmTime is too small, "
2488918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            + alarmTime + ", setting to " + (now + SYNC_ALARM_TIMEOUT_MIN));
2489918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
2490918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                alarmTime = now + SYNC_ALARM_TIMEOUT_MIN;
2491918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            } else if (alarmTime > now + SYNC_ALARM_TIMEOUT_MAX) {
2492918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
2493918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "manageSyncAlarm: the alarmTime is too large, "
2494918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            + alarmTime + ", setting to " + (now + SYNC_ALARM_TIMEOUT_MIN));
24959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2496918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                alarmTime = now + SYNC_ALARM_TIMEOUT_MAX;
24979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
24989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // determine if we need to set or cancel the alarm
25009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean shouldSet = false;
25019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean shouldCancel = false;
25029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean alarmIsActive = mAlarmScheduleTime != null;
2503918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            final boolean needAlarm = alarmTime != Long.MAX_VALUE;
25049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (needAlarm) {
25059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!alarmIsActive || alarmTime < mAlarmScheduleTime) {
25069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    shouldSet = true;
25079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
25089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
25099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                shouldCancel = alarmIsActive;
25109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // set or cancel the alarm as directed
25139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ensureAlarmService();
25149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (shouldSet) {
2515918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
2516918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                    Log.v(TAG, "requesting that the alarm manager wake us up at elapsed time "
2517918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            + alarmTime + ", now is " + now + ", " + ((alarmTime - now) / 1000)
2518918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                            + " secs from now");
2519918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                }
25209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAlarmScheduleTime = alarmTime;
25219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime,
25229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mSyncAlarmIntent);
25239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (shouldCancel) {
25249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAlarmScheduleTime = null;
25259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAlarmService.cancel(mSyncAlarmIntent);
25269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void sendSyncStateIntent() {
25309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent syncStateIntent = new Intent(Intent.ACTION_SYNC_STATE_CHANGED);
2531a34f1ad7c3a68d971e6332aa2fb1c16d083920b3Dianne Hackborn            syncStateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
25329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            syncStateIntent.putExtra("active", mNeedSyncActiveNotification);
2533918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            syncStateIntent.putExtra("failing", false);
2534cd75706117432e33d11639e675bcff50479a6bb9Amith Yamasani            mContext.sendBroadcastAsUser(syncStateIntent, UserHandle.OWNER);
25359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2537d9d2f1140b52fd0c014e9deac59f6000564b7e84Fred Quintana        private void installHandleTooManyDeletesNotification(Account account, String authority,
25384120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                long numDeletes, int userId) {
25399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mNotificationMgr == null) return;
2540c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana
2541c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana            final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
2542c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana                    authority, 0 /* flags */);
2543c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana            if (providerInfo == null) {
2544c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana                return;
2545c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana            }
2546c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana            CharSequence authorityName = providerInfo.loadLabel(mContext.getPackageManager());
2547c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana
2548b19e62add0a747127952862bb7bea0b73379edccFred Quintana            Intent clickIntent = new Intent(mContext, SyncActivityTooManyDeletes.class);
25499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            clickIntent.putExtra("account", account);
255086135d3240a50f9224b49fb8407a1c86cae0e1b9Tadashi G. Takaoka            clickIntent.putExtra("authority", authority);
2551c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana            clickIntent.putExtra("provider", authorityName.toString());
25529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            clickIntent.putExtra("numDeletes", numDeletes);
25539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isActivityAvailable(clickIntent)) {
25559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "No activity found to handle too many deletes.");
25569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
25579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final PendingIntent pendingIntent = PendingIntent
25604120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                    .getActivityAsUser(mContext, 0, clickIntent,
25614120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                            PendingIntent.FLAG_CANCEL_CURRENT, null, new UserHandle(userId));
25629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
25649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    R.string.contentServiceTooManyDeletesNotificationDesc);
25659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Notification notification =
25679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new Notification(R.drawable.stat_notify_sync_error,
25689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mContext.getString(R.string.contentServiceSync),
25699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        System.currentTimeMillis());
25709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            notification.setLatestEventInfo(mContext,
25719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mContext.getString(R.string.contentServiceSyncNotificationTitle),
2572c848b7023bcb19d7a392eb9f4669e56906e5382cFred Quintana                    String.format(tooManyDeletesDescFormat.toString(), authorityName),
25739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pendingIntent);
25749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            notification.flags |= Notification.FLAG_ONGOING_EVENT;
25754120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn            mNotificationMgr.notifyAsUser(null, account.hashCode() ^ authority.hashCode(),
25764120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                    notification, new UserHandle(userId));
25779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
25809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Checks whether an activity exists on the system image for the given intent.
25819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
25829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param intent The intent for an activity.
25839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return Whether or not an activity exists.
25849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
25859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean isActivityAvailable(Intent intent) {
25869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PackageManager pm = mContext.getPackageManager();
25879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
25889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int listSize = list.size();
25899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < listSize; i++) {
25909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ResolveInfo resolveInfo = list.get(i);
25919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
25929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        != 0) {
25939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return true;
25949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
25959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
25989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public long insertStartSyncEvent(SyncOperation syncOperation) {
26019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int source = syncOperation.syncSource;
26029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long now = System.currentTimeMillis();
26039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2604231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            EventLog.writeEvent(2720, syncOperation.authority,
260544f574781545781c31db3dcf495ed08763073f75Doug Zongker                                SyncStorageEngine.EVENT_START, source,
260644f574781545781c31db3dcf495ed08763073f75Doug Zongker                                syncOperation.account.name.hashCode());
26079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSyncStorageEngine.insertStartSyncEvent(
260904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    syncOperation.account, syncOperation.userId, syncOperation.authority,
2610dc47556cb37b6f25faceb5eb97cef60d384b55fbFred Quintana                    now, source, syncOperation.isInitialization());
26119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
26149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int upstreamActivity, int downstreamActivity, long elapsedTime) {
2615231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            EventLog.writeEvent(2720, syncOperation.authority,
261644f574781545781c31db3dcf495ed08763073f75Doug Zongker                                SyncStorageEngine.EVENT_STOP, syncOperation.syncSource,
261744f574781545781c31db3dcf495ed08763073f75Doug Zongker                                syncOperation.account.name.hashCode());
26189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
261977c560f3d7891d9ae1ad714b5f65a22ff4f4c06bFred Quintana            mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
2620c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                    resultMessage, downstreamActivity, upstreamActivity);
26219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2623918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana
2624918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    private boolean isSyncStillActive(ActiveSyncContext activeSyncContext) {
2625918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        for (ActiveSyncContext sync : mActiveSyncContexts) {
2626918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            if (sync == activeSyncContext) {
2627918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana                return true;
2628918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana            }
2629918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        }
2630918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana        return false;
2631918339ab8255f8e1d03d8448ab1d9036c7c15173Fred Quintana    }
26329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2633