blob: 9f80a83038afc4ed5ab1cc3685022bf63a147c9a [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.content;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Makoto Onukidecc5ba2019-01-15 09:34:05 -080019import static com.android.server.content.SyncLogger.logSafe;
20
Alon Alberte0bde332011-09-22 14:26:16 -070021import android.accounts.Account;
Amith Yamasanif29f2362012-04-05 18:29:52 -070022import android.accounts.AccountAndUser;
Alon Alberte0bde332011-09-22 14:26:16 -070023import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070024import android.accounts.AccountManagerInternal;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080025import android.annotation.NonNull;
Makoto Onuki3ab77812018-07-09 14:29:33 -070026import android.annotation.Nullable;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080027import android.annotation.UserIdInt;
Fred Quintana33e44692011-12-05 15:04:16 -080028import android.app.ActivityManager;
Amith Yamasani9422bdc2013-04-10 16:58:19 -070029import android.app.AppGlobals;
Alon Alberte0bde332011-09-22 14:26:16 -070030import android.app.Notification;
31import android.app.NotificationManager;
32import android.app.PendingIntent;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000033import android.app.job.JobInfo;
34import android.app.job.JobScheduler;
Makoto Onuki75ad2492018-03-28 14:42:42 -070035import android.app.usage.UsageStatsManagerInternal;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080036import android.content.BroadcastReceiver;
37import android.content.ComponentName;
38import android.content.ContentResolver;
Makoto Onuki75ad2492018-03-28 14:42:42 -070039import android.content.ContentResolver.SyncExemption;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080040import android.content.Context;
41import android.content.ISyncAdapter;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080042import android.content.ISyncAdapterUnsyncableAccountCallback;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080043import android.content.ISyncContext;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080044import android.content.Intent;
45import android.content.IntentFilter;
Matthew Williamsfa774182013-06-18 15:44:11 -070046import android.content.PeriodicSync;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080047import android.content.ServiceConnection;
48import android.content.SyncActivityTooManyDeletes;
49import android.content.SyncAdapterType;
50import android.content.SyncAdaptersCache;
51import android.content.SyncInfo;
52import android.content.SyncResult;
53import android.content.SyncStatusInfo;
Makoto Onuki94986212018-04-11 16:24:46 -070054import android.content.SyncStatusInfo.Stats;
Alon Alberte0bde332011-09-22 14:26:16 -070055import android.content.pm.ApplicationInfo;
Amith Yamasani9422bdc2013-04-10 16:58:19 -070056import android.content.pm.PackageInfo;
Alon Alberte0bde332011-09-22 14:26:16 -070057import android.content.pm.PackageManager;
Todd Kennedy0eb97382017-10-03 16:57:22 -070058import android.content.pm.PackageManager.NameNotFoundException;
Makoto Onukid4764302018-03-30 17:32:57 -070059import android.content.pm.PackageManagerInternal;
Alon Alberte0bde332011-09-22 14:26:16 -070060import android.content.pm.ProviderInfo;
61import android.content.pm.RegisteredServicesCache;
62import android.content.pm.RegisteredServicesCacheListener;
63import android.content.pm.ResolveInfo;
Amith Yamasani04e0d262012-02-14 11:50:53 -080064import android.content.pm.UserInfo;
Matthew Williams8b76d202015-05-03 18:16:25 -070065import android.database.ContentObserver;
Alon Alberte0bde332011-09-22 14:26:16 -070066import android.net.ConnectivityManager;
67import android.net.NetworkInfo;
Matthew Williams1967c8d2015-06-19 19:03:13 -070068import android.net.TrafficStats;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080069import android.os.BatteryStats;
Makoto Onukibbf6d8c2017-08-11 12:11:39 -070070import android.os.Binder;
Makoto Onukidd4b14f2017-08-17 14:03:48 -070071import android.os.Build;
Fred Quintana918339a2010-10-05 14:00:39 -070072import android.os.Bundle;
73import android.os.Handler;
Makoto Onukie08a5c22018-04-27 13:28:46 -070074import android.os.HandlerThread;
Fred Quintana918339a2010-10-05 14:00:39 -070075import android.os.IBinder;
76import android.os.Looper;
77import android.os.Message;
78import android.os.PowerManager;
Makoto Onuki75ad2492018-03-28 14:42:42 -070079import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070080import android.os.RemoteCallback;
Fred Quintana918339a2010-10-05 14:00:39 -070081import android.os.RemoteException;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080082import android.os.ServiceManager;
Fred Quintana918339a2010-10-05 14:00:39 -070083import android.os.SystemClock;
84import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070085import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070086import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070087import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.text.format.Time;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.util.EventLog;
91import android.util.Log;
Fred Quintana307da1a2010-01-21 14:24:20 -080092import android.util.Pair;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000093import android.util.Slog;
Makoto Onuki3ab77812018-07-09 14:29:33 -070094import android.util.SparseBooleanArray;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000095
Alon Albert8e285552012-09-17 15:05:27 -070096import com.android.internal.R;
Makoto Onuki056a9752018-05-08 15:21:56 -070097import com.android.internal.annotations.GuardedBy;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080098import com.android.internal.app.IBatteryStats;
Makoto Onukid4764302018-03-30 17:32:57 -070099import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
100import com.android.internal.notification.SystemNotificationChannels;
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700101import com.android.internal.os.BackgroundThread;
Makoto Onukid4764302018-03-30 17:32:57 -0700102import com.android.internal.util.ArrayUtils;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700103import com.android.internal.util.IndentingPrintWriter;
Makoto Onuki94986212018-04-11 16:24:46 -0700104import com.android.internal.util.function.QuadConsumer;
Makoto Onukid4764302018-03-30 17:32:57 -0700105import com.android.server.DeviceIdleController;
106import com.android.server.LocalServices;
107import com.android.server.SystemService;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800108import com.android.server.accounts.AccountManagerService;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000109import com.android.server.backup.AccountSyncSettingsBackupHelper;
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700110import com.android.server.content.SyncStorageEngine.AuthorityInfo;
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700111import com.android.server.content.SyncStorageEngine.EndPoint;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800112import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
Makoto Onukid4764302018-03-30 17:32:57 -0700113import com.android.server.job.JobSchedulerInternal;
114
115import com.google.android.collect.Lists;
116import com.google.android.collect.Maps;
Alon Albert8e285552012-09-17 15:05:27 -0700117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119import java.io.PrintWriter;
120import java.util.ArrayList;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000121import java.util.Arrays;
Fred Quintana918339a2010-10-05 14:00:39 -0700122import java.util.Collection;
123import java.util.Collections;
Alon Alberte0bde332011-09-22 14:26:16 -0700124import java.util.Comparator;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000125import java.util.HashMap;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000126import java.util.HashSet;
127import java.util.List;
128import java.util.Map;
Matthew Williams9ad2c842015-10-16 12:01:31 -0700129import java.util.Objects;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000130import java.util.Random;
131import java.util.Set;
Makoto Onuki94986212018-04-11 16:24:46 -0700132import java.util.function.Function;
Makoto Onuki15e7a252017-06-08 17:12:05 -0700133import java.util.function.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134
135/**
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000136 * Implementation details:
137 * All scheduled syncs will be passed on to JobScheduler as jobs
138 * (See {@link #scheduleSyncOperationH(SyncOperation, long)}. This function schedules a job
139 * with JobScheduler with appropriate delay and constraints (according to backoffs and extras).
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000140 * The scheduleSyncOperationH function also assigns a unique jobId to each
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000141 * SyncOperation.
142 *
143 * Periodic Syncs:
144 * Each periodic sync is scheduled as a periodic job. If a periodic sync fails, we create a new
145 * one off SyncOperation and set its {@link SyncOperation#sourcePeriodicId} field to the jobId of the
146 * periodic sync. We don't allow the periodic job to run while any job initiated by it is pending.
147 *
148 * Backoffs:
149 * Each {@link EndPoint} has a backoff associated with it. When a SyncOperation fails, we increase
150 * the backoff on the authority. Then we reschedule all syncs associated with that authority to
151 * run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
152 * are rescheduled. A rescheduled sync will get a new jobId.
153 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 * @hide
155 */
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700156public class SyncManager {
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700157 static final String TAG = "SyncManager";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700159 private static final boolean DEBUG_ACCOUNT_ACCESS = false;
160
Makoto Onukib47e8942017-09-18 14:03:03 -0700161 // Only do the check on a debuggable build.
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700162 private static final boolean ENABLE_SUSPICIOUS_CHECK = Build.IS_DEBUGGABLE;
163
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 /** Delay a sync due to local changes this long. In milliseconds */
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700165 private static final long LOCAL_SYNC_DELAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700167 static {
Fred Quintana918339a2010-10-05 14:00:39 -0700168 LOCAL_SYNC_DELAY =
169 SystemProperties.getLong("sync.local_sync_delay", 30 * 1000 /* 30 seconds */);
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 /**
Fred Quintana8570f742010-02-18 10:32:54 -0800173 * How long to wait before retrying a sync that failed due to one already being in progress.
174 */
175 private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
176
Matthew Williams92a1c092014-08-25 19:18:32 -0700177 /**
Matthew Williams1967c8d2015-06-19 19:03:13 -0700178 * How often to periodically poll network traffic for an adapter performing a sync to determine
179 * whether progress is being made.
180 */
181 private static final long SYNC_MONITOR_WINDOW_LENGTH_MILLIS = 60 * 1000; // 60 seconds
182
183 /**
184 * How many bytes must be transferred (Tx + Rx) over the period of time defined by
185 * {@link #SYNC_MONITOR_WINDOW_LENGTH_MILLIS} for the sync to be considered to be making
186 * progress.
187 */
188 private static final int SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES = 10; // 10 bytes
189
190 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000191 * If a previously scheduled sync becomes ready and we are low on storage, it gets
192 * pushed back for this amount of time.
193 */
194 private static final long SYNC_DELAY_ON_LOW_STORAGE = 60*60*1000; // 1 hour
195
196 /**
197 * If a sync becomes ready and it conflicts with an already running sync, it gets
198 * pushed back for this amount of time.
199 */
200 private static final long SYNC_DELAY_ON_CONFLICT = 10*1000; // 10 seconds
Fred Quintana3ec47302010-03-10 10:08:31 -0800201
Shreyas Basargefa272532016-03-09 16:52:48 +0000202 /**
203 * Generate job ids in the range [MIN_SYNC_JOB_ID, MAX_SYNC_JOB_ID) to avoid conflicts with
204 * other jobs scheduled by the system process.
205 */
206 private static final int MIN_SYNC_JOB_ID = 100000;
207 private static final int MAX_SYNC_JOB_ID = 110000;
208
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800209 private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/";
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700210 private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
Fred Quintana918339a2010-10-05 14:00:39 -0700211 private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
212
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700213
214 private static final int SYNC_OP_STATE_VALID = 0;
215 private static final int SYNC_OP_STATE_INVALID = 1;
216 private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
217
Philip P. Moltmann486b2412018-01-03 11:29:01 -0800218 /** Flags used when connecting to a sync adapter service */
219 private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
220 | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
221
Makoto Onuki056a9752018-05-08 15:21:56 -0700222 /** Singleton instance. */
223 @GuardedBy("SyncManager.class")
224 private static SyncManager sInstance;
225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
Amith Yamasani04e0d262012-02-14 11:50:53 -0800228 private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
229
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700230 // TODO: add better locking around mRunningAccounts
231 private volatile AccountAndUser[] mRunningAccounts = INITIAL_ACCOUNTS_ARRAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
Fred Quintana918339a2010-10-05 14:00:39 -0700233 volatile private PowerManager.WakeLock mSyncManagerWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 volatile private boolean mDataConnectionIsConnected = false;
235 volatile private boolean mStorageIsLow = false;
Dianne Hackborn4870e9d2015-04-08 16:55:47 -0700236 volatile private boolean mDeviceIsIdle = false;
Dianne Hackborn627dfa12015-11-11 18:10:30 -0800237 volatile private boolean mReportedSyncActive = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 private final NotificationManager mNotificationMgr;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800240 private final IBatteryStats mBatteryStats;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000241 private JobScheduler mJobScheduler;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000242 private JobSchedulerInternal mJobSchedulerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700244 private SyncStorageEngine mSyncStorageEngine;
Jeff Sharkeya706e2f2012-10-16 12:02:42 -0700245
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700246 protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
Fred Quintanaf892fb32009-08-27 21:32:08 -0700248 // Synchronized on "this". Instead of using this directly one should instead call
249 // its accessor, getConnManager().
250 private ConnectivityManager mConnManagerDoNotUseDirectly;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251
Matthew Williams8b76d202015-05-03 18:16:25 -0700252 /** Track whether the device has already been provisioned. */
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000253 private volatile boolean mProvisioned;
Matthew Williams8b76d202015-05-03 18:16:25 -0700254
Makoto Onuki94986212018-04-11 16:24:46 -0700255 protected final SyncAdaptersCache mSyncAdapters;
Fred Quintana718d8a22009-04-29 17:53:20 -0700256
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000257 private final Random mRand;
258
Makoto Onukia9dca242017-06-21 17:06:49 -0700259 private final SyncLogger mLogger;
260
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000261 private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
262 for (JobInfo job: pendingJobs) {
263 if (job.getId() == jobId) {
264 return true;
265 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000266 }
267 for (ActiveSyncContext asc: mActiveSyncContexts) {
268 if (asc.mSyncOperation.jobId == jobId) {
269 return true;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000270 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000271 }
272 return false;
273 }
274
275 private int getUnusedJobIdH() {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000276 int newJobId;
277 do {
278 newJobId = MIN_SYNC_JOB_ID + mRand.nextInt(MAX_SYNC_JOB_ID - MIN_SYNC_JOB_ID);
279 } while (isJobIdInUseLockedH(newJobId,
280 mJobSchedulerInternal.getSystemScheduledPendingJobs()));
281 return newJobId;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000282 }
283
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000284 private List<SyncOperation> getAllPendingSyncs() {
285 verifyJobScheduler();
286 List<JobInfo> pendingJobs = mJobSchedulerInternal.getSystemScheduledPendingJobs();
287 List<SyncOperation> pendingSyncs = new ArrayList<SyncOperation>(pendingJobs.size());
288 for (JobInfo job: pendingJobs) {
289 SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
290 if (op != null) {
291 pendingSyncs.add(op);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000292 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000293 }
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000294 return pendingSyncs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000295 }
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700296
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700297 private final BroadcastReceiver mStorageIntentReceiver =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700299 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 public void onReceive(Context context, Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 String action = intent.getAction();
302 if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
303 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000304 Slog.v(TAG, "Internal storage is low.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 }
306 mStorageIsLow = true;
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700307 cancelActiveSync(
308 SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
Makoto Onukia9dca242017-06-21 17:06:49 -0700309 null /* any sync */,
310 "storage low");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
312 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000313 Slog.v(TAG, "Internal storage is ok.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 }
315 mStorageIsLow = false;
Makoto Onukia9dca242017-06-21 17:06:49 -0700316 rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
317 "storage ok");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 }
319 }
320 };
321
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700322 private final BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700323 @Override
Amith Yamasanid648a602012-09-26 15:06:10 -0700324 public void onReceive(Context context, Intent intent) {
Makoto Onukifb636cc2017-12-07 15:46:26 -0800325 EndPoint target = new EndPoint(null, null, getSendingUserId());
Shreyas Basargedcb88c82016-02-03 00:09:18 +0000326 updateRunningAccounts(target /* sync targets for user */);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700327 }
328 };
329
Fred Quintanab3029c32010-04-06 13:27:12 -0700330 private final PowerManager mPowerManager;
Ashish Sharma69d95de2012-04-11 17:27:24 -0700331
Amith Yamasani9535c912012-10-10 21:48:33 -0700332 private final UserManager mUserManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700333
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700334 private final AccountManager mAccountManager;
335
336 private final AccountManagerInternal mAccountManagerInternal;
337
Svet Ganov973edd192016-09-08 20:15:55 -0700338 private final PackageManagerInternal mPackageManagerInternal;
339
Amith Yamasani258848d2012-08-10 17:06:33 -0700340 private List<UserInfo> getAllUsers() {
Amith Yamasani9535c912012-10-10 21:48:33 -0700341 return mUserManager.getUsers();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800342 }
343
344 private boolean containsAccountAndUser(AccountAndUser[] accounts, Account account, int userId) {
345 boolean found = false;
346 for (int i = 0; i < accounts.length; i++) {
347 if (accounts[i].userId == userId
348 && accounts[i].account.equals(account)) {
349 found = true;
350 break;
351 }
352 }
353 return found;
354 }
355
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000356 /** target indicates endpoints that should be synced after account info is updated. */
357 private void updateRunningAccounts(EndPoint target) {
358 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_ACCOUNTS_UPDATED");
振淦王60a74312015-12-01 16:37:31 +0800359 // Update accounts in handler thread.
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000360 Message m = mSyncHandler.obtainMessage(SyncHandler.MESSAGE_ACCOUNTS_UPDATED);
361 m.obj = target;
362 m.sendToTarget();
Fred Quintanad9d2f112009-04-23 13:36:27 -0700363 }
364
Makoto Onuki3ab77812018-07-09 14:29:33 -0700365 private void removeStaleAccounts() {
Amith Yamasanidb6a14c2012-10-17 21:16:52 -0700366 for (UserInfo user : mUserManager.getUsers(true)) {
367 // Skip any partially created/removed users
368 if (user.partial) continue;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700369 Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(
370 user.id, mContext.getOpPackageName());
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000371
Makoto Onuki3ab77812018-07-09 14:29:33 -0700372 mSyncStorageEngine.removeStaleAccounts(accountsForUser, user.id);
Jeff Sharkey8f55d112012-10-11 11:00:21 -0700373 }
374 }
375
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 private BroadcastReceiver mConnectivityIntentReceiver =
377 new BroadcastReceiver() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000378 @Override
379 public void onReceive(Context context, Intent intent) {
380 final boolean wasConnected = mDataConnectionIsConnected;
Alon Alberted1d2532011-02-15 14:02:14 -0800381
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000382 // Don't use the intent to figure out if network is connected, just check
383 // ConnectivityManager directly.
384 mDataConnectionIsConnected = readDataConnectionState();
385 if (mDataConnectionIsConnected) {
386 if (!wasConnected) {
387 if (Log.isLoggable(TAG, Log.VERBOSE)) {
388 Slog.v(TAG, "Reconnection detected: clearing all backoffs");
389 }
Makoto Onukia9dca242017-06-21 17:06:49 -0700390 // Note the location of this code was wrong from nyc to oc; fixed in DR.
391 clearAllBackoffs("network reconnect");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000392 }
Matthew Williams119aac92014-09-28 20:42:23 -0700393 }
Alon Alberted1d2532011-02-15 14:02:14 -0800394 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000395 };
396
Makoto Onukia9dca242017-06-21 17:06:49 -0700397 private void clearAllBackoffs(String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000398 mSyncStorageEngine.clearAllBackoffsLocked();
Makoto Onukia9dca242017-06-21 17:06:49 -0700399 rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000400 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401
Alon Albert1bad83a2011-02-16 10:29:56 -0800402 private boolean readDataConnectionState() {
Alon Alberted1d2532011-02-15 14:02:14 -0800403 NetworkInfo networkInfo = getConnectivityManager().getActiveNetworkInfo();
404 return (networkInfo != null) && networkInfo.isConnected();
405 }
406
Makoto Onukie7b02982017-08-24 14:23:36 -0700407 private String getJobStats() {
408 JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
409 return "JobStats: "
410 + ((js == null) ? "(JobSchedulerInternal==null)"
411 : js.getPersistStats().toString());
412 }
413
Dianne Hackborn55280a92009-05-07 15:53:46 -0700414 private BroadcastReceiver mShutdownIntentReceiver =
415 new BroadcastReceiver() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000416 @Override
417 public void onReceive(Context context, Intent intent) {
418 Log.w(TAG, "Writing sync state before shutdown...");
419 getSyncStorageEngine().writeAllState();
Makoto Onukie7b02982017-08-24 14:23:36 -0700420
421 mLogger.log(getJobStats());
Makoto Onukife224e02017-06-29 14:11:14 -0700422 mLogger.log("Shutting down.");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000423 }
424 };
Dianne Hackborn55280a92009-05-07 15:53:46 -0700425
Makoto Onuki94986212018-04-11 16:24:46 -0700426 private final BroadcastReceiver mOtherIntentsReceiver =
427 new BroadcastReceiver() {
428 @Override
429 public void onReceive(Context context, Intent intent) {
430 if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
431 mSyncStorageEngine.setClockValid();
432 return;
433 }
434 }
435 };
436
Amith Yamasani13593602012-03-22 16:16:17 -0700437 private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
438 @Override
439 public void onReceive(Context context, Intent intent) {
Alon Albert8e285552012-09-17 15:05:27 -0700440 String action = intent.getAction();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700441 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
442 if (userId == UserHandle.USER_NULL) return;
443
Alon Albert8e285552012-09-17 15:05:27 -0700444 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700445 onUserRemoved(userId);
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700446 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
447 onUserUnlocked(userId);
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -0700448 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
449 onUserStopped(userId);
Alon Albert8e285552012-09-17 15:05:27 -0700450 }
Amith Yamasani13593602012-03-22 16:16:17 -0700451 }
452 };
453
Makoto Onukie08a5c22018-04-27 13:28:46 -0700454 private final HandlerThread mThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 private final SyncHandler mSyncHandler;
Makoto Onukiaad2b512018-02-07 09:31:46 -0800456 private final SyncManagerConstants mConstants;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457
Makoto Onuki3ab77812018-07-09 14:29:33 -0700458 @GuardedBy("mUnlockedUsers")
459 private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
Fred Quintana4f9cfc52009-09-02 15:20:23 -0700460
Fred Quintanaf892fb32009-08-27 21:32:08 -0700461 private ConnectivityManager getConnectivityManager() {
462 synchronized (this) {
463 if (mConnManagerDoNotUseDirectly == null) {
464 mConnManagerDoNotUseDirectly = (ConnectivityManager)mContext.getSystemService(
465 Context.CONNECTIVITY_SERVICE);
466 }
467 return mConnManagerDoNotUseDirectly;
468 }
469 }
470
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000471 /**
472 * Cancel all unnecessary jobs. This function will be run once after every boot.
473 */
474 private void cleanupJobs() {
475 // O(n^2) in number of jobs, so we run this on the background thread.
476 mSyncHandler.postAtFrontOfQueue(new Runnable() {
477 @Override
478 public void run() {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000479 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000480 Set<String> cleanedKeys = new HashSet<String>();
481 for (SyncOperation opx: ops) {
482 if (cleanedKeys.contains(opx.key)) {
483 continue;
484 }
485 cleanedKeys.add(opx.key);
486 for (SyncOperation opy: ops) {
487 if (opx == opy) {
488 continue;
489 }
490 if (opx.key.equals(opy.key)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700491 mLogger.log("Removing duplicate sync: ", opy);
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700492 cancelJob(opy, "cleanupJobs() x=" + opx + " y=" + opy);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000493 }
494 }
495 }
496 }
497 });
498 }
499
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000500 private synchronized void verifyJobScheduler() {
501 if (mJobScheduler != null) {
502 return;
503 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700504 final long token = Binder.clearCallingIdentity();
505 try {
506 if (Log.isLoggable(TAG, Log.VERBOSE)) {
507 Log.d(TAG, "initializing JobScheduler object.");
508 }
509 mJobScheduler = (JobScheduler) mContext.getSystemService(
510 Context.JOB_SCHEDULER_SERVICE);
511 mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
512 // Get all persisted syncs from JobScheduler
513 List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
514
515 int numPersistedPeriodicSyncs = 0;
516 int numPersistedOneshotSyncs = 0;
517 for (JobInfo job : pendingJobs) {
518 SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
519 if (op != null) {
520 if (op.isPeriodic) {
521 numPersistedPeriodicSyncs++;
522 } else {
523 numPersistedOneshotSyncs++;
524 // Set the pending status of this EndPoint to true. Pending icon is
525 // shown on the settings activity.
526 mSyncStorageEngine.markPending(op.target, true);
527 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000528 }
529 }
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700530 final String summary = "Loaded persisted syncs: "
531 + numPersistedPeriodicSyncs + " periodic syncs, "
532 + numPersistedOneshotSyncs + " oneshot syncs, "
533 + (pendingJobs.size()) + " total system server jobs, "
Makoto Onukie7b02982017-08-24 14:23:36 -0700534 + getJobStats();
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700535 Slog.i(TAG, summary);
536 mLogger.log(summary);
537
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700538 cleanupJobs();
539
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700540 if (ENABLE_SUSPICIOUS_CHECK &&
541 (numPersistedPeriodicSyncs == 0) && likelyHasPeriodicSyncs()) {
542 Slog.wtf(TAG, "Device booted with no persisted periodic syncs: " + summary);
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700543 }
544 } finally {
545 Binder.restoreCallingIdentity(token);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000546 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700547 }
548
549 /**
550 * @return whether the device most likely has some periodic syncs.
551 */
552 private boolean likelyHasPeriodicSyncs() {
553 try {
Makoto Onukib47e8942017-09-18 14:03:03 -0700554 // Each sync adapter has a daily periodic sync by default, but sync adapters can remove
555 // them by themselves. So here, we use an arbitrary threshold. If there are more than
556 // this many sync endpoints, surely one of them should have a periodic sync...
557 return mSyncStorageEngine.getAuthorityCount() >= 6;
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700558 } catch (Throwable th) {
559 // Just in case.
560 }
561 return false;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000562 }
563
564 private JobScheduler getJobScheduler() {
565 verifyJobScheduler();
566 return mJobScheduler;
567 }
568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 public SyncManager(Context context, boolean factoryTest) {
Makoto Onuki056a9752018-05-08 15:21:56 -0700570 synchronized (SyncManager.class) {
571 if (sInstance == null) {
572 sInstance = this;
573 } else {
574 Slog.wtf(TAG, "SyncManager instantiated multiple times");
575 }
576 }
577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 // Initialize the SyncStorageEngine first, before registering observers
579 // and creating threads and so on; it may fail if the disk is full.
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700580 mContext = context;
Amith Yamasani9535c912012-10-10 21:48:33 -0700581
Makoto Onukia9dca242017-06-21 17:06:49 -0700582 mLogger = SyncLogger.getInstance();
583
Makoto Onuki6963bea72017-12-12 10:42:39 -0800584 SyncStorageEngine.init(context, BackgroundThread.get().getLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 mSyncStorageEngine = SyncStorageEngine.getSingleton();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800586 mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700587 @Override
Makoto Onuki61283ec2018-01-31 17:22:36 -0800588 public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras,
Makoto Onukie183a402018-08-29 11:46:41 -0700589 @SyncExemption int syncExemptionFlag, int callingUid, int callingPid) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000590 scheduleSync(info.account, info.userId, reason, info.provider, extras,
Makoto Onukie183a402018-08-29 11:46:41 -0700591 AuthorityInfo.UNDEFINED, syncExemptionFlag, callingUid, callingPid, null);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000592 }
593 });
594
595 mSyncStorageEngine.setPeriodicSyncAddedListener(
596 new SyncStorageEngine.PeriodicSyncAddedListener() {
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000597 @Override
598 public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
599 long flex) {
600 updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
601 }
602 });
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000603
604 mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
605 @Override
606 public void onAuthorityRemoved(EndPoint removedAuthority) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700607 removeSyncsForAuthority(removedAuthority, "onAuthorityRemoved");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800608 }
609 });
610
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700611 mSyncAdapters = new SyncAdaptersCache(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612
Makoto Onukie08a5c22018-04-27 13:28:46 -0700613 mThread = new HandlerThread("SyncManager", android.os.Process.THREAD_PRIORITY_BACKGROUND);
614 mThread.start();
615 mSyncHandler = new SyncHandler(mThread.getLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616
Fred Quintana44037e62010-01-21 13:14:49 -0800617 mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700618 @Override
619 public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
Fred Quintana44037e62010-01-21 13:14:49 -0800620 if (!removed) {
Alon Albert57286f92012-10-09 14:21:38 -0700621 scheduleSync(null, UserHandle.USER_ALL,
622 SyncOperation.REASON_SERVICE_CHANGED,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800623 type.authority, null, AuthorityInfo.UNDEFINED,
Makoto Onukie183a402018-08-29 11:46:41 -0700624 ContentResolver.SYNC_EXEMPTION_NONE,
625 Process.myUid(), -1, null);
Fred Quintana44037e62010-01-21 13:14:49 -0800626 }
627 }
628 }, mSyncHandler);
Fred Quintana718d8a22009-04-29 17:53:20 -0700629
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000630 mRand = new Random(System.currentTimeMillis());
Makoto Onukiaad2b512018-02-07 09:31:46 -0800631 mConstants = new SyncManagerConstants(context);
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
634 context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
635
636 intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
637 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
638 context.registerReceiver(mStorageIntentReceiver, intentFilter);
639
Dianne Hackborn55280a92009-05-07 15:53:46 -0700640 intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
641 intentFilter.setPriority(100);
642 context.registerReceiver(mShutdownIntentReceiver, intentFilter);
643
Amith Yamasani13593602012-03-22 16:16:17 -0700644 intentFilter = new IntentFilter();
645 intentFilter.addAction(Intent.ACTION_USER_REMOVED);
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700646 intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -0700647 intentFilter.addAction(Intent.ACTION_USER_STOPPED);
Alon Albert8e285552012-09-17 15:05:27 -0700648 mContext.registerReceiverAsUser(
649 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
Amith Yamasani13593602012-03-22 16:16:17 -0700650
Makoto Onuki94986212018-04-11 16:24:46 -0700651 intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
652 context.registerReceiver(mOtherIntentsReceiver, intentFilter);
653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 if (!factoryTest) {
655 mNotificationMgr = (NotificationManager)
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000656 context.getSystemService(Context.NOTIFICATION_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 } else {
658 mNotificationMgr = null;
659 }
Fred Quintanab3029c32010-04-06 13:27:12 -0700660 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
Amith Yamasani9535c912012-10-10 21:48:33 -0700661 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700662 mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
663 mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
Svet Ganov973edd192016-09-08 20:15:55 -0700664 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700665
Svet Ganovf6d424f12016-09-20 20:18:53 -0700666 mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
667 // If the UID gained access to the account kick-off syncs lacking account access
668 if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
669 scheduleSync(account, UserHandle.getUserId(uid),
670 SyncOperation.REASON_ACCOUNTS_UPDATED,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800671 null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS,
Makoto Onukie183a402018-08-29 11:46:41 -0700672 ContentResolver.SYNC_EXEMPTION_NONE,
673 Process.myUid(), -2, null);
Svet Ganovf6d424f12016-09-20 20:18:53 -0700674 }
675 });
676
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800677 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
678 BatteryStats.SERVICE_NAME));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679
Fred Quintana918339a2010-10-05 14:00:39 -0700680 // This WakeLock is used to ensure that we stay awake while running the sync loop
681 // message handler. Normally we will hold a sync adapter wake lock while it is being
682 // synced but during the execution of the sync loop it might finish a sync for
683 // one sync adapter before starting the sync for the other sync adapter and we
684 // don't want the device to go to sleep during that window.
685 mSyncManagerWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
686 SYNC_LOOP_WAKE_LOCK);
687 mSyncManagerWakeLock.setReferenceCounted(false);
688
Matthew Williams8b76d202015-05-03 18:16:25 -0700689 mProvisioned = isDeviceProvisioned();
690 if (!mProvisioned) {
691 final ContentResolver resolver = context.getContentResolver();
692 ContentObserver provisionedObserver =
693 new ContentObserver(null /* current thread */) {
694 public void onChange(boolean selfChange) {
695 mProvisioned |= isDeviceProvisioned();
696 if (mProvisioned) {
Matthew Williams8b76d202015-05-03 18:16:25 -0700697 resolver.unregisterContentObserver(this);
698 }
699 }
700 };
701
702 synchronized (mSyncHandler) {
703 resolver.registerContentObserver(
704 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
705 false /* notifyForDescendents */,
706 provisionedObserver);
707
708 // The device *may* have been provisioned while we were registering above observer.
709 // Check again to make sure.
710 mProvisioned |= isDeviceProvisioned();
711 if (mProvisioned) {
712 resolver.unregisterContentObserver(provisionedObserver);
713 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700714 }
Matthew Williams8b76d202015-05-03 18:16:25 -0700715 }
Fred Quintanae91ebe22009-09-29 20:44:30 -0700716
717 if (!factoryTest) {
Amith Yamasanid648a602012-09-26 15:06:10 -0700718 // Register for account list updates for all users
719 mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
720 UserHandle.ALL,
721 new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
Matthew Williams5c6756f2014-10-02 04:12:28 +0000722 null, null);
Fred Quintanae91ebe22009-09-29 20:44:30 -0700723 }
Ashish Sharma69d95de2012-04-11 17:27:24 -0700724
Svet Ganov65712b02016-09-01 10:24:11 -0700725 // Sync adapters were able to access the synced account without the accounts
726 // permission which circumvents our permission model. Therefore, we require
727 // sync adapters that don't have access to the account to get user consent.
728 // This can be noisy, therefore we will white-list sync adapters installed
729 // before we started checking for account access because they already know
730 // the account (they run before) which is the genie is out of the bottle.
731 whiteListExistingSyncAdaptersIfNeeded();
Makoto Onukife224e02017-06-29 14:11:14 -0700732
Makoto Onukie7b02982017-08-24 14:23:36 -0700733 mLogger.log("Sync manager initialized: " + Build.FINGERPRINT);
Svet Ganov65712b02016-09-01 10:24:11 -0700734 }
735
Makoto Onuki3ab77812018-07-09 14:29:33 -0700736 public void onStartUser(int userId) {
737 // Log on the handler to avoid slowing down device boot.
738 mSyncHandler.post(() -> mLogger.log("onStartUser: user=", userId));
Makoto Onukife224e02017-06-29 14:11:14 -0700739 }
740
Makoto Onuki3ab77812018-07-09 14:29:33 -0700741 public void onUnlockUser(int userId) {
742 synchronized (mUnlockedUsers) {
743 mUnlockedUsers.put(userId, true);
744 }
745 // Log on the handler to avoid slowing down device boot.
746 mSyncHandler.post(() -> mLogger.log("onUnlockUser: user=", userId));
Makoto Onukife224e02017-06-29 14:11:14 -0700747 }
748
Makoto Onuki3ab77812018-07-09 14:29:33 -0700749 public void onStopUser(int userId) {
750 synchronized (mUnlockedUsers) {
751 mUnlockedUsers.put(userId, false);
752 }
753 // Log on the handler to avoid slowing down user switch.
754 mSyncHandler.post(() -> mLogger.log("onStopUser: user=", userId));
755 }
756
757 private boolean isUserUnlocked(int userId) {
758 synchronized (mUnlockedUsers) {
759 return mUnlockedUsers.get(userId);
760 }
Makoto Onukife224e02017-06-29 14:11:14 -0700761 }
762
Makoto Onukiaad2b512018-02-07 09:31:46 -0800763 public void onBootPhase(int phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800764 // Note SyncManager only receives PHASE_ACTIVITY_MANAGER_READY and after.
Makoto Onukiaad2b512018-02-07 09:31:46 -0800765 switch (phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800766 case SystemService.PHASE_ACTIVITY_MANAGER_READY:
Makoto Onukiaad2b512018-02-07 09:31:46 -0800767 mConstants.start();
768 break;
769 }
770 }
Makoto Onukife224e02017-06-29 14:11:14 -0700771
Svet Ganov65712b02016-09-01 10:24:11 -0700772 private void whiteListExistingSyncAdaptersIfNeeded() {
773 if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
774 return;
775 }
776 List<UserInfo> users = mUserManager.getUsers(true);
777 final int userCount = users.size();
778 for (int i = 0; i < userCount; i++) {
779 UserHandle userHandle = users.get(i).getUserHandle();
780 final int userId = userHandle.getIdentifier();
781 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
782 : mSyncAdapters.getAllServices(userId)) {
783 String packageName = service.componentName.getPackageName();
784 for (Account account : mAccountManager.getAccountsByTypeAsUser(
785 service.type.accountType, userHandle)) {
786 if (!canAccessAccount(account, packageName, userId)) {
787 mAccountManager.updateAppPermission(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700788 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
Svet Ganov65712b02016-09-01 10:24:11 -0700789 }
790 }
791 }
792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 }
794
Matthew Williams8b76d202015-05-03 18:16:25 -0700795 private boolean isDeviceProvisioned() {
796 final ContentResolver resolver = mContext.getContentResolver();
797 return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 /**
800 * Return a random value v that satisfies minValue <= v < maxValue. The difference between
801 * maxValue and minValue must be less than Integer.MAX_VALUE.
802 */
803 private long jitterize(long minValue, long maxValue) {
804 Random random = new Random(SystemClock.elapsedRealtime());
805 long spread = maxValue - minValue;
806 if (spread > Integer.MAX_VALUE) {
807 throw new IllegalArgumentException("the difference between the maxValue and the "
808 + "minValue must be less than " + Integer.MAX_VALUE);
809 }
810 return minValue + random.nextInt((int)spread);
811 }
812
Dianne Hackborn231cc602009-04-27 17:10:36 -0700813 public SyncStorageEngine getSyncStorageEngine() {
814 return mSyncStorageEngine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 }
Doug Zongker44f57472009-09-20 15:52:43 -0700816
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700817 private int getIsSyncable(Account account, int userId, String providerName) {
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700818 int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
819 UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
820
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000821 // If it's not a restricted user, return isSyncable.
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700822 if (userInfo == null || !userInfo.isRestricted()) return isSyncable;
823
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000824 // Else check if the sync adapter has opted-in or not.
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700825 RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
826 mSyncAdapters.getServiceInfo(
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000827 SyncAdapterType.newKey(providerName, account.type), userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700828 if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700829
830 PackageInfo pInfo = null;
831 try {
832 pInfo = AppGlobals.getPackageManager().getPackageInfo(
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000833 syncAdapterInfo.componentName.getPackageName(), 0, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700834 if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700835 } catch (RemoteException re) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000836 // Shouldn't happen.
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700837 return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700838 }
839 if (pInfo.restrictedAccountType != null
840 && pInfo.restrictedAccountType.equals(account.type)) {
841 return isSyncable;
842 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700843 return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700844 }
845 }
846
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000847 private void setAuthorityPendingState(EndPoint info) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000848 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000849 for (SyncOperation op: ops) {
850 if (!op.isPeriodic && op.target.matchesSpec(info)) {
851 getSyncStorageEngine().markPending(info, true);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700852 return;
853 }
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700854 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000855 getSyncStorageEngine().markPending(info, false);
Matthew Williamsfa774182013-06-18 15:44:11 -0700856 }
857
858 /**
859 * Initiate a sync. This can start a sync for all providers
860 * (pass null to url, set onlyTicklable to false), only those
861 * providers that are marked as ticklable (pass null to url,
862 * set onlyTicklable to true), or a specific provider (set url
863 * to the content url of the provider).
864 *
865 * <p>If the ContentResolver.SYNC_EXTRAS_UPLOAD boolean in extras is
866 * true then initiate a sync that just checks for local changes to send
867 * to the server, otherwise initiate a sync that first gets any
868 * changes from the server before sending local changes back to
869 * the server.
870 *
871 * <p>If a specific provider is being synced (the url is non-null)
872 * then the extras can contain SyncAdapter-specific information
873 * to control what gets synced (e.g. which specific feed to sync).
874 *
875 * <p>You'll start getting callbacks after this.
876 *
877 * @param requestedAccount the account to sync, may be null to signify all accounts
878 * @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
879 * then all users' accounts are considered.
880 * @param reason for sync request. If this is a positive integer, it is the Linux uid
881 * assigned to the process that requested the sync. If it's negative, the sync was requested by
882 * the SyncManager itself and could be one of the following:
883 * {@link SyncOperation#REASON_BACKGROUND_DATA_SETTINGS_CHANGED}
884 * {@link SyncOperation#REASON_ACCOUNTS_UPDATED}
885 * {@link SyncOperation#REASON_SERVICE_CHANGED}
886 * {@link SyncOperation#REASON_PERIODIC}
887 * {@link SyncOperation#REASON_IS_SYNCABLE}
888 * {@link SyncOperation#REASON_SYNC_AUTO}
889 * {@link SyncOperation#REASON_MASTER_SYNC_AUTO}
890 * {@link SyncOperation#REASON_USER_START}
891 * @param requestedAuthority the authority to sync, may be null to indicate all authorities
892 * @param extras a Map of SyncAdapter-specific information to control
893 * syncs of a specific provider. Can be null. Is ignored
894 * if the url is null.
Svet Ganovf6d424f12016-09-20 20:18:53 -0700895 * @param targetSyncState Only sync authorities that have the specified sync state.
896 * Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
Matthew Williamsfa774182013-06-18 15:44:11 -0700897 */
898 public void scheduleSync(Account requestedAccount, int userId, int reason,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800899 String requestedAuthority, Bundle extras, int targetSyncState,
Makoto Onukie183a402018-08-29 11:46:41 -0700900 @SyncExemption int syncExemptionFlag, int callingUid, int callingPid,
901 String callingPackage) {
Shreyas Basargeba1f7902016-10-01 00:19:44 +0100902 scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
Makoto Onukie183a402018-08-29 11:46:41 -0700903 0 /* min delay */, true /* checkIfAccountReady */, syncExemptionFlag,
904 callingUid, callingPid, callingPackage);
Shreyas Basargeba1f7902016-10-01 00:19:44 +0100905 }
906
907 /**
908 * @param minDelayMillis The sync can't land before this delay expires.
909 */
910 private void scheduleSync(Account requestedAccount, int userId, int reason,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800911 String requestedAuthority, Bundle extras, int targetSyncState,
912 final long minDelayMillis, boolean checkIfAccountReady,
Makoto Onukie183a402018-08-29 11:46:41 -0700913 @SyncExemption int syncExemptionFlag,
914 int callingUid, int callingPid, String callingPackage) {
Matthew Williamsfa774182013-06-18 15:44:11 -0700915 if (extras == null) {
916 extras = new Bundle();
917 }
Makoto Onukie183a402018-08-29 11:46:41 -0700918 extras.size(); // Force unpacel.
Makoto Onuki77d2af22019-02-20 14:45:42 -0800919 if (Log.isLoggable(TAG, Log.VERBOSE)) {
920 mLogger.log("scheduleSync: account=", requestedAccount,
921 " u", userId,
922 " authority=", requestedAuthority,
923 " reason=", reason,
924 " extras=", extras,
925 " cuid=", callingUid, " cpid=", callingPid, " cpkg=", callingPackage,
926 " mdm=", minDelayMillis,
927 " ciar=", checkIfAccountReady,
928 " sef=", syncExemptionFlag);
929 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700930
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700931 AccountAndUser[] accounts = null;
932 if (requestedAccount != null) {
933 if (userId != UserHandle.USER_ALL) {
934 accounts = new AccountAndUser[]{new AccountAndUser(requestedAccount, userId)};
935 } else {
936 for (AccountAndUser runningAccount : mRunningAccounts) {
937 if (requestedAccount.equals(runningAccount.account)) {
938 accounts = ArrayUtils.appendElement(AccountAndUser.class,
939 accounts, runningAccount);
940 }
941 }
942 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700943 } else {
Matthew Williamsfa774182013-06-18 15:44:11 -0700944 accounts = mRunningAccounts;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700945 }
946
947 if (ArrayUtils.isEmpty(accounts)) {
Makoto Onukie183a402018-08-29 11:46:41 -0700948 mLogger.log("scheduleSync: no accounts configured, dropping");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700949 return;
Matthew Williamsfa774182013-06-18 15:44:11 -0700950 }
951
952 final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
953 final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
954 if (manualSync) {
955 extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
956 extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
957 }
958 final boolean ignoreSettings =
959 extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
960
961 int source;
962 if (uploadOnly) {
963 source = SyncStorageEngine.SOURCE_LOCAL;
964 } else if (manualSync) {
965 source = SyncStorageEngine.SOURCE_USER;
966 } else if (requestedAuthority == null) {
967 source = SyncStorageEngine.SOURCE_POLL;
968 } else {
Makoto Onuki94986212018-04-11 16:24:46 -0700969 if (extras.containsKey("feed")) {
970 source = SyncStorageEngine.SOURCE_FEED;
971 } else{
972 // This isn't strictly server, since arbitrary callers can (and do) request
973 // a non-forced two-way sync on a specific url.
974 source = SyncStorageEngine.SOURCE_OTHER;
975 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700976 }
977
978 for (AccountAndUser account : accounts) {
Fyodor Kupolov6fde2982015-01-06 17:46:37 -0800979 // If userId is specified, do not sync accounts of other users
Xiaohui Chen98404fd2015-08-17 16:09:02 -0700980 if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
Fyodor Kupolov6fde2982015-01-06 17:46:37 -0800981 && userId != account.userId) {
982 continue;
983 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700984 // Compile a list of authorities that have sync adapters.
985 // For each authority sync each account that matches a sync adapter.
986 final HashSet<String> syncableAuthorities = new HashSet<String>();
987 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
988 mSyncAdapters.getAllServices(account.userId)) {
989 syncableAuthorities.add(syncAdapter.type.authority);
990 }
991
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000992 // If the url was specified then replace the list of authorities
Matthew Williamsfa774182013-06-18 15:44:11 -0700993 // with just this authority or clear it if this authority isn't
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000994 // syncable.
Matthew Williamsfa774182013-06-18 15:44:11 -0700995 if (requestedAuthority != null) {
996 final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
997 syncableAuthorities.clear();
998 if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
999 }
1000
1001 for (String authority : syncableAuthorities) {
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001002 int isSyncable = computeSyncable(account.account, account.userId, authority,
1003 !checkIfAccountReady);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001004
Matthew Williams53abfdb2015-06-10 20:06:37 -07001005 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001006 continue;
1007 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001008
1009 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
1010 mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority,
1011 account.account.type), account.userId);
Matthew Williamsfa774182013-06-18 15:44:11 -07001012 if (syncAdapterInfo == null) {
1013 continue;
1014 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001015
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001016 final int owningUid = syncAdapterInfo.uid;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001017
1018 if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
Makoto Onukie183a402018-08-29 11:46:41 -07001019 mLogger.log("scheduleSync: Not scheduling sync operation: "
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001020 + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001021 Bundle finalExtras = new Bundle(extras);
Svet Ganov973edd192016-09-08 20:15:55 -07001022 String packageName = syncAdapterInfo.componentName.getPackageName();
1023 // If the app did not run and has no account access, done
Makoto Onuki850045d2018-08-09 11:31:14 -07001024 if (!wasPackageEverLaunched(packageName, userId)) {
Svet Ganov973edd192016-09-08 20:15:55 -07001025 continue;
1026 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001027 mAccountManagerInternal.requestAccountAccess(account.account,
Svet Ganov973edd192016-09-08 20:15:55 -07001028 packageName, userId,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001029 new RemoteCallback((Bundle result) -> {
1030 if (result != null
1031 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
1032 scheduleSync(account.account, userId, reason, authority,
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001033 finalExtras, targetSyncState, minDelayMillis,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001034 true /* checkIfAccountReady */,
Makoto Onukie183a402018-08-29 11:46:41 -07001035 syncExemptionFlag, callingUid, callingPid,
1036 callingPackage);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001037 }
1038 }
1039 ));
1040 continue;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001041 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001042
Matthew Williamsfa774182013-06-18 15:44:11 -07001043 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
1044 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001045 if (!checkIfAccountReady && isSyncable < 0 && isAlwaysSyncable) {
Matthew Williams53abfdb2015-06-10 20:06:37 -07001046 mSyncStorageEngine.setIsSyncable(
Makoto Onukid4764302018-03-30 17:32:57 -07001047 account.account, account.userId, authority, AuthorityInfo.SYNCABLE,
Makoto Onukie183a402018-08-29 11:46:41 -07001048 callingUid, callingPid);
Matthew Williams53abfdb2015-06-10 20:06:37 -07001049 isSyncable = AuthorityInfo.SYNCABLE;
Matthew Williamsfa774182013-06-18 15:44:11 -07001050 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001051
Svet Ganovf6d424f12016-09-20 20:18:53 -07001052 if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001053 continue;
1054 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07001055
Matthew Williamsfa774182013-06-18 15:44:11 -07001056 if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
1057 continue;
1058 }
1059
Matthew Williamsfa774182013-06-18 15:44:11 -07001060 boolean syncAllowed =
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001061 (isSyncable < 0) // Always allow if the isSyncable state is unknown.
1062 || ignoreSettings
1063 || (mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
Matthew Williamsfa774182013-06-18 15:44:11 -07001064 && mSyncStorageEngine.getSyncAutomatically(account.account,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001065 account.userId, authority));
Matthew Williamsfa774182013-06-18 15:44:11 -07001066 if (!syncAllowed) {
Makoto Onukie183a402018-08-29 11:46:41 -07001067 mLogger.log("scheduleSync: sync of ", account, " ", authority,
1068 " is not allowed, dropping request");
Matthew Williamsfa774182013-06-18 15:44:11 -07001069 continue;
1070 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001071 SyncStorageEngine.EndPoint info =
1072 new SyncStorageEngine.EndPoint(
1073 account.account, authority, account.userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001074 long delayUntil =
1075 mSyncStorageEngine.getDelayUntilTime(info);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001076
1077 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
1078
Svet Ganovf6d424f12016-09-20 20:18:53 -07001079 if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001080 if (checkIfAccountReady) {
1081 Bundle finalExtras = new Bundle(extras);
1082
1083 sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId,
1084 () -> scheduleSync(account.account, account.userId, reason,
1085 authority, finalExtras, targetSyncState, minDelayMillis,
Makoto Onukie183a402018-08-29 11:46:41 -07001086 false, syncExemptionFlag, callingUid, callingPid,
1087 callingPackage));
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001088 } else {
1089 // Initialisation sync.
1090 Bundle newExtras = new Bundle();
1091 newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
Makoto Onukie183a402018-08-29 11:46:41 -07001092
1093 mLogger.log("scheduleSync: schedule initialisation sync ",
1094 account, " ", authority);
1095
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001096 postScheduleSyncMessage(
1097 new SyncOperation(account.account, account.userId,
1098 owningUid, owningPackage, reason, source,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001099 authority, newExtras, allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001100 syncExemptionFlag),
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001101 minDelayMillis
1102 );
Matthew Williamsfa774182013-06-18 15:44:11 -07001103 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07001104 } else if (targetSyncState == AuthorityInfo.UNDEFINED
1105 || targetSyncState == isSyncable) {
Makoto Onukie183a402018-08-29 11:46:41 -07001106 mLogger.log("scheduleSync: scheduling sync ",
1107 account, " ", authority);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001108 postScheduleSyncMessage(
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001109 new SyncOperation(account.account, account.userId,
1110 owningUid, owningPackage, reason, source,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001111 authority, extras, allowParallelSyncs, syncExemptionFlag),
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001112 minDelayMillis
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001113 );
Makoto Onukie183a402018-08-29 11:46:41 -07001114 } else {
1115 mLogger.log("scheduleSync: not handling ",
1116 account, " ", authority);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 }
1118 }
1119 }
1120 }
1121
Svet Ganov96b9c752016-10-17 19:29:58 -07001122 public int computeSyncable(Account account, int userId, String authority,
1123 boolean checkAccountAccess) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001124 final int status = getIsSyncable(account, userId, authority);
1125 if (status == AuthorityInfo.NOT_SYNCABLE) {
1126 return AuthorityInfo.NOT_SYNCABLE;
1127 }
1128 final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
1129 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
1130 mSyncAdapters.getServiceInfo(type, userId);
1131 if (syncAdapterInfo == null) {
1132 return AuthorityInfo.NOT_SYNCABLE;
1133 }
1134 final int owningUid = syncAdapterInfo.uid;
1135 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
1136 try {
Dianne Hackbornc3af19a2017-01-20 17:00:44 -08001137 if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001138 Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
1139 + syncAdapterInfo.componentName
1140 + " -- package not allowed to start");
1141 return AuthorityInfo.NOT_SYNCABLE;
1142 }
1143 } catch (RemoteException e) {
1144 /* ignore - local call */
1145 }
Svet Ganov96b9c752016-10-17 19:29:58 -07001146 if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
Makoto Onukidecc5ba2019-01-15 09:34:05 -08001147 Log.w(TAG, "Access to " + logSafe(account) + " denied for package "
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001148 + owningPackage + " in UID " + syncAdapterInfo.uid);
1149 return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
1150 }
1151
1152 return status;
1153 }
1154
1155 private boolean canAccessAccount(Account account, String packageName, int uid) {
1156 if (mAccountManager.hasAccountAccess(account, packageName,
1157 UserHandle.getUserHandleForUid(uid))) {
1158 return true;
1159 }
1160 // We relax the account access rule to also include the system apps as
1161 // they are trusted and we want to minimize the cases where the user
1162 // involvement is required to grant access to the synced account.
1163 try {
1164 mContext.getPackageManager().getApplicationInfoAsUser(packageName,
1165 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.getUserId(uid));
1166 return true;
1167 } catch (NameNotFoundException e) {
1168 return false;
1169 }
1170 }
1171
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001172 private void removeSyncsForAuthority(EndPoint info, String why) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001173 mLogger.log("removeSyncsForAuthority: ", info);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001174 verifyJobScheduler();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001175 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001176 for (SyncOperation op: ops) {
1177 if (op.target.matchesSpec(info)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001178 mLogger.log("canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001179 cancelJob(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001180 }
1181 }
1182 }
1183
1184 /**
1185 * Remove a specific periodic sync identified by its target and extras.
1186 */
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001187 public void removePeriodicSync(EndPoint target, Bundle extras, String why) {
1188 Message m = mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_REMOVE_PERIODIC_SYNC,
1189 Pair.create(target, why));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001190 m.setData(extras);
1191 m.sendToTarget();
1192 }
1193
1194 /**
1195 * Add a periodic sync. If a sync with same target and extras exists, its period and
1196 * flexMillis will be updated.
1197 */
1198 public void updateOrAddPeriodicSync(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001199 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001200 UpdatePeriodicSyncMessagePayload payload = new UpdatePeriodicSyncMessagePayload(target,
1201 pollFrequency, flex, extras);
1202 mSyncHandler.obtainMessage(SyncHandler.MESSAGE_UPDATE_PERIODIC_SYNC, payload)
1203 .sendToTarget();
1204 }
1205
1206 /**
1207 * Get a list of periodic syncs corresponding to the given target.
1208 */
1209 public List<PeriodicSync> getPeriodicSyncs(EndPoint target) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001210 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001211 List<PeriodicSync> periodicSyncs = new ArrayList<PeriodicSync>();
1212
1213 for (SyncOperation op: ops) {
1214 if (op.isPeriodic && op.target.matchesSpec(target)) {
1215 periodicSyncs.add(new PeriodicSync(op.target.account, op.target.provider,
1216 op.extras, op.periodMillis / 1000, op.flexMillis / 1000));
1217 }
1218 }
1219
1220 return periodicSyncs;
1221 }
1222
Matthew Williamsfa774182013-06-18 15:44:11 -07001223 /**
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001224 * Schedule sync based on local changes to a provider. We wait for at least LOCAL_SYNC_DELAY
1225 * ms to batch syncs.
Matthew Williamsfa774182013-06-18 15:44:11 -07001226 */
Makoto Onuki61283ec2018-01-31 17:22:36 -08001227 public void scheduleLocalSync(Account account, int userId, int reason, String authority,
Makoto Onukie183a402018-08-29 11:46:41 -07001228 @SyncExemption int syncExemptionFlag,
1229 int callingUid, int callingPid, String callingPackage) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 final Bundle extras = new Bundle();
1231 extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
Matthew Williamsfa774182013-06-18 15:44:11 -07001232 scheduleSync(account, userId, reason, authority, extras,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001233 AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */,
Makoto Onukie183a402018-08-29 11:46:41 -07001234 syncExemptionFlag, callingUid, callingPid, callingPackage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 }
1236
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001237 public SyncAdapterType[] getSyncAdapterTypes(int userId) {
1238 final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
1239 serviceInfos = mSyncAdapters.getAllServices(userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -07001240 SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
1241 int i = 0;
1242 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
1243 types[i] = serviceInfo.type;
1244 ++i;
1245 }
1246 return types;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 }
1248
Amith Yamasani37a40c22015-06-17 13:25:42 -07001249 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
1250 return mSyncAdapters.getSyncAdapterPackagesForAuthority(authority, userId);
1251 }
1252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001254 SyncResult syncResult) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001255 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 Message msg = mSyncHandler.obtainMessage();
1257 msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001258 msg.obj = new SyncFinishedOrCancelledMessagePayload(syncContext, syncResult);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 mSyncHandler.sendMessage(msg);
1260 }
1261
Makoto Onukia9dca242017-06-21 17:06:49 -07001262 private void sendCancelSyncsMessage(final SyncStorageEngine.EndPoint info, Bundle extras,
1263 String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001264 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_CANCEL");
Makoto Onukia9dca242017-06-21 17:06:49 -07001265
1266 mLogger.log("sendCancelSyncsMessage() ep=", info, " why=", why);
1267
Fred Quintana918339a2010-10-05 14:00:39 -07001268 Message msg = mSyncHandler.obtainMessage();
1269 msg.what = SyncHandler.MESSAGE_CANCEL;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001270 msg.setData(extras);
1271 msg.obj = info;
Fred Quintana918339a2010-10-05 14:00:39 -07001272 mSyncHandler.sendMessage(msg);
1273 }
1274
Matthew Williams92a1c092014-08-25 19:18:32 -07001275 /**
Matthew Williams1967c8d2015-06-19 19:03:13 -07001276 * Post a delayed message that will monitor the given sync context by periodically checking how
1277 * much network has been used by the uid.
Matthew Williams92a1c092014-08-25 19:18:32 -07001278 */
Matthew Williams1967c8d2015-06-19 19:03:13 -07001279 private void postMonitorSyncProgressMessage(ActiveSyncContext activeSyncContext) {
Matthew Williams92a1c092014-08-25 19:18:32 -07001280 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001281 Slog.v(TAG, "posting MESSAGE_SYNC_MONITOR in " +
Matthew Williams1967c8d2015-06-19 19:03:13 -07001282 (SYNC_MONITOR_WINDOW_LENGTH_MILLIS/1000) + "s");
Matthew Williams92a1c092014-08-25 19:18:32 -07001283 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07001284
1285 activeSyncContext.mBytesTransferredAtLastPoll =
1286 getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
1287 activeSyncContext.mLastPolledTimeElapsed = SystemClock.elapsedRealtime();
1288 Message monitorMessage =
1289 mSyncHandler.obtainMessage(
1290 SyncHandler.MESSAGE_MONITOR_SYNC,
1291 activeSyncContext);
1292 mSyncHandler.sendMessageDelayed(monitorMessage, SYNC_MONITOR_WINDOW_LENGTH_MILLIS);
Matthew Williams92a1c092014-08-25 19:18:32 -07001293 }
1294
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001295 private void postScheduleSyncMessage(SyncOperation syncOperation, long minDelayMillis) {
1296 ScheduleSyncMessagePayload payload =
1297 new ScheduleSyncMessagePayload(syncOperation, minDelayMillis);
1298 mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, payload).sendToTarget();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001299 }
1300
Matthew Williams1967c8d2015-06-19 19:03:13 -07001301 /**
1302 * Monitor sync progress by calculating how many bytes it is managing to send to and fro.
1303 */
1304 private long getTotalBytesTransferredByUid(int uid) {
1305 return (TrafficStats.getUidRxBytes(uid) + TrafficStats.getUidTxBytes(uid));
1306 }
1307
1308 /**
1309 * Convenience class for passing parameters for a finished or cancelled sync to the handler
1310 * to be processed.
1311 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001312 private class SyncFinishedOrCancelledMessagePayload {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 public final ActiveSyncContext activeSyncContext;
1314 public final SyncResult syncResult;
1315
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001316 SyncFinishedOrCancelledMessagePayload(ActiveSyncContext syncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001317 SyncResult syncResult) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 this.activeSyncContext = syncContext;
1319 this.syncResult = syncResult;
1320 }
1321 }
1322
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001323 private class UpdatePeriodicSyncMessagePayload {
1324 public final EndPoint target;
1325 public final long pollFrequency;
1326 public final long flex;
1327 public final Bundle extras;
1328
1329 UpdatePeriodicSyncMessagePayload(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001330 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001331 this.target = target;
1332 this.pollFrequency = pollFrequency;
1333 this.flex = flex;
1334 this.extras = extras;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 }
1336 }
1337
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001338 private static class ScheduleSyncMessagePayload {
1339 final SyncOperation syncOperation;
1340 final long minDelayMillis;
1341
1342 ScheduleSyncMessagePayload(SyncOperation syncOperation, long minDelayMillis) {
1343 this.syncOperation = syncOperation;
1344 this.minDelayMillis = minDelayMillis;
1345 }
1346 }
1347
Makoto Onukia9dca242017-06-21 17:06:49 -07001348 private void clearBackoffSetting(EndPoint target, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001349 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
1350 if (backoff != null && backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE &&
1351 backoff.second == SyncStorageEngine.NOT_IN_BACKOFF_MODE) {
1352 return;
1353 }
1354 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1355 Slog.v(TAG, "Clearing backoffs for " + target);
1356 }
1357 mSyncStorageEngine.setBackoff(target,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001358 SyncStorageEngine.NOT_IN_BACKOFF_MODE,
1359 SyncStorageEngine.NOT_IN_BACKOFF_MODE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001360
Makoto Onukia9dca242017-06-21 17:06:49 -07001361 rescheduleSyncs(target, why);
Alon Albert6e079a32010-11-12 12:41:09 -08001362 }
1363
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001364 private void increaseBackoffSetting(EndPoint target) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001365 final long now = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366
Fred Quintana307da1a2010-01-21 14:24:20 -08001367 final Pair<Long, Long> previousSettings =
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001368 mSyncStorageEngine.getBackoff(target);
Alon Albertaeeb6202010-12-09 16:14:02 -08001369 long newDelayInMs = -1;
1370 if (previousSettings != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001371 // Don't increase backoff before current backoff is expired. This will happen for op's
Alon Albertaeeb6202010-12-09 16:14:02 -08001372 // with ignoreBackoff set.
1373 if (now < previousSettings.first) {
1374 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001375 Slog.v(TAG, "Still in backoff, do not increase it. "
1376 + "Remaining: " + ((previousSettings.first - now) / 1000) + " seconds.");
Alon Albertaeeb6202010-12-09 16:14:02 -08001377 }
1378 return;
1379 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001380 // Subsequent delays are the double of the previous delay.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001381 newDelayInMs =
1382 (long) (previousSettings.second * mConstants.getRetryTimeIncreaseFactor());
Alon Albertaeeb6202010-12-09 16:14:02 -08001383 }
1384 if (newDelayInMs <= 0) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001385 // The initial delay is the jitterized INITIAL_SYNC_RETRY_TIME_IN_MS.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001386 final long initialRetryMs = mConstants.getInitialSyncRetryTimeInSeconds() * 1000;
1387 newDelayInMs = jitterize(initialRetryMs, (long)(initialRetryMs * 1.1));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 }
1389
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001390 // Cap the delay.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001391 final long maxSyncRetryTimeInSeconds = mConstants.getMaxSyncRetryTimeInSeconds();
1392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
1394 newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
1395 }
1396
Alon Albertc1ac7762010-10-28 13:35:55 -07001397 final long backoff = now + newDelayInMs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001398 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1399 Slog.v(TAG, "Backoff until: " + backoff + ", delayTime: " + newDelayInMs);
1400 }
1401 mSyncStorageEngine.setBackoff(target, backoff, newDelayInMs);
Makoto Onukia9dca242017-06-21 17:06:49 -07001402 rescheduleSyncs(target, "increaseBackoffSetting");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001403 }
Alon Albertc1ac7762010-10-28 13:35:55 -07001404
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001405 /**
1406 * Reschedule all scheduled syncs for this EndPoint. The syncs will be scheduled according
1407 * to current backoff and delayUntil values of this EndPoint.
1408 */
Makoto Onukia9dca242017-06-21 17:06:49 -07001409 private void rescheduleSyncs(EndPoint target, String why) {
1410 mLogger.log("rescheduleSyncs() ep=", target, " why=", why);
1411
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001412 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001413 int count = 0;
1414 for (SyncOperation op: ops) {
1415 if (!op.isPeriodic && op.target.matchesSpec(target)) {
1416 count++;
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001417 cancelJob(op, why);
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001418 postScheduleSyncMessage(op, 0 /* min delay */);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001419 }
1420 }
1421 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1422 Slog.v(TAG, "Rescheduled " + count + " syncs for " + target);
Fred Quintana918339a2010-10-05 14:00:39 -07001423 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001424 }
1425
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001426 private void setDelayUntilTime(EndPoint target, long delayUntilSeconds) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001427 final long delayUntil = delayUntilSeconds * 1000;
1428 final long absoluteNow = System.currentTimeMillis();
1429 long newDelayUntilTime;
1430 if (delayUntil > absoluteNow) {
1431 newDelayUntilTime = SystemClock.elapsedRealtime() + (delayUntil - absoluteNow);
1432 } else {
1433 newDelayUntilTime = 0;
1434 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001435 mSyncStorageEngine.setDelayUntilTime(target, newDelayUntilTime);
1436 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1437 Slog.v(TAG, "Delay Until time set to " + newDelayUntilTime + " for " + target);
Fred Quintana918339a2010-10-05 14:00:39 -07001438 }
Makoto Onukia9dca242017-06-21 17:06:49 -07001439 rescheduleSyncs(target, "delayUntil newDelayUntilTime: " + newDelayUntilTime);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001440 }
1441
1442 private boolean isAdapterDelayed(EndPoint target) {
1443 long now = SystemClock.elapsedRealtime();
1444 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
1445 if (backoff != null && backoff.first != SyncStorageEngine.NOT_IN_BACKOFF_MODE
1446 && backoff.first > now) {
1447 return true;
1448 }
1449 if (mSyncStorageEngine.getDelayUntilTime(target) > now) {
1450 return true;
1451 }
1452 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453 }
1454
1455 /**
Matthew Williams8ef22042013-07-26 12:56:39 -07001456 * Cancel the active sync if it matches the target.
1457 * @param info object containing info about which syncs to cancel. The target can
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001458 * have null account/provider info to specify all accounts/providers.
1459 * @param extras if non-null, specifies the exact sync to remove.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 */
Makoto Onukia9dca242017-06-21 17:06:49 -07001461 public void cancelActiveSync(SyncStorageEngine.EndPoint info, Bundle extras, String why) {
1462 sendCancelSyncsMessage(info, extras, why);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 }
1464
1465 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001466 * Schedule a sync operation with JobScheduler.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001468 private void scheduleSyncOperationH(SyncOperation syncOperation) {
1469 scheduleSyncOperationH(syncOperation, 0L);
1470 }
1471
1472 private void scheduleSyncOperationH(SyncOperation syncOperation, long minDelay) {
1473 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
1474 if (syncOperation == null) {
1475 Slog.e(TAG, "Can't schedule null sync operation.");
1476 return;
1477 }
1478 if (!syncOperation.ignoreBackoff()) {
1479 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target);
1480 if (backoff == null) {
Makoto Onukidecc5ba2019-01-15 09:34:05 -08001481 Slog.e(TAG, "Couldn't find backoff values for "
1482 + logSafe(syncOperation.target));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001483 backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
1484 SyncStorageEngine.NOT_IN_BACKOFF_MODE);
1485 }
1486 long now = SystemClock.elapsedRealtime();
1487 long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0
1488 : backoff.first - now;
1489 long delayUntil = mSyncStorageEngine.getDelayUntilTime(syncOperation.target);
1490 long delayUntilDelay = delayUntil > now ? delayUntil - now : 0;
1491 if (isLoggable) {
1492 Slog.v(TAG, "backoff delay:" + backoffDelay
1493 + " delayUntil delay:" + delayUntilDelay);
1494 }
1495 minDelay = Math.max(minDelay, Math.max(backoffDelay, delayUntilDelay));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 }
1497
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001498 if (minDelay < 0) {
1499 minDelay = 0;
1500 }
1501
1502 // Check if duplicate syncs are pending. If found, keep one with least expected run time.
Makoto Onuki61283ec2018-01-31 17:22:36 -08001503
1504 // If any of the duplicate ones has exemption, then we inherit it.
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001505 if (!syncOperation.isPeriodic) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001506 int inheritedSyncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001507
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001508 // Check currently running syncs
1509 for (ActiveSyncContext asc: mActiveSyncContexts) {
1510 if (asc.mSyncOperation.key.equals(syncOperation.key)) {
1511 if (isLoggable) {
1512 Log.v(TAG, "Duplicate sync is already running. Not scheduling "
1513 + syncOperation);
1514 }
1515 return;
1516 }
1517 }
1518
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001519 int duplicatesCount = 0;
1520 long now = SystemClock.elapsedRealtime();
1521 syncOperation.expectedRuntime = now + minDelay;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001522 List<SyncOperation> pending = getAllPendingSyncs();
Makoto Onuki61283ec2018-01-31 17:22:36 -08001523 SyncOperation syncToRun = syncOperation;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001524 for (SyncOperation op : pending) {
1525 if (op.isPeriodic) {
1526 continue;
1527 }
1528 if (op.key.equals(syncOperation.key)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001529 if (syncToRun.expectedRuntime > op.expectedRuntime) {
1530 syncToRun = op;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001531 }
1532 duplicatesCount++;
1533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001535 if (duplicatesCount > 1) {
1536 Slog.e(TAG, "FATAL ERROR! File a bug if you see this.");
1537 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001538
1539 if (syncOperation != syncToRun) {
1540 // If there's a duplicate with an earlier run time that's not exempted,
1541 // and if the current operation is exempted with no minDelay,
1542 // cancel the duplicate one and keep the current one.
1543 //
1544 // This means the duplicate one has a negative expected run time, but it hasn't
1545 // been executed possibly because of app-standby.
1546
Makoto Onuki75ad2492018-03-28 14:42:42 -07001547 if ((minDelay == 0)
1548 && (syncToRun.syncExemptionFlag < syncOperation.syncExemptionFlag)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001549 syncToRun = syncOperation;
Makoto Onuki75ad2492018-03-28 14:42:42 -07001550 inheritedSyncExemptionFlag =
1551 Math.max(inheritedSyncExemptionFlag, syncToRun.syncExemptionFlag);
Makoto Onuki61283ec2018-01-31 17:22:36 -08001552 }
1553 }
1554
1555 // Cancel all other duplicate syncs.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001556 for (SyncOperation op : pending) {
1557 if (op.isPeriodic) {
1558 continue;
1559 }
1560 if (op.key.equals(syncOperation.key)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001561 if (op != syncToRun) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001562 if (isLoggable) {
1563 Slog.v(TAG, "Cancelling duplicate sync " + op);
1564 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07001565 inheritedSyncExemptionFlag =
1566 Math.max(inheritedSyncExemptionFlag, op.syncExemptionFlag);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001567 cancelJob(op, "scheduleSyncOperationH-duplicate");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001568 }
1569 }
1570 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001571 if (syncToRun != syncOperation) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001572 // Don't schedule because a duplicate sync with earlier expected runtime exists.
1573 if (isLoggable) {
1574 Slog.v(TAG, "Not scheduling because a duplicate exists.");
1575 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001576
1577 // TODO Should we give the winning one SYNC_EXTRAS_APP_STANDBY_EXEMPTED
1578 // if the current one has it?
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001579 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001581
1582 // If any of the duplicates had exemption, we exempt the current one.
Makoto Onuki75ad2492018-03-28 14:42:42 -07001583 //
1584 if (inheritedSyncExemptionFlag > ContentResolver.SYNC_EXEMPTION_NONE) {
1585 syncOperation.syncExemptionFlag = inheritedSyncExemptionFlag;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001588
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001589 // Syncs that are re-scheduled shouldn't get a new job id.
1590 if (syncOperation.jobId == SyncOperation.NO_JOB_ID) {
1591 syncOperation.jobId = getUnusedJobIdH();
1592 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001593
1594 if (isLoggable) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001595 Slog.v(TAG, "scheduling sync operation " + syncOperation.toString());
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001596 }
1597
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001598 int priority = syncOperation.findPriority();
1599
1600 final int networkType = syncOperation.isNotAllowedOnMetered() ?
1601 JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
1602
Makoto Onuki61283ec2018-01-31 17:22:36 -08001603 // Note this logic means when an exempted sync fails,
1604 // the back-off one will inherit it too, and will be exempted from app-standby.
Makoto Onuki75ad2492018-03-28 14:42:42 -07001605 final int jobFlags = syncOperation.isAppStandbyExempted()
Makoto Onuki61283ec2018-01-31 17:22:36 -08001606 ? JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY : 0;
1607
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001608 JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001609 new ComponentName(mContext, SyncJobService.class))
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001610 .setExtras(syncOperation.toJobInfoExtras())
1611 .setRequiredNetworkType(networkType)
1612 .setPersisted(true)
Makoto Onuki61283ec2018-01-31 17:22:36 -08001613 .setPriority(priority)
1614 .setFlags(jobFlags);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001615
1616 if (syncOperation.isPeriodic) {
1617 b.setPeriodic(syncOperation.periodMillis, syncOperation.flexMillis);
1618 } else {
1619 if (minDelay > 0) {
1620 b.setMinimumLatency(minDelay);
1621 }
1622 getSyncStorageEngine().markPending(syncOperation.target, true);
1623 }
1624
1625 if (syncOperation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)) {
1626 b.setRequiresCharging(true);
1627 }
1628
Makoto Onuki75ad2492018-03-28 14:42:42 -07001629 if (syncOperation.syncExemptionFlag
Makoto Onukid5f25d22018-05-22 16:02:17 -07001630 == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001631 DeviceIdleController.LocalService dic =
1632 LocalServices.getService(DeviceIdleController.LocalService.class);
1633 if (dic != null) {
1634 dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID,
1635 syncOperation.owningPackage,
1636 mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
1637 UserHandle.getUserId(syncOperation.owningUid),
1638 /* sync=*/ false, "sync by top app");
1639 }
1640 }
1641
Michael Wachenschwanzc3295202019-02-20 17:19:52 -08001642 final UsageStatsManagerInternal usmi =
1643 LocalServices.getService(UsageStatsManagerInternal.class);
1644 if (usmi != null) {
1645 usmi.reportSyncScheduled(syncOperation.owningPackage,
1646 UserHandle.getUserId(syncOperation.owningUid),
1647 syncOperation.isAppStandbyExempted());
Makoto Onukid5f25d22018-05-22 16:02:17 -07001648 }
1649
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001650 getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
Shreyas Basargeeda34e42016-04-26 00:14:02 +01001651 syncOperation.target.userId, syncOperation.wakeLockName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 }
1653
1654 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07001655 * Remove scheduled sync operations.
Matthew Williams8ef22042013-07-26 12:56:39 -07001656 * @param info limit the removals to operations that match this target. The target can
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001657 * have null account/provider info to specify all accounts/providers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 */
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001659 public void clearScheduledSyncOperations(SyncStorageEngine.EndPoint info) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001660 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001661 for (SyncOperation op: ops) {
1662 if (!op.isPeriodic && op.target.matchesSpec(info)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001663 cancelJob(op, "clearScheduledSyncOperations");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001664 getSyncStorageEngine().markPending(op.target, false);
1665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001667 mSyncStorageEngine.setBackoff(info,
Fred Quintana918339a2010-10-05 14:00:39 -07001668 SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 }
1670
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001671 /**
1672 * Remove a specified sync, if it exists.
1673 * @param info Authority for which the sync is to be removed.
1674 * @param extras extras bundle to uniquely identify sync.
1675 */
1676 public void cancelScheduledSyncOperation(SyncStorageEngine.EndPoint info, Bundle extras) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001677 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001678 for (SyncOperation op: ops) {
1679 if (!op.isPeriodic && op.target.matchesSpec(info)
1680 && syncExtrasEquals(extras, op.extras, false)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001681 cancelJob(op, "cancelScheduledSyncOperation");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001682 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001683 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001684 setAuthorityPendingState(info);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001685 // Reset the back-off if there are no more syncs pending.
1686 if (!mSyncStorageEngine.isSyncPending(info)) {
1687 mSyncStorageEngine.setBackoff(info,
1688 SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
1689 }
1690 }
1691
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001692 private void maybeRescheduleSync(SyncResult syncResult, SyncOperation operation) {
1693 final boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 if (isLoggable) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001695 Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 }
1697
Fred Quintana53bd2522010-02-05 15:28:12 -08001698 // The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
1699 // request. Retries of the request will always honor the backoff, so clear the
1700 // flag in case we retry this request.
1701 if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
1702 operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
1703 }
1704
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01001705 if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
1706 && !syncResult.syncAlreadyInProgress) {
1707 // syncAlreadyInProgress flag is set by AbstractThreadedSyncAdapter. The sync adapter
1708 // has no way of knowing that a sync error occured. So we DO retry if the error is
1709 // syncAlreadyInProgress.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001710 if (isLoggable) {
1711 Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
1712 + operation);
1713 }
Fred Quintana918339a2010-10-05 14:00:39 -07001714 } else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)
1715 && !syncResult.syncAlreadyInProgress) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001716 // If this was an upward sync then schedule a two-way sync immediately.
Fred Quintana53bd2522010-02-05 15:28:12 -08001717 operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001718 if (isLoggable) {
1719 Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
1720 + "encountered an error: " + operation);
1721 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001722 scheduleSyncOperationH(operation);
Fred Quintana307da1a2010-01-21 14:24:20 -08001723 } else if (syncResult.tooManyRetries) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001724 // If this sync aborted because the internal sync loop retried too many times then
1725 // don't reschedule. Otherwise we risk getting into a retry loop.
1726 if (isLoggable) {
1727 Log.d(TAG, "not retrying sync operation because it retried too many times: "
1728 + operation);
1729 }
Fred Quintanaaa7edda2009-12-03 14:18:58 -08001730 } else if (syncResult.madeSomeProgress()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001731 // If the operation succeeded to some extent then retry immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 if (isLoggable) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001733 Log.d(TAG, "retrying sync operation because even though it had an error "
1734 + "it achieved some success");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001736 scheduleSyncOperationH(operation);
Fred Quintana8570f742010-02-18 10:32:54 -08001737 } else if (syncResult.syncAlreadyInProgress) {
1738 if (isLoggable) {
1739 Log.d(TAG, "retrying sync operation that failed because there was already a "
1740 + "sync in progress: " + operation);
1741 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001742 scheduleSyncOperationH(operation, DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 } else if (syncResult.hasSoftError()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001744 // If this was a two-way sync then retry soft errors with an exponential backoff.
Fred Quintana307da1a2010-01-21 14:24:20 -08001745 if (isLoggable) {
1746 Log.d(TAG, "retrying sync operation because it encountered a soft error: "
1747 + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001749 scheduleSyncOperationH(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 } else {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001751 // Otherwise do not reschedule.
Makoto Onukidecc5ba2019-01-15 09:34:05 -08001752 Log.e(TAG, "not retrying sync operation because the error is a hard error: "
1753 + logSafe(operation));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 }
1755 }
1756
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07001757 private void onUserUnlocked(int userId) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001758 // Make sure that accounts we're about to use are valid.
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001759 AccountManagerService.getSingleton().validateAccounts(userId);
1760
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001761 mSyncAdapters.invalidateCache(userId);
1762
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001763 EndPoint target = new EndPoint(null, null, userId);
1764 updateRunningAccounts(target);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001765
Makoto Onuki61283ec2018-01-31 17:22:36 -08001766 // Schedule sync for any accounts under started user, but only the NOT_INITIALIZED adapters.
Svetoslavf3f02ac2015-09-08 14:36:35 -07001767 final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId,
1768 mContext.getOpPackageName());
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001769 for (Account account : accounts) {
Alon Albert57286f92012-10-09 14:21:38 -07001770 scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
Makoto Onukie183a402018-08-29 11:46:41 -07001771 AuthorityInfo.NOT_INITIALIZED, ContentResolver.SYNC_EXEMPTION_NONE,
1772 Process.myUid(), -3, null);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001773 }
Alon Albert8e285552012-09-17 15:05:27 -07001774 }
Amith Yamasani13593602012-03-22 16:16:17 -07001775
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -07001776 private void onUserStopped(int userId) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001777 updateRunningAccounts(null /* Don't sync any target */);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001778
1779 cancelActiveSync(
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001780 new SyncStorageEngine.EndPoint(
1781 null /* any account */,
1782 null /* any authority */,
1783 userId),
Makoto Onukia9dca242017-06-21 17:06:49 -07001784 null /* any sync. */,
1785 "onUserStopped"
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001786 );
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001787 }
1788
1789 private void onUserRemoved(int userId) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001790 mLogger.log("onUserRemoved: u", userId);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001791 updateRunningAccounts(null /* Don't sync any target */);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001792
Amith Yamasani13593602012-03-22 16:16:17 -07001793 // Clean up the storage engine database
Makoto Onuki3ab77812018-07-09 14:29:33 -07001794 mSyncStorageEngine.removeStaleAccounts(null, userId);
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001795 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001796 for (SyncOperation op: ops) {
1797 if (op.target.userId == userId) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001798 cancelJob(op, "user removed u" + userId);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001799 }
1800 }
1801 }
1802
Amith Yamasani96a0fd652015-04-10 16:16:30 -07001803 /**
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001804 * Construct intent used to bind to an adapter.
1805 *
1806 * @param context Context to create intent for
1807 * @param syncAdapterComponent The adapter description
1808 * @param userId The user the adapter belongs to
1809 *
1810 * @return The intent required to bind to the adapter
1811 */
1812 static @NonNull Intent getAdapterBindIntent(@NonNull Context context,
1813 @NonNull ComponentName syncAdapterComponent, @UserIdInt int userId) {
1814 final Intent intent = new Intent();
1815 intent.setAction("android.content.SyncAdapter");
1816 intent.setComponent(syncAdapterComponent);
1817 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1818 com.android.internal.R.string.sync_binding_label);
1819 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0,
1820 new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId)));
1821
1822 return intent;
1823 }
1824
1825 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 * @hide
1827 */
Alon Alberteca75112010-12-08 15:02:33 -08001828 class ActiveSyncContext extends ISyncContext.Stub
1829 implements ServiceConnection, IBinder.DeathRecipient {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 final SyncOperation mSyncOperation;
1831 final long mHistoryRowId;
Fred Quintana718d8a22009-04-29 17:53:20 -07001832 ISyncAdapter mSyncAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 final long mStartTime;
1834 long mTimeoutStartTime;
Fred Quintana3ec47302010-03-10 10:08:31 -08001835 boolean mBound;
Fred Quintana918339a2010-10-05 14:00:39 -07001836 final PowerManager.WakeLock mSyncWakeLock;
1837 final int mSyncAdapterUid;
1838 SyncInfo mSyncInfo;
Alon Alberteca75112010-12-08 15:02:33 -08001839 boolean mIsLinkedToDeath = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001840 String mEventName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841
Matthew Williams1967c8d2015-06-19 19:03:13 -07001842 /** Total bytes transferred, counted at {@link #mLastPolledTimeElapsed} */
1843 long mBytesTransferredAtLastPoll;
1844 /**
1845 * Last point in {@link SystemClock#elapsedRealtime()} at which we checked the # of bytes
1846 * transferred to/fro by this adapter.
1847 */
1848 long mLastPolledTimeElapsed;
1849
Fred Quintana918339a2010-10-05 14:00:39 -07001850 /**
1851 * Create an ActiveSyncContext for an impending sync and grab the wakelock for that
1852 * sync adapter. Since this grabs the wakelock you need to be sure to call
1853 * close() when you are done with this ActiveSyncContext, whether the sync succeeded
1854 * or not.
1855 * @param syncOperation the SyncOperation we are about to sync
1856 * @param historyRowId the row in which to record the history info for this sync
1857 * @param syncAdapterUid the UID of the application that contains the sync adapter
1858 * for this sync. This is used to attribute the wakelock hold to that application.
1859 */
1860 public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001861 int syncAdapterUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 super();
Fred Quintana918339a2010-10-05 14:00:39 -07001863 mSyncAdapterUid = syncAdapterUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 mSyncOperation = syncOperation;
1865 mHistoryRowId = historyRowId;
Fred Quintana718d8a22009-04-29 17:53:20 -07001866 mSyncAdapter = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 mStartTime = SystemClock.elapsedRealtime();
1868 mTimeoutStartTime = mStartTime;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001869 mSyncWakeLock = mSyncHandler.getSyncWakeLock(mSyncOperation);
Fred Quintana918339a2010-10-05 14:00:39 -07001870 mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
1871 mSyncWakeLock.acquire();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 }
1873
1874 public void sendHeartbeat() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001875 // Heartbeats are no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
1877
1878 public void onFinished(SyncResult result) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001879 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "onFinished: " + this);
1880 // Include "this" in the message so that the handler can ignore it if this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 // ActiveSyncContext is no longer the mActiveSyncContext at message handling
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001882 // time.
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001883 mLogger.log("onFinished result=", result, " endpoint=",
1884 (mSyncOperation == null ? "null" : mSyncOperation.target));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 sendSyncFinishedOrCanceledMessage(this, result);
1886 }
1887
Makoto Onukidecc5ba2019-01-15 09:34:05 -08001888 public void toString(StringBuilder sb, boolean logSafe) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 sb.append("startTime ").append(mStartTime)
1890 .append(", mTimeoutStartTime ").append(mTimeoutStartTime)
1891 .append(", mHistoryRowId ").append(mHistoryRowId)
Makoto Onukidecc5ba2019-01-15 09:34:05 -08001892 .append(", syncOperation ").append(
1893 logSafe ? logSafe(mSyncOperation) : mSyncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 }
1895
Fred Quintana718d8a22009-04-29 17:53:20 -07001896 public void onServiceConnected(ComponentName name, IBinder service) {
1897 Message msg = mSyncHandler.obtainMessage();
1898 msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001899 msg.obj = new ServiceConnectionData(this, service);
Fred Quintana718d8a22009-04-29 17:53:20 -07001900 mSyncHandler.sendMessage(msg);
1901 }
1902
1903 public void onServiceDisconnected(ComponentName name) {
1904 Message msg = mSyncHandler.obtainMessage();
1905 msg.what = SyncHandler.MESSAGE_SERVICE_DISCONNECTED;
1906 msg.obj = new ServiceConnectionData(this, null);
1907 mSyncHandler.sendMessage(msg);
1908 }
1909
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001910 boolean bindToSyncAdapter(ComponentName serviceComponent, int userId) {
Fred Quintana718d8a22009-04-29 17:53:20 -07001911 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001912 Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
Fred Quintana718d8a22009-04-29 17:53:20 -07001913 }
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001914 Intent intent = getAdapterBindIntent(mContext, serviceComponent, userId);
1915
Fred Quintana3ec47302010-03-10 10:08:31 -08001916 mBound = true;
Amith Yamasani27b89e62013-01-16 12:30:11 -08001917 final boolean bindResult = mContext.bindServiceAsUser(intent, this,
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001918 SYNC_ADAPTER_CONNECTION_FLAGS, new UserHandle(mSyncOperation.target.userId));
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001919 mLogger.log("bindService() returned=", mBound, " for ", this);
Fred Quintana3ec47302010-03-10 10:08:31 -08001920 if (!bindResult) {
1921 mBound = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001922 } else {
1923 try {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08001924 mEventName = mSyncOperation.wakeLockName();
Dianne Hackbornfdb19562014-07-11 16:03:36 -07001925 mBatteryStats.noteSyncStart(mEventName, mSyncAdapterUid);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001926 } catch (RemoteException e) {
1927 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001928 }
1929 return bindResult;
Fred Quintana718d8a22009-04-29 17:53:20 -07001930 }
1931
Fred Quintana918339a2010-10-05 14:00:39 -07001932 /**
1933 * Performs the required cleanup, which is the releasing of the wakelock and
1934 * unbinding from the sync adapter (if actually bound).
1935 */
Fred Quintana3ec47302010-03-10 10:08:31 -08001936 protected void close() {
Fred Quintana718d8a22009-04-29 17:53:20 -07001937 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1938 Log.d(TAG, "unBindFromSyncAdapter: connection " + this);
1939 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001940 if (mBound) {
1941 mBound = false;
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001942 mLogger.log("unbindService for ", this);
Fred Quintana3ec47302010-03-10 10:08:31 -08001943 mContext.unbindService(this);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001944 try {
Dianne Hackbornfdb19562014-07-11 16:03:36 -07001945 mBatteryStats.noteSyncFinish(mEventName, mSyncAdapterUid);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001946 } catch (RemoteException e) {
1947 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001948 }
Fred Quintana918339a2010-10-05 14:00:39 -07001949 mSyncWakeLock.release();
Dianne Hackbornc24ab862011-10-18 15:55:03 -07001950 mSyncWakeLock.setWorkSource(null);
Fred Quintana718d8a22009-04-29 17:53:20 -07001951 }
1952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 public String toString() {
1954 StringBuilder sb = new StringBuilder();
Makoto Onukidecc5ba2019-01-15 09:34:05 -08001955 toString(sb, false);
1956 return sb.toString();
1957 }
1958
1959 public String toSafeString() {
1960 StringBuilder sb = new StringBuilder();
1961 toString(sb, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 return sb.toString();
1963 }
Alon Alberteca75112010-12-08 15:02:33 -08001964
1965 @Override
1966 public void binderDied() {
1967 sendSyncFinishedOrCanceledMessage(this, null);
1968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 }
1970
Makoto Onukia9dca242017-06-21 17:06:49 -07001971 protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001972 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
Makoto Onuki75ad2492018-03-28 14:42:42 -07001973
1974 final SyncAdapterStateFetcher buckets = new SyncAdapterStateFetcher();
1975
1976 dumpSyncState(ipw, buckets);
Makoto Onukiaad2b512018-02-07 09:31:46 -08001977 mConstants.dump(pw, "");
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001978 dumpSyncAdapters(ipw);
Makoto Onukia9dca242017-06-21 17:06:49 -07001979
1980 if (dumpAll) {
1981 ipw.println("Detailed Sync History");
1982 mLogger.dumpAll(pw);
1983 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 }
1985
Dianne Hackborn231cc602009-04-27 17:10:36 -07001986 static String formatTime(long time) {
Makoto Onukif74cf942018-04-16 17:04:58 -07001987 if (time == 0) {
1988 return "N/A";
1989 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001990 Time tobj = new Time();
1991 tobj.set(time);
1992 return tobj.format("%Y-%m-%d %H:%M:%S");
1993 }
Doug Zongker44f57472009-09-20 15:52:43 -07001994
Makoto Onuki15e7a252017-06-08 17:12:05 -07001995 private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
1996 int res = Integer.compare(op1.target.userId, op2.target.userId);
1997 if (res != 0) return res;
1998
1999 final Comparator<String> stringComparator = String.CASE_INSENSITIVE_ORDER;
2000
2001 res = stringComparator.compare(op1.target.account.type, op2.target.account.type);
2002 if (res != 0) return res;
2003
2004 res = stringComparator.compare(op1.target.account.name, op2.target.account.name);
2005 if (res != 0) return res;
2006
2007 res = stringComparator.compare(op1.target.provider, op2.target.provider);
2008 if (res != 0) return res;
2009
2010 res = Integer.compare(op1.reason, op2.reason);
2011 if (res != 0) return res;
2012
2013 res = Long.compare(op1.periodMillis, op2.periodMillis);
2014 if (res != 0) return res;
2015
2016 res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
2017 if (res != 0) return res;
2018
2019 res = Long.compare(op1.jobId, op2.jobId);
2020 if (res != 0) return res;
2021
2022 return 0;
2023 };
2024
2025 private final static Comparator<SyncOperation> sOpRuntimeComparator = (op1, op2) -> {
2026 int res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
2027 if (res != 0) return res;
2028
2029 return sOpDumpComparator.compare(op1, op2);
2030 };
2031
2032 private static <T> int countIf(Collection<T> col, Predicate<T> p) {
2033 int ret = 0;
2034 for (T item : col) {
2035 if (p.test(item)) ret++;
2036 }
2037 return ret;
2038 }
2039
Makoto Onuki75ad2492018-03-28 14:42:42 -07002040 protected void dumpPendingSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00002041 List<SyncOperation> pendingSyncs = getAllPendingSyncs();
Makoto Onuki15e7a252017-06-08 17:12:05 -07002042
2043 pw.print("Pending Syncs: ");
2044 pw.println(countIf(pendingSyncs, op -> !op.isPeriodic));
2045
2046 Collections.sort(pendingSyncs, sOpRuntimeComparator);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002047 int count = 0;
2048 for (SyncOperation op: pendingSyncs) {
2049 if (!op.isPeriodic) {
Makoto Onukidecc5ba2019-01-15 09:34:05 -08002050 pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002051 count++;
2052 }
2053 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002054 pw.println();
2055 }
2056
Makoto Onuki75ad2492018-03-28 14:42:42 -07002057 protected void dumpPeriodicSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00002058 List<SyncOperation> pendingSyncs = getAllPendingSyncs();
Makoto Onuki15e7a252017-06-08 17:12:05 -07002059
2060 pw.print("Periodic Syncs: ");
2061 pw.println(countIf(pendingSyncs, op -> op.isPeriodic));
2062
2063 Collections.sort(pendingSyncs, sOpDumpComparator);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002064 int count = 0;
2065 for (SyncOperation op: pendingSyncs) {
2066 if (op.isPeriodic) {
Makoto Onukidecc5ba2019-01-15 09:34:05 -08002067 pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002068 count++;
2069 }
2070 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002071 pw.println();
2072 }
2073
Makoto Onuki15e7a252017-06-08 17:12:05 -07002074 /**
2075 * Similar to {@link android.util.TimeUtils#formatDuration}, but it's more suitable and concise
2076 * for the sync manager dumpsys. (Don't add the leading + sign, don't show milliseconds.)
2077 */
2078 public static StringBuilder formatDurationHMS(StringBuilder sb, long duration) {
2079 duration /= 1000;
2080 if (duration < 0) {
2081 sb.append('-');
2082 duration = -duration;
2083 }
2084 final long seconds = duration % 60;
2085 duration /= 60;
2086
2087 final long minutes = duration % 60;
2088 duration /= 60;
2089
2090 final long hours = duration % 24;
2091 duration /= 24;
2092
2093 final long days = duration;
2094
2095 boolean print = false;
2096 if (days > 0) {
2097 sb.append(days);
2098 sb.append('d');
2099 print = true;
2100 }
2101 print = printTwoDigitNumber(sb, hours, 'h', print);
2102 print = printTwoDigitNumber(sb, minutes, 'm', print);
2103 print = printTwoDigitNumber(sb, seconds, 's', print);
2104 if (!print) {
2105 sb.append("0s");
2106 }
2107
2108 return sb;
2109 }
2110
2111 private static boolean printTwoDigitNumber(StringBuilder sb, long value, char unit,
2112 boolean always) {
2113 if (!always && (value == 0)) {
2114 return false;
2115 }
2116 if (always && (value < 10)) {
2117 sb.append('0');
2118 }
2119 sb.append(value);
2120 sb.append(unit);
2121 return true;
2122 }
2123
Makoto Onuki75ad2492018-03-28 14:42:42 -07002124 protected void dumpSyncState(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07002125 final StringBuilder sb = new StringBuilder();
2126
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002127 pw.print("Data connected: "); pw.println(mDataConnectionIsConnected);
2128 pw.print("Battery saver: ");
2129 pw.println((mPowerManager != null) && mPowerManager.isPowerSaveMode());
2130
2131 pw.print("Background network restriction: ");
2132 {
2133 final ConnectivityManager cm = getConnectivityManager();
2134 final int status = (cm == null) ? -1 : cm.getRestrictBackgroundStatus();
2135 switch (status) {
2136 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
2137 pw.println(" disabled");
2138 break;
2139 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
2140 pw.println(" whitelisted");
2141 break;
2142 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
2143 pw.println(" enabled");
2144 break;
2145 default:
2146 pw.print("Unknown(");
2147 pw.print(status);
2148 pw.println(")");
2149 break;
2150 }
2151 }
2152
2153 pw.print("Auto sync: ");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002154 List<UserInfo> users = getAllUsers();
2155 if (users != null) {
2156 for (UserInfo user : users) {
2157 pw.print("u" + user.id + "="
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002158 + mSyncStorageEngine.getMasterSyncAutomatically(user.id) + " ");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002159 }
2160 pw.println();
2161 }
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002162 pw.print("Memory low: "); pw.println(mStorageIsLow);
2163 pw.print("Device idle: "); pw.println(mDeviceIsIdle);
2164 pw.print("Reported active: "); pw.println(mReportedSyncActive);
Makoto Onuki94986212018-04-11 16:24:46 -07002165 pw.print("Clock valid: "); pw.println(mSyncStorageEngine.isClockValid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166
Jeff Sharkey6eb96202012-10-10 13:13:54 -07002167 final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002168
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002169 pw.print("Accounts: ");
Fred Quintana53bd2522010-02-05 15:28:12 -08002170 if (accounts != INITIAL_ACCOUNTS_ARRAY) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07002171 pw.println(accounts.length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 } else {
Fred Quintana53bd2522010-02-05 15:28:12 -08002173 pw.println("not known yet");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 final long now = SystemClock.elapsedRealtime();
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002176 pw.print("Now: "); pw.print(now);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002177 pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002178
2179 sb.setLength(0);
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002180 pw.print("Uptime: "); pw.print(formatDurationHMS(sb, now));
Makoto Onuki15e7a252017-06-08 17:12:05 -07002181 pw.println();
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002182 pw.print("Time spent syncing: ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002183
2184 sb.setLength(0);
2185 pw.print(formatDurationHMS(sb,
2186 mSyncHandler.mSyncTimeTracker.timeSpentSyncing()));
2187 pw.print(", sync ");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002188 pw.print(mSyncHandler.mSyncTimeTracker.mLastWasSyncing ? "" : "not ");
2189 pw.println("in progress");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190
Fred Quintana918339a2010-10-05 14:00:39 -07002191 pw.println();
2192 pw.println("Active Syncs: " + mActiveSyncContexts.size());
Alon Albert57286f92012-10-09 14:21:38 -07002193 final PackageManager pm = mContext.getPackageManager();
Fred Quintana918339a2010-10-05 14:00:39 -07002194 for (SyncManager.ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07002195 final long durationInSeconds = (now - activeSyncContext.mStartTime);
Fred Quintana918339a2010-10-05 14:00:39 -07002196 pw.print(" ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002197 sb.setLength(0);
2198 pw.print(formatDurationHMS(sb, durationInSeconds));
Fred Quintana918339a2010-10-05 14:00:39 -07002199 pw.print(" - ");
Makoto Onukidecc5ba2019-01-15 09:34:05 -08002200 pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets, /*logSafe=*/ false));
Fred Quintana918339a2010-10-05 14:00:39 -07002201 pw.println();
2202 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002203 pw.println();
2204
Makoto Onuki75ad2492018-03-28 14:42:42 -07002205 dumpPendingSyncs(pw, buckets);
2206 dumpPeriodicSyncs(pw, buckets);
Fred Quintana918339a2010-10-05 14:00:39 -07002207
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002208 // Join the installed sync adapter with the accounts list and emit for everything.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002209 pw.println("Sync Status");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002210
2211 final ArrayList<Pair<EndPoint, SyncStatusInfo>> statuses = new ArrayList<>();
2212
Makoto Onuki94986212018-04-11 16:24:46 -07002213 mSyncStorageEngine.resetTodayStats(/* force=*/ false);
2214
Amith Yamasani04e0d262012-02-14 11:50:53 -08002215 for (AccountAndUser account : accounts) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002216 final boolean unlocked;
2217 synchronized (mUnlockedUsers) {
2218 unlocked = mUnlockedUsers.get(account.userId);
2219 }
2220 pw.printf("Account %s u%d %s%s\n",
2221 account.account.name, account.userId, account.account.type,
2222 (unlocked ? "" : " (locked)"));
Alon Albert57286f92012-10-09 14:21:38 -07002223
2224 pw.println("=======================================================================");
Makoto Onuki94986212018-04-11 16:24:46 -07002225 final PrintTable table = new PrintTable(16);
Alon Albert57286f92012-10-09 14:21:38 -07002226 table.set(0, 0,
2227 "Authority", // 0
2228 "Syncable", // 1
2229 "Enabled", // 2
Makoto Onuki94986212018-04-11 16:24:46 -07002230
2231 "Stats", // 3 "Total", "Today" or "Yesterday".
2232
2233 "Loc", // 4 # of syncs with local sources. (including failures/cancels. )
2234 "Poll", // 5 "poll" syncs.
2235 "Per", // 6 Periodic syncs.
2236 "Feed", // 7 Syncs with a "feed" extra. (subscribedfeeds?)
2237 "User", // 8 User-initiated
2238 "Othr", // 9 Other sources.
2239
2240 "Tot", // 10 Total syncs (including failures / cancels)
2241 "Fail", // 11 (Failure)
2242 "Can", // 12 (Cancel)
2243
2244 "Time", // 13 Total time
2245 "Last Sync", // 14
2246 "Backoff" // 15
Alon Albert57286f92012-10-09 14:21:38 -07002247 );
2248
2249 final List<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> sorted =
2250 Lists.newArrayList();
2251 sorted.addAll(mSyncAdapters.getAllServices(account.userId));
2252 Collections.sort(sorted,
2253 new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002254 @Override
2255 public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00002256 RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002257 return lhs.type.authority.compareTo(rhs.type.authority);
2258 }
2259 });
Alon Albert57286f92012-10-09 14:21:38 -07002260 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType : sorted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002261 if (!syncAdapterType.type.accountType.equals(account.account.type)) {
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002262 continue;
2263 }
Alon Albert57286f92012-10-09 14:21:38 -07002264 int row = table.getNumRows();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002265 Pair<AuthorityInfo, SyncStatusInfo> syncAuthoritySyncStatus =
Georgi Nikolovdbe846b2013-06-25 14:09:56 -07002266 mSyncStorageEngine.getCopyOfAuthorityWithSyncStatus(
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002267 new SyncStorageEngine.EndPoint(
2268 account.account,
2269 syncAdapterType.type.authority,
2270 account.userId));
Georgi Nikolovdbe846b2013-06-25 14:09:56 -07002271 SyncStorageEngine.AuthorityInfo settings = syncAuthoritySyncStatus.first;
2272 SyncStatusInfo status = syncAuthoritySyncStatus.second;
Makoto Onuki15e7a252017-06-08 17:12:05 -07002273 statuses.add(Pair.create(settings.target, status));
Matthew Williams8ef22042013-07-26 12:56:39 -07002274 String authority = settings.target.provider;
Alon Albert57286f92012-10-09 14:21:38 -07002275 if (authority.length() > 50) {
2276 authority = authority.substring(authority.length() - 50);
2277 }
2278 table.set(row, 0, authority, settings.syncable, settings.enabled);
Makoto Onuki15e7a252017-06-08 17:12:05 -07002279
Makoto Onuki94986212018-04-11 16:24:46 -07002280 QuadConsumer<String, Stats, Function<Integer, String>, Integer> c =
2281 (label, stats, filter, r) -> {
2282 sb.setLength(0);
2283 table.set(r, 3,
2284 label,
2285 filter.apply(stats.numSourceLocal),
2286 filter.apply(stats.numSourcePoll),
2287 filter.apply(stats.numSourcePeriodic),
2288 filter.apply(stats.numSourceFeed),
2289 filter.apply(stats.numSourceUser),
2290 filter.apply(stats.numSourceOther),
2291 filter.apply(stats.numSyncs),
2292 filter.apply(stats.numFailures),
2293 filter.apply(stats.numCancels),
2294 formatDurationHMS(sb, stats.totalElapsedTime));
2295 };
2296 c.accept("Total", status.totalStats, (i) -> Integer.toString(i), row);
2297 c.accept("Today", status.todayStats, this::zeroToEmpty, row + 1);
2298 c.accept("Yestr", status.yesterdayStats, this::zeroToEmpty, row + 2);
2299
2300 final int LAST_SYNC = 14;
2301 final int BACKOFF = LAST_SYNC + 1;
Alon Albert57286f92012-10-09 14:21:38 -07002302
Alon Albert57286f92012-10-09 14:21:38 -07002303 int row1 = row;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002304 if (settings.delayUntil > now) {
Makoto Onuki94986212018-04-11 16:24:46 -07002305 table.set(row1++, BACKOFF, "D: " + (settings.delayUntil - now) / 1000);
Alon Albert57286f92012-10-09 14:21:38 -07002306 if (settings.backoffTime > now) {
Makoto Onuki94986212018-04-11 16:24:46 -07002307 table.set(row1++, BACKOFF, "B: " + (settings.backoffTime - now) / 1000);
2308 table.set(row1++, BACKOFF, settings.backoffDelay / 1000);
Alon Albert57286f92012-10-09 14:21:38 -07002309 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002310 }
Alon Albert57286f92012-10-09 14:21:38 -07002311
Makoto Onuki010291d2017-06-06 16:32:47 -07002312 row1 = row;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002313 if (status.lastSuccessTime != 0) {
Makoto Onuki94986212018-04-11 16:24:46 -07002314 table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastSuccessSource]
Alon Albert57286f92012-10-09 14:21:38 -07002315 + " " + "SUCCESS");
Makoto Onuki94986212018-04-11 16:24:46 -07002316 table.set(row1++, LAST_SYNC, formatTime(status.lastSuccessTime));
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002317 }
2318 if (status.lastFailureTime != 0) {
Makoto Onuki94986212018-04-11 16:24:46 -07002319 table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastFailureSource]
Alon Albert57286f92012-10-09 14:21:38 -07002320 + " " + "FAILURE");
Makoto Onuki94986212018-04-11 16:24:46 -07002321 table.set(row1++, LAST_SYNC, formatTime(status.lastFailureTime));
Alon Albert57286f92012-10-09 14:21:38 -07002322 //noinspection UnusedAssignment
Makoto Onuki94986212018-04-11 16:24:46 -07002323 table.set(row1++, LAST_SYNC, status.lastFailureMesg);
Dianne Hackborn231cc602009-04-27 17:10:36 -07002324 }
2325 }
Alon Albert57286f92012-10-09 14:21:38 -07002326 table.writeTo(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002328
2329 dumpSyncHistory(pw);
2330
2331 pw.println();
2332 pw.println("Per Adapter History");
Makoto Onuki94986212018-04-11 16:24:46 -07002333 pw.println("(SERVER is now split up to FEED and OTHER)");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002334
2335 for (int i = 0; i < statuses.size(); i++) {
2336 final Pair<EndPoint, SyncStatusInfo> event = statuses.get(i);
2337
2338 pw.print(" ");
2339 pw.print(event.first.account.name);
2340 pw.print('/');
2341 pw.print(event.first.account.type);
2342 pw.print(" u");
2343 pw.print(event.first.userId);
2344 pw.print(" [");
2345 pw.print(event.first.provider);
2346 pw.print("]");
2347 pw.println();
2348
Makoto Onukif74cf942018-04-16 17:04:58 -07002349 pw.println(" Per source last syncs:");
2350 for (int j = 0; j < SyncStorageEngine.SOURCES.length; j++) {
2351 pw.print(" ");
2352 pw.print(String.format("%8s", SyncStorageEngine.SOURCES[j]));
2353 pw.print(" Success: ");
2354 pw.print(formatTime(event.second.perSourceLastSuccessTimes[j]));
2355
2356 pw.print(" Failure: ");
2357 pw.println(formatTime(event.second.perSourceLastFailureTimes[j]));
2358 }
2359
2360 pw.println(" Last syncs:");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002361 for (int j = 0; j < event.second.getEventCount(); j++) {
Makoto Onukif74cf942018-04-16 17:04:58 -07002362 pw.print(" ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002363 pw.print(formatTime(event.second.getEventTime(j)));
2364 pw.print(' ');
2365 pw.print(event.second.getEvent(j));
2366 pw.println();
2367 }
Makoto Onukif74cf942018-04-16 17:04:58 -07002368 if (event.second.getEventCount() == 0) {
2369 pw.println(" N/A");
2370 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002371 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002372 }
2373
Makoto Onuki94986212018-04-11 16:24:46 -07002374 private String zeroToEmpty(int value) {
2375 return (value != 0) ? Integer.toString(value) : "";
2376 }
2377
Dianne Hackborn231cc602009-04-27 17:10:36 -07002378 private void dumpTimeSec(PrintWriter pw, long time) {
2379 pw.print(time/1000); pw.print('.'); pw.print((time/100)%10);
2380 pw.print('s');
2381 }
Doug Zongker44f57472009-09-20 15:52:43 -07002382
Dianne Hackborn231cc602009-04-27 17:10:36 -07002383 private void dumpDayStatistic(PrintWriter pw, SyncStorageEngine.DayStats ds) {
2384 pw.print("Success ("); pw.print(ds.successCount);
2385 if (ds.successCount > 0) {
2386 pw.print(" for "); dumpTimeSec(pw, ds.successTime);
2387 pw.print(" avg="); dumpTimeSec(pw, ds.successTime/ds.successCount);
2388 }
2389 pw.print(") Failure ("); pw.print(ds.failureCount);
2390 if (ds.failureCount > 0) {
2391 pw.print(" for "); dumpTimeSec(pw, ds.failureTime);
2392 pw.print(" avg="); dumpTimeSec(pw, ds.failureTime/ds.failureCount);
2393 }
2394 pw.println(")");
2395 }
Doug Zongker44f57472009-09-20 15:52:43 -07002396
Alon Alberte0bde332011-09-22 14:26:16 -07002397 protected void dumpSyncHistory(PrintWriter pw) {
2398 dumpRecentHistory(pw);
2399 dumpDayStatistics(pw);
2400 }
2401
2402 private void dumpRecentHistory(PrintWriter pw) {
2403 final ArrayList<SyncStorageEngine.SyncHistoryItem> items
2404 = mSyncStorageEngine.getSyncHistory();
2405 if (items != null && items.size() > 0) {
2406 final Map<String, AuthoritySyncStats> authorityMap = Maps.newHashMap();
2407 long totalElapsedTime = 0;
2408 long totalTimes = 0;
2409 final int N = items.size();
2410
2411 int maxAuthority = 0;
2412 int maxAccount = 0;
2413 for (SyncStorageEngine.SyncHistoryItem item : items) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002414 SyncStorageEngine.AuthorityInfo authorityInfo
Alon Alberte0bde332011-09-22 14:26:16 -07002415 = mSyncStorageEngine.getAuthority(item.authorityId);
2416 final String authorityName;
2417 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002418 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002419 authorityName = authorityInfo.target.provider;
2420 accountKey = authorityInfo.target.account.name + "/"
2421 + authorityInfo.target.account.type
2422 + " u" + authorityInfo.target.userId;
Alon Alberte0bde332011-09-22 14:26:16 -07002423 } else {
2424 authorityName = "Unknown";
2425 accountKey = "Unknown";
2426 }
2427
2428 int length = authorityName.length();
2429 if (length > maxAuthority) {
2430 maxAuthority = length;
2431 }
2432 length = accountKey.length();
2433 if (length > maxAccount) {
2434 maxAccount = length;
2435 }
2436
2437 final long elapsedTime = item.elapsedTime;
2438 totalElapsedTime += elapsedTime;
2439 totalTimes++;
2440 AuthoritySyncStats authoritySyncStats = authorityMap.get(authorityName);
2441 if (authoritySyncStats == null) {
2442 authoritySyncStats = new AuthoritySyncStats(authorityName);
2443 authorityMap.put(authorityName, authoritySyncStats);
2444 }
2445 authoritySyncStats.elapsedTime += elapsedTime;
2446 authoritySyncStats.times++;
2447 final Map<String, AccountSyncStats> accountMap = authoritySyncStats.accountMap;
2448 AccountSyncStats accountSyncStats = accountMap.get(accountKey);
2449 if (accountSyncStats == null) {
2450 accountSyncStats = new AccountSyncStats(accountKey);
2451 accountMap.put(accountKey, accountSyncStats);
2452 }
2453 accountSyncStats.elapsedTime += elapsedTime;
2454 accountSyncStats.times++;
2455
2456 }
2457
Alon Albert27096822012-01-11 18:06:41 -08002458 if (totalElapsedTime > 0) {
2459 pw.println();
2460 pw.printf("Detailed Statistics (Recent history): "
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002461 + "%d (# of times) %ds (sync time)\n",
Alon Albert27096822012-01-11 18:06:41 -08002462 totalTimes, totalElapsedTime / 1000);
Alon Alberte0bde332011-09-22 14:26:16 -07002463
Alon Albert27096822012-01-11 18:06:41 -08002464 final List<AuthoritySyncStats> sortedAuthorities =
2465 new ArrayList<AuthoritySyncStats>(authorityMap.values());
2466 Collections.sort(sortedAuthorities, new Comparator<AuthoritySyncStats>() {
Alon Albertbf976ba2011-10-03 13:06:43 -07002467 @Override
Alon Albert27096822012-01-11 18:06:41 -08002468 public int compare(AuthoritySyncStats lhs, AuthoritySyncStats rhs) {
Alon Albertbf976ba2011-10-03 13:06:43 -07002469 // reverse order
2470 int compare = Integer.compare(rhs.times, lhs.times);
2471 if (compare == 0) {
2472 compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
Alon Alberte0bde332011-09-22 14:26:16 -07002473 }
Alon Albertbf976ba2011-10-03 13:06:43 -07002474 return compare;
Alon Alberte0bde332011-09-22 14:26:16 -07002475 }
Alon Albertbf976ba2011-10-03 13:06:43 -07002476 });
Alon Albert27096822012-01-11 18:06:41 -08002477
2478 final int maxLength = Math.max(maxAuthority, maxAccount + 3);
2479 final int padLength = 2 + 2 + maxLength + 2 + 10 + 11;
2480 final char chars[] = new char[padLength];
2481 Arrays.fill(chars, '-');
2482 final String separator = new String(chars);
2483
2484 final String authorityFormat =
2485 String.format(" %%-%ds: %%-9s %%-11s\n", maxLength + 2);
2486 final String accountFormat =
2487 String.format(" %%-%ds: %%-9s %%-11s\n", maxLength);
2488
2489 pw.println(separator);
2490 for (AuthoritySyncStats authoritySyncStats : sortedAuthorities) {
2491 String name = authoritySyncStats.name;
2492 long elapsedTime;
2493 int times;
2494 String timeStr;
2495 String timesStr;
2496
2497 elapsedTime = authoritySyncStats.elapsedTime;
2498 times = authoritySyncStats.times;
Alon Albertbf976ba2011-10-03 13:06:43 -07002499 timeStr = String.format("%ds/%d%%",
2500 elapsedTime / 1000,
2501 elapsedTime * 100 / totalElapsedTime);
2502 timesStr = String.format("%d/%d%%",
2503 times,
2504 times * 100 / totalTimes);
Alon Albert27096822012-01-11 18:06:41 -08002505 pw.printf(authorityFormat, name, timesStr, timeStr);
2506
2507 final List<AccountSyncStats> sortedAccounts =
2508 new ArrayList<AccountSyncStats>(
2509 authoritySyncStats.accountMap.values());
2510 Collections.sort(sortedAccounts, new Comparator<AccountSyncStats>() {
2511 @Override
2512 public int compare(AccountSyncStats lhs, AccountSyncStats rhs) {
2513 // reverse order
2514 int compare = Integer.compare(rhs.times, lhs.times);
2515 if (compare == 0) {
2516 compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
2517 }
2518 return compare;
2519 }
2520 });
2521 for (AccountSyncStats stats: sortedAccounts) {
2522 elapsedTime = stats.elapsedTime;
2523 times = stats.times;
2524 timeStr = String.format("%ds/%d%%",
2525 elapsedTime / 1000,
2526 elapsedTime * 100 / totalElapsedTime);
2527 timesStr = String.format("%d/%d%%",
2528 times,
2529 times * 100 / totalTimes);
2530 pw.printf(accountFormat, stats.name, timesStr, timeStr);
2531 }
2532 pw.println(separator);
Alon Alberte0bde332011-09-22 14:26:16 -07002533 }
Alon Alberte0bde332011-09-22 14:26:16 -07002534 }
2535
2536 pw.println();
2537 pw.println("Recent Sync History");
Makoto Onuki94986212018-04-11 16:24:46 -07002538 pw.println("(SERVER is now split up to FEED and OTHER)");
Alon Albert57286f92012-10-09 14:21:38 -07002539 final String format = " %-" + maxAccount + "s %-" + maxAuthority + "s %s\n";
Alon Albertbf976ba2011-10-03 13:06:43 -07002540 final Map<String, Long> lastTimeMap = Maps.newHashMap();
Alon Albert57286f92012-10-09 14:21:38 -07002541 final PackageManager pm = mContext.getPackageManager();
Alon Alberte0bde332011-09-22 14:26:16 -07002542 for (int i = 0; i < N; i++) {
2543 SyncStorageEngine.SyncHistoryItem item = items.get(i);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002544 SyncStorageEngine.AuthorityInfo authorityInfo
Alon Alberte0bde332011-09-22 14:26:16 -07002545 = mSyncStorageEngine.getAuthority(item.authorityId);
2546 final String authorityName;
2547 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002548 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002549 authorityName = authorityInfo.target.provider;
2550 accountKey = authorityInfo.target.account.name + "/"
2551 + authorityInfo.target.account.type
2552 + " u" + authorityInfo.target.userId;
Alon Alberte0bde332011-09-22 14:26:16 -07002553 } else {
2554 authorityName = "Unknown";
2555 accountKey = "Unknown";
2556 }
2557 final long elapsedTime = item.elapsedTime;
2558 final Time time = new Time();
2559 final long eventTime = item.eventTime;
2560 time.set(eventTime);
2561
Alon Albertbf976ba2011-10-03 13:06:43 -07002562 final String key = authorityName + "/" + accountKey;
2563 final Long lastEventTime = lastTimeMap.get(key);
2564 final String diffString;
2565 if (lastEventTime == null) {
2566 diffString = "";
2567 } else {
2568 final long diff = (lastEventTime - eventTime) / 1000;
2569 if (diff < 60) {
2570 diffString = String.valueOf(diff);
2571 } else if (diff < 3600) {
2572 diffString = String.format("%02d:%02d", diff / 60, diff % 60);
2573 } else {
2574 final long sec = diff % 3600;
2575 diffString = String.format("%02d:%02d:%02d",
2576 diff / 3600, sec / 60, sec % 60);
2577 }
2578 }
2579 lastTimeMap.put(key, eventTime);
2580
2581 pw.printf(" #%-3d: %s %8s %5.1fs %8s",
Alon Alberte0bde332011-09-22 14:26:16 -07002582 i + 1,
2583 formatTime(eventTime),
2584 SyncStorageEngine.SOURCES[item.source],
Alon Albertbf976ba2011-10-03 13:06:43 -07002585 ((float) elapsedTime) / 1000,
2586 diffString);
Alon Albert57286f92012-10-09 14:21:38 -07002587 pw.printf(format, accountKey, authorityName,
2588 SyncOperation.reasonToString(pm, item.reason));
Alon Alberte0bde332011-09-22 14:26:16 -07002589
2590 if (item.event != SyncStorageEngine.EVENT_STOP
2591 || item.upstreamActivity != 0
2592 || item.downstreamActivity != 0) {
2593 pw.printf(" event=%d upstreamActivity=%d downstreamActivity=%d\n",
2594 item.event,
2595 item.upstreamActivity,
2596 item.downstreamActivity);
2597 }
2598 if (item.mesg != null
2599 && !SyncStorageEngine.MESG_SUCCESS.equals(item.mesg)) {
2600 pw.printf(" mesg=%s\n", item.mesg);
2601 }
2602 }
Alon Albert57286f92012-10-09 14:21:38 -07002603 pw.println();
2604 pw.println("Recent Sync History Extras");
Makoto Onuki94986212018-04-11 16:24:46 -07002605 pw.println("(SERVER is now split up to FEED and OTHER)");
Alon Albert57286f92012-10-09 14:21:38 -07002606 for (int i = 0; i < N; i++) {
2607 final SyncStorageEngine.SyncHistoryItem item = items.get(i);
2608 final Bundle extras = item.extras;
2609 if (extras == null || extras.size() == 0) {
2610 continue;
2611 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002612 final SyncStorageEngine.AuthorityInfo authorityInfo
Alon Albert57286f92012-10-09 14:21:38 -07002613 = mSyncStorageEngine.getAuthority(item.authorityId);
2614 final String authorityName;
2615 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002616 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002617 authorityName = authorityInfo.target.provider;
2618 accountKey = authorityInfo.target.account.name + "/"
2619 + authorityInfo.target.account.type
2620 + " u" + authorityInfo.target.userId;
Alon Albert57286f92012-10-09 14:21:38 -07002621 } else {
2622 authorityName = "Unknown";
2623 accountKey = "Unknown";
2624 }
2625 final Time time = new Time();
2626 final long eventTime = item.eventTime;
2627 time.set(eventTime);
2628
2629 pw.printf(" #%-3d: %s %8s ",
2630 i + 1,
2631 formatTime(eventTime),
2632 SyncStorageEngine.SOURCES[item.source]);
2633
2634 pw.printf(format, accountKey, authorityName, extras);
2635 }
Alon Alberte0bde332011-09-22 14:26:16 -07002636 }
2637 }
2638
2639 private void dumpDayStatistics(PrintWriter pw) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07002640 SyncStorageEngine.DayStats dses[] = mSyncStorageEngine.getDayStatistics();
2641 if (dses != null && dses[0] != null) {
2642 pw.println();
2643 pw.println("Sync Statistics");
2644 pw.print(" Today: "); dumpDayStatistic(pw, dses[0]);
2645 int today = dses[0].day;
2646 int i;
2647 SyncStorageEngine.DayStats ds;
Doug Zongker44f57472009-09-20 15:52:43 -07002648
Dianne Hackborn231cc602009-04-27 17:10:36 -07002649 // Print each day in the current week.
2650 for (i=1; i<=6 && i < dses.length; i++) {
2651 ds = dses[i];
2652 if (ds == null) break;
2653 int delta = today-ds.day;
2654 if (delta > 6) break;
Doug Zongker44f57472009-09-20 15:52:43 -07002655
Dianne Hackborn231cc602009-04-27 17:10:36 -07002656 pw.print(" Day-"); pw.print(delta); pw.print(": ");
2657 dumpDayStatistic(pw, ds);
2658 }
Doug Zongker44f57472009-09-20 15:52:43 -07002659
Dianne Hackborn231cc602009-04-27 17:10:36 -07002660 // Aggregate all following days into weeks and print totals.
2661 int weekDay = today;
2662 while (i < dses.length) {
2663 SyncStorageEngine.DayStats aggr = null;
2664 weekDay -= 7;
2665 while (i < dses.length) {
2666 ds = dses[i];
2667 if (ds == null) {
2668 i = dses.length;
2669 break;
2670 }
2671 int delta = weekDay-ds.day;
2672 if (delta > 6) break;
2673 i++;
Doug Zongker44f57472009-09-20 15:52:43 -07002674
Dianne Hackborn231cc602009-04-27 17:10:36 -07002675 if (aggr == null) {
2676 aggr = new SyncStorageEngine.DayStats(weekDay);
2677 }
2678 aggr.successCount += ds.successCount;
2679 aggr.successTime += ds.successTime;
2680 aggr.failureCount += ds.failureCount;
2681 aggr.failureTime += ds.failureTime;
2682 }
2683 if (aggr != null) {
2684 pw.print(" Week-"); pw.print((today-weekDay)/7); pw.print(": ");
2685 dumpDayStatistic(pw, aggr);
2686 }
2687 }
2688 }
Alon Alberte0bde332011-09-22 14:26:16 -07002689 }
Doug Zongker44f57472009-09-20 15:52:43 -07002690
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002691 private void dumpSyncAdapters(IndentingPrintWriter pw) {
2692 pw.println();
2693 final List<UserInfo> users = getAllUsers();
2694 if (users != null) {
2695 for (UserInfo user : users) {
2696 pw.println("Sync adapters for " + user + ":");
2697 pw.increaseIndent();
2698 for (RegisteredServicesCache.ServiceInfo<?> info :
2699 mSyncAdapters.getAllServices(user.id)) {
2700 pw.println(info);
2701 }
2702 pw.decreaseIndent();
2703 pw.println();
2704 }
2705 }
2706 }
2707
Alon Alberte0bde332011-09-22 14:26:16 -07002708 private static class AuthoritySyncStats {
2709 String name;
2710 long elapsedTime;
2711 int times;
2712 Map<String, AccountSyncStats> accountMap = Maps.newHashMap();
2713
2714 private AuthoritySyncStats(String name) {
2715 this.name = name;
2716 }
2717 }
2718
2719 private static class AccountSyncStats {
2720 String name;
2721 long elapsedTime;
2722 int times;
2723
2724 private AccountSyncStats(String name) {
2725 this.name = name;
Dianne Hackborn231cc602009-04-27 17:10:36 -07002726 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727 }
2728
Philip P. Moltmann486b2412018-01-03 11:29:01 -08002729 interface OnReadyCallback {
2730 void onReady();
2731 }
2732
2733 static void sendOnUnsyncableAccount(@NonNull Context context,
2734 @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
2735 @UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) {
2736 OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo,
2737 onReadyCallback);
2738
2739 boolean isBound = context.bindServiceAsUser(
2740 getAdapterBindIntent(context, syncAdapterInfo.componentName, userId),
2741 connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId));
2742
2743 if (isBound) {
2744 // Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection.
2745 (new Handler(Looper.getMainLooper())).postDelayed(
2746 () -> context.unbindService(connection),
2747 OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS);
2748 } else {
2749 /*
2750 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
2751 * there the service cannot be bound, assume the default behavior.
2752 */
2753 connection.onReady();
2754 }
2755 }
2756
2757
2758 /**
2759 * Helper class for calling ISyncAdapter.onUnsyncableAccountDone.
2760 *
2761 * If this returns {@code true} the onReadyCallback is called. Otherwise nothing happens.
2762 */
2763 private static class OnUnsyncableAccountCheck implements ServiceConnection {
2764 static final long SERVICE_BOUND_TIME_MILLIS = 5000;
2765
2766 private final @NonNull OnReadyCallback mOnReadyCallback;
2767 private final @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType>
2768 mSyncAdapterInfo;
2769
2770 OnUnsyncableAccountCheck(
2771 @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
2772 @NonNull OnReadyCallback onReadyCallback) {
2773 mSyncAdapterInfo = syncAdapterInfo;
2774 mOnReadyCallback = onReadyCallback;
2775 }
2776
2777 private void onReady() {
2778 long identity = Binder.clearCallingIdentity();
2779 try {
2780 mOnReadyCallback.onReady();
2781 } finally {
2782 Binder.restoreCallingIdentity(identity);
2783 }
2784 }
2785
2786 @Override
2787 public void onServiceConnected(ComponentName name, IBinder service) {
2788 final ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
2789
2790 try {
2791 adapter.onUnsyncableAccount(new ISyncAdapterUnsyncableAccountCallback.Stub() {
2792 @Override
2793 public void onUnsyncableAccountDone(boolean isReady) {
2794 if (isReady) {
2795 onReady();
2796 }
2797 }
2798 });
2799 } catch (RemoteException e) {
2800 Slog.e(TAG, "Could not call onUnsyncableAccountDone " + mSyncAdapterInfo, e);
2801 /*
2802 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
2803 * there is a crash in the implementation, assume the default behavior.
2804 */
2805 onReady();
2806 }
2807 }
2808
2809 @Override
2810 public void onServiceDisconnected(ComponentName name) {
2811 // Wait until the service connects again
2812 }
2813 }
2814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002815 /**
2816 * A helper object to keep track of the time we have spent syncing since the last boot
2817 */
2818 private class SyncTimeTracker {
2819 /** True if a sync was in progress on the most recent call to update() */
2820 boolean mLastWasSyncing = false;
2821 /** Used to track when lastWasSyncing was last set */
2822 long mWhenSyncStarted = 0;
2823 /** The cumulative time we have spent syncing */
2824 private long mTimeSpentSyncing;
2825
2826 /** Call to let the tracker know that the sync state may have changed */
2827 public synchronized void update() {
Fred Quintana918339a2010-10-05 14:00:39 -07002828 final boolean isSyncInProgress = !mActiveSyncContexts.isEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002829 if (isSyncInProgress == mLastWasSyncing) return;
2830 final long now = SystemClock.elapsedRealtime();
2831 if (isSyncInProgress) {
2832 mWhenSyncStarted = now;
2833 } else {
2834 mTimeSpentSyncing += now - mWhenSyncStarted;
2835 }
2836 mLastWasSyncing = isSyncInProgress;
2837 }
2838
2839 /** Get how long we have been syncing, in ms */
2840 public synchronized long timeSpentSyncing() {
2841 if (!mLastWasSyncing) return mTimeSpentSyncing;
2842
2843 final long now = SystemClock.elapsedRealtime();
2844 return mTimeSpentSyncing + (now - mWhenSyncStarted);
2845 }
2846 }
2847
Fred Quintana718d8a22009-04-29 17:53:20 -07002848 class ServiceConnectionData {
2849 public final ActiveSyncContext activeSyncContext;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002850 public final IBinder adapter;
2851
2852 ServiceConnectionData(ActiveSyncContext activeSyncContext, IBinder adapter) {
Fred Quintana718d8a22009-04-29 17:53:20 -07002853 this.activeSyncContext = activeSyncContext;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002854 this.adapter = adapter;
Fred Quintana718d8a22009-04-29 17:53:20 -07002855 }
2856 }
2857
Makoto Onuki3ab77812018-07-09 14:29:33 -07002858 @Nullable
2859 private static SyncManager getInstance() {
Makoto Onuki056a9752018-05-08 15:21:56 -07002860 synchronized (SyncManager.class) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002861 if (sInstance == null) {
2862 Slog.wtf(TAG, "sInstance == null"); // Maybe called too early?
2863 }
2864 return sInstance;
2865 }
2866 }
2867
2868 /**
2869 * @return whether the device is ready to run sync jobs for a given user.
2870 */
2871 public static boolean readyToSync(int userId) {
2872 final SyncManager instance = getInstance();
2873 return (instance != null) && SyncJobService.isReady()
2874 && instance.mProvisioned && instance.isUserUnlocked(userId);
2875 }
2876
2877 public static void sendMessage(Message message) {
2878 final SyncManager instance = getInstance();
2879 if (instance != null) {
2880 instance.mSyncHandler.sendMessage(message);
Makoto Onuki056a9752018-05-08 15:21:56 -07002881 }
2882 }
2883
2884 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002885 * Handles SyncOperation Messages that are posted to the associated
2886 * HandlerThread.
2887 */
2888 class SyncHandler extends Handler {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002889 // Messages that can be sent on mHandler.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002890 private static final int MESSAGE_SYNC_FINISHED = 1;
Fred Quintana718d8a22009-04-29 17:53:20 -07002891 private static final int MESSAGE_SERVICE_CONNECTED = 4;
2892 private static final int MESSAGE_SERVICE_DISCONNECTED = 5;
Fred Quintana918339a2010-10-05 14:00:39 -07002893 private static final int MESSAGE_CANCEL = 6;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002894 static final int MESSAGE_START_SYNC = 10;
2895 static final int MESSAGE_STOP_SYNC = 11;
2896 static final int MESSAGE_SCHEDULE_SYNC = 12;
2897 static final int MESSAGE_UPDATE_PERIODIC_SYNC = 13;
2898 static final int MESSAGE_REMOVE_PERIODIC_SYNC = 14;
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002899
Matthew Williams1967c8d2015-06-19 19:03:13 -07002900 /**
2901 * Posted periodically to monitor network process for long-running syncs.
2902 * obj: {@link com.android.server.content.SyncManager.ActiveSyncContext}
2903 */
2904 private static final int MESSAGE_MONITOR_SYNC = 8;
振淦王60a74312015-12-01 16:37:31 +08002905 private static final int MESSAGE_ACCOUNTS_UPDATED = 9;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002906
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002907 public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002908 private final HashMap<String, PowerManager.WakeLock> mWakeLocks = Maps.newHashMap();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002909
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002910 public SyncHandler(Looper looper) {
2911 super(looper);
2912 }
2913
2914 public void handleMessage(Message msg) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002915 // TODO Do we really need this wake lock?? If we actually needed it, this is probably
2916 // not the best place to acquire the lock -- it's probably too late, because the device
2917 // could have gone to sleep before we reach here.
2918 mSyncManagerWakeLock.acquire();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002919 try {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002920 handleSyncMessage(msg);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002921 } finally {
2922 mSyncManagerWakeLock.release();
2923 }
2924 }
2925
2926 private void handleSyncMessage(Message msg) {
2927 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
2928
2929 try {
2930 mDataConnectionIsConnected = readDataConnectionState();
2931 switch (msg.what) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002932 case MESSAGE_ACCOUNTS_UPDATED:
2933 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2934 Slog.v(TAG, "handleSyncHandlerMessage: MESSAGE_ACCOUNTS_UPDATED");
2935 }
2936 EndPoint targets = (EndPoint) msg.obj;
2937 updateRunningAccountsH(targets);
2938 break;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002939 case MESSAGE_SCHEDULE_SYNC:
Shreyas Basargeba1f7902016-10-01 00:19:44 +01002940 ScheduleSyncMessagePayload syncPayload =
2941 (ScheduleSyncMessagePayload) msg.obj;
2942 SyncOperation op = syncPayload.syncOperation;
2943 scheduleSyncOperationH(op, syncPayload.minDelayMillis);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002944 break;
2945
2946 case MESSAGE_START_SYNC:
2947 op = (SyncOperation) msg.obj;
2948 startSyncH(op);
2949 break;
2950
2951 case MESSAGE_STOP_SYNC:
2952 op = (SyncOperation) msg.obj;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002953 if (isLoggable) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00002954 Slog.v(TAG, "Stop sync received.");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002955 }
2956 ActiveSyncContext asc = findActiveSyncContextH(op.jobId);
2957 if (asc != null) {
2958 runSyncFinishedOrCanceledH(null /* no result */, asc);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00002959 boolean reschedule = msg.arg1 != 0;
2960 boolean applyBackoff = msg.arg2 != 0;
2961 if (isLoggable) {
2962 Slog.v(TAG, "Stopping sync. Reschedule: " + reschedule
2963 + "Backoff: " + applyBackoff);
2964 }
2965 if (applyBackoff) {
2966 increaseBackoffSetting(op.target);
2967 }
2968 if (reschedule) {
2969 deferStoppedSyncH(op, 0);
2970 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002971 }
2972 break;
2973
2974 case MESSAGE_UPDATE_PERIODIC_SYNC:
2975 UpdatePeriodicSyncMessagePayload data =
2976 (UpdatePeriodicSyncMessagePayload) msg.obj;
2977 updateOrAddPeriodicSyncH(data.target, data.pollFrequency,
2978 data.flex, data.extras);
2979 break;
2980 case MESSAGE_REMOVE_PERIODIC_SYNC:
Makoto Onukidd4b14f2017-08-17 14:03:48 -07002981 Pair<EndPoint, String> args = (Pair<EndPoint, String>) (msg.obj);
2982 removePeriodicSyncH(args.first, msg.getData(), args.second);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002983 break;
2984
2985 case SyncHandler.MESSAGE_CANCEL:
2986 SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
2987 Bundle extras = msg.peekData();
Makoto Onukidecc5ba2019-01-15 09:34:05 -08002988 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002989 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_CANCEL: "
2990 + endpoint + " bundle: " + extras);
2991 }
Makoto Onukia9dca242017-06-21 17:06:49 -07002992 cancelActiveSyncH(endpoint, extras, "MESSAGE_CANCEL");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002993 break;
2994
2995 case SyncHandler.MESSAGE_SYNC_FINISHED:
2996 SyncFinishedOrCancelledMessagePayload payload =
2997 (SyncFinishedOrCancelledMessagePayload) msg.obj;
2998 if (!isSyncStillActiveH(payload.activeSyncContext)) {
Makoto Onukidecc5ba2019-01-15 09:34:05 -08002999 if (isLoggable) {
3000 Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
3001 + "sync is no longer active: "
3002 + payload.activeSyncContext);
3003 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003004 break;
3005 }
3006 if (isLoggable) {
3007 Slog.v(TAG, "syncFinished" + payload.activeSyncContext.mSyncOperation);
3008 }
Makoto Onuki3ab77812018-07-09 14:29:33 -07003009 SyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003010 payload.activeSyncContext.mSyncOperation.jobId, false,
3011 "sync finished");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003012 runSyncFinishedOrCanceledH(payload.syncResult,
3013 payload.activeSyncContext);
3014 break;
3015
3016 case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
3017 ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
Makoto Onukidecc5ba2019-01-15 09:34:05 -08003018 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003019 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
3020 + msgData.activeSyncContext);
3021 }
3022 // Check that this isn't an old message.
3023 if (isSyncStillActiveH(msgData.activeSyncContext)) {
3024 runBoundToAdapterH(
3025 msgData.activeSyncContext,
3026 msgData.adapter);
3027 }
3028 break;
3029 }
3030
3031 case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
3032 final ActiveSyncContext currentSyncContext =
3033 ((ServiceConnectionData) msg.obj).activeSyncContext;
Makoto Onukidecc5ba2019-01-15 09:34:05 -08003034 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003035 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
3036 + currentSyncContext);
3037 }
3038 // Check that this isn't an old message.
3039 if (isSyncStillActiveH(currentSyncContext)) {
3040 // cancel the sync if we have a syncadapter, which means one is
3041 // outstanding
3042 try {
3043 if (currentSyncContext.mSyncAdapter != null) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003044 mLogger.log("Calling cancelSync for SERVICE_DISCONNECTED ",
3045 currentSyncContext,
3046 " adapter=", currentSyncContext.mSyncAdapter);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003047 currentSyncContext.mSyncAdapter.cancelSync(currentSyncContext);
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003048 mLogger.log("Canceled");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003049 }
3050 } catch (RemoteException e) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003051 mLogger.log("RemoteException ", Log.getStackTraceString(e));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003052 // We don't need to retry this in this case.
3053 }
3054
3055 // Pretend that the sync failed with an IOException,
3056 // which is a soft error.
3057 SyncResult syncResult = new SyncResult();
3058 syncResult.stats.numIoExceptions++;
Makoto Onuki3ab77812018-07-09 14:29:33 -07003059 SyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003060 currentSyncContext.mSyncOperation.jobId, false,
3061 "service disconnected");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003062 runSyncFinishedOrCanceledH(syncResult, currentSyncContext);
3063 }
3064 break;
3065 }
3066
3067 case SyncHandler.MESSAGE_MONITOR_SYNC:
3068 ActiveSyncContext monitoredSyncContext = (ActiveSyncContext) msg.obj;
Makoto Onukidecc5ba2019-01-15 09:34:05 -08003069 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003070 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_MONITOR_SYNC: " +
3071 monitoredSyncContext.mSyncOperation.target);
3072 }
3073
3074 if (isSyncNotUsingNetworkH(monitoredSyncContext)) {
3075 Log.w(TAG, String.format(
3076 "Detected sync making no progress for %s. cancelling.",
Makoto Onukidecc5ba2019-01-15 09:34:05 -08003077 logSafe(monitoredSyncContext)));
Makoto Onuki3ab77812018-07-09 14:29:33 -07003078 SyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003079 monitoredSyncContext.mSyncOperation.jobId, false,
3080 "no network activity");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003081 runSyncFinishedOrCanceledH(
3082 null /* cancel => no result */, monitoredSyncContext);
3083 } else {
3084 // Repost message to check again.
3085 postMonitorSyncProgressMessage(monitoredSyncContext);
3086 }
3087 break;
3088
3089 }
3090 } finally {
3091 mSyncTimeTracker.update();
Fred Quintanae91ebe22009-09-29 20:44:30 -07003092 }
3093 }
3094
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003095 private PowerManager.WakeLock getSyncWakeLock(SyncOperation operation) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08003096 final String wakeLockKey = operation.wakeLockName();
Fred Quintanab3029c32010-04-06 13:27:12 -07003097 PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
3098 if (wakeLock == null) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08003099 final String name = SYNC_WAKE_LOCK_PREFIX + wakeLockKey;
Fred Quintanab3029c32010-04-06 13:27:12 -07003100 wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
3101 wakeLock.setReferenceCounted(false);
3102 mWakeLocks.put(wakeLockKey, wakeLock);
3103 }
3104 return wakeLock;
3105 }
3106
Matthew Williams8704fc32013-09-27 11:32:35 -07003107 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003108 * Defer the specified SyncOperation by rescheduling it on the JobScheduler with some
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003109 * delay. This is equivalent to a failure. If this is a periodic sync, a delayed one-off
3110 * sync will be scheduled.
Matthew Williams8704fc32013-09-27 11:32:35 -07003111 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003112 private void deferSyncH(SyncOperation op, long delay, String why) {
3113 mLogger.log("deferSyncH() ", (op.isPeriodic ? "periodic " : ""),
3114 "sync. op=", op, " delay=", delay, " why=", why);
Makoto Onuki3ab77812018-07-09 14:29:33 -07003115 SyncJobService.callJobFinished(op.jobId, false, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003116 if (op.isPeriodic) {
3117 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
3118 } else {
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003119 // mSyncJobService.callJobFinished is async, so cancel the job to ensure we don't
3120 // find the this job in the pending jobs list while looking for duplicates
3121 // before scheduling it at a later time.
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003122 cancelJob(op, "deferSyncH()");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003123 scheduleSyncOperationH(op, delay);
Fred Quintanae91ebe22009-09-29 20:44:30 -07003124 }
3125 }
Matthew Williams8704fc32013-09-27 11:32:35 -07003126
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003127 /* Same as deferSyncH, but assumes that job is no longer running on JobScheduler. */
3128 private void deferStoppedSyncH(SyncOperation op, long delay) {
3129 if (op.isPeriodic) {
3130 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
3131 } else {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003132 scheduleSyncOperationH(op, delay);
3133 }
3134 }
3135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003136 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003137 * Cancel an active sync and reschedule it on the JobScheduler with some delay.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003138 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003139 private void deferActiveSyncH(ActiveSyncContext asc, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003140 SyncOperation op = asc.mSyncOperation;
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003141 runSyncFinishedOrCanceledH(null, asc);
Makoto Onukia9dca242017-06-21 17:06:49 -07003142 deferSyncH(op, SYNC_DELAY_ON_CONFLICT, why);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 }
3144
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003145 private void startSyncH(SyncOperation op) {
3146 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3147 if (isLoggable) Slog.v(TAG, op.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148
Makoto Onuki94986212018-04-11 16:24:46 -07003149 // At this point, we know the device has been connected to the server, so
3150 // assume the clock is correct.
3151 mSyncStorageEngine.setClockValid();
3152
Makoto Onuki3ab77812018-07-09 14:29:33 -07003153 SyncJobService.markSyncStarted(op.jobId);
Makoto Onuki5397be12017-12-20 16:22:34 +09003154
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003155 if (mStorageIsLow) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003156 deferSyncH(op, SYNC_DELAY_ON_LOW_STORAGE, "storage low");
Matthew Williams8704fc32013-09-27 11:32:35 -07003157 return;
3158 }
3159
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003160 if (op.isPeriodic) {
3161 // Don't allow this periodic to run if a previous instance failed and is currently
3162 // scheduled according to some backoff criteria.
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003163 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003164 for (SyncOperation syncOperation: ops) {
3165 if (syncOperation.sourcePeriodicId == op.jobId) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003166 SyncJobService.callJobFinished(op.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003167 "periodic sync, pending");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003168 return;
Fred Quintana718d8a22009-04-29 17:53:20 -07003169 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003170 }
3171 // Don't allow this periodic to run if a previous instance failed and is currently
3172 // executing according to some backoff criteria.
3173 for (ActiveSyncContext asc: mActiveSyncContexts) {
3174 if (asc.mSyncOperation.sourcePeriodicId == op.jobId) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003175 SyncJobService.callJobFinished(op.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003176 "periodic sync, already running");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003177 return;
Fred Quintana718d8a22009-04-29 17:53:20 -07003178 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003179 }
3180 // Check for adapter delays.
3181 if (isAdapterDelayed(op.target)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003182 deferSyncH(op, 0 /* No minimum delay */, "backing off");
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003183 return;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003184 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003185 }
Fred Quintana718d8a22009-04-29 17:53:20 -07003186
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003187 // Check for conflicting syncs.
3188 for (ActiveSyncContext asc: mActiveSyncContexts) {
3189 if (asc.mSyncOperation.isConflict(op)) {
3190 // If the provided SyncOperation conflicts with a running one, the lower
3191 // priority sync is pre-empted.
3192 if (asc.mSyncOperation.findPriority() >= op.findPriority()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003194 Slog.v(TAG, "Rescheduling sync due to conflict " + op.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003196 deferSyncH(op, SYNC_DELAY_ON_CONFLICT, "delay on conflict");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003197 return;
Matthew Williamsfa774182013-06-18 15:44:11 -07003198 } else {
Matthew Williamsfa774182013-06-18 15:44:11 -07003199 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003200 Slog.v(TAG, "Pushing back running sync due to a higher priority sync");
Fred Quintana918339a2010-10-05 14:00:39 -07003201 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003202 deferActiveSyncH(asc, "preempted");
Shreyas Basarge7680dd92016-02-11 14:52:47 +00003203 break;
Alon Albert8e285552012-09-17 15:05:27 -07003204 }
3205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 }
3207
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003208 final int syncOpState = computeSyncOpState(op);
3209 switch (syncOpState) {
3210 case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
3211 case SYNC_OP_STATE_INVALID: {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003212 SyncJobService.callJobFinished(op.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003213 "invalid op state: " + syncOpState);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003214 } return;
3215 }
3216
3217 if (!dispatchSyncOperation(op)) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003218 SyncJobService.callJobFinished(op.jobId, false, "dispatchSyncOperation() failed");
Fred Quintana918339a2010-10-05 14:00:39 -07003219 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003220
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003221 setAuthorityPendingState(op.target);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003222 }
3223
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003224 private ActiveSyncContext findActiveSyncContextH(int jobId) {
3225 for (ActiveSyncContext asc: mActiveSyncContexts) {
3226 SyncOperation op = asc.mSyncOperation;
3227 if (op != null && op.jobId == jobId) {
3228 return asc;
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003229 }
3230 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003231 return null;
Matthew Williamsa4745542015-12-10 20:29:02 +00003232 }
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003233
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003234 private void updateRunningAccountsH(EndPoint syncTargets) {
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003235 AccountAndUser[] oldAccounts = mRunningAccounts;
振淦王60a74312015-12-01 16:37:31 +08003236 mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003237 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3238 Slog.v(TAG, "Accounts list: ");
3239 for (AccountAndUser acc : mRunningAccounts) {
3240 Slog.v(TAG, acc.toString());
3241 }
3242 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003243 if (mLogger.enabled()) {
3244 mLogger.log("updateRunningAccountsH: ", Arrays.toString(mRunningAccounts));
3245 }
Makoto Onuki3ab77812018-07-09 14:29:33 -07003246 removeStaleAccounts();
振淦王60a74312015-12-01 16:37:31 +08003247
3248 AccountAndUser[] accounts = mRunningAccounts;
3249 for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
3250 if (!containsAccountAndUser(accounts,
3251 currentSyncContext.mSyncOperation.target.account,
3252 currentSyncContext.mSyncOperation.target.userId)) {
3253 Log.d(TAG, "canceling sync since the account is no longer running");
3254 sendSyncFinishedOrCanceledMessage(currentSyncContext,
3255 null /* no result since this is a cancel */);
3256 }
3257 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003258
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003259 // On account add, check if there are any settings to be restored.
3260 for (AccountAndUser aau : mRunningAccounts) {
3261 if (!containsAccountAndUser(oldAccounts, aau.account, aau.userId)) {
3262 if (Log.isLoggable(TAG, Log.DEBUG)) {
3263 Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
3264 }
Ruslan Tkhakokhov19513032019-02-05 11:06:21 +00003265 AccountSyncSettingsBackupHelper.accountAdded(mContext, syncTargets.userId);
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003266 break;
3267 }
3268 }
3269
Rubin Xu2c548e02016-04-01 17:47:28 +01003270 // Cancel all jobs from non-existent accounts.
3271 AccountAndUser[] allAccounts = AccountManagerService.getSingleton().getAllAccounts();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003272 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003273 for (SyncOperation op: ops) {
Rubin Xu2c548e02016-04-01 17:47:28 +01003274 if (!containsAccountAndUser(allAccounts, op.target.account, op.target.userId)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003275 mLogger.log("canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003276 cancelJob(op, "updateRunningAccountsH()");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003277 }
3278 }
3279
3280 if (syncTargets != null) {
3281 scheduleSync(syncTargets.account, syncTargets.userId,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003282 SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
Makoto Onuki61283ec2018-01-31 17:22:36 -08003283 null, AuthorityInfo.NOT_INITIALIZED,
Makoto Onukie183a402018-08-29 11:46:41 -07003284 ContentResolver.SYNC_EXEMPTION_NONE, Process.myUid(), -4, null);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003285 }
3286 }
3287
3288 /**
3289 * The given SyncOperation will be removed and a new one scheduled in its place if
3290 * an updated period or flex is specified.
3291 * @param syncOperation SyncOperation whose period and flex is to be updated.
3292 * @param pollFrequencyMillis new period in milliseconds.
3293 * @param flexMillis new flex time in milliseconds.
3294 */
3295 private void maybeUpdateSyncPeriodH(SyncOperation syncOperation, long pollFrequencyMillis,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003296 long flexMillis) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003297 if (!(pollFrequencyMillis == syncOperation.periodMillis
3298 && flexMillis == syncOperation.flexMillis)) {
3299 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3300 Slog.v(TAG, "updating period " + syncOperation + " to " + pollFrequencyMillis
3301 + " and flex to " + flexMillis);
3302 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003303 SyncOperation newOp = new SyncOperation(syncOperation, pollFrequencyMillis,
3304 flexMillis);
3305 newOp.jobId = syncOperation.jobId;
3306 scheduleSyncOperationH(newOp);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003307 }
3308 }
3309
3310 private void updateOrAddPeriodicSyncH(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003311 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003312 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3313 verifyJobScheduler(); // Will fill in mScheduledSyncs cache if it is not already filled.
3314 final long pollFrequencyMillis = pollFrequency * 1000L;
3315 final long flexMillis = flex * 1000L;
3316 if (isLoggable) {
3317 Slog.v(TAG, "Addition to periodic syncs requested: " + target
3318 + " period: " + pollFrequency
3319 + " flexMillis: " + flex
3320 + " extras: " + extras.toString());
3321 }
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003322 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003323 for (SyncOperation op: ops) {
3324 if (op.isPeriodic && op.target.matchesSpec(target)
3325 && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
3326 maybeUpdateSyncPeriodH(op, pollFrequencyMillis, flexMillis);
3327 return;
3328 }
3329 }
3330
3331 if (isLoggable) {
3332 Slog.v(TAG, "Adding new periodic sync: " + target
3333 + " period: " + pollFrequency
3334 + " flexMillis: " + flex
3335 + " extras: " + extras.toString());
3336 }
3337
3338 final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
3339 syncAdapterInfo = mSyncAdapters.getServiceInfo(
3340 SyncAdapterType.newKey(
3341 target.provider, target.account.type),
3342 target.userId);
3343 if (syncAdapterInfo == null) {
3344 return;
3345 }
3346
3347 SyncOperation op = new SyncOperation(target, syncAdapterInfo.uid,
3348 syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC,
3349 SyncStorageEngine.SOURCE_PERIODIC, extras,
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003350 syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003351 pollFrequencyMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003352
3353 final int syncOpState = computeSyncOpState(op);
3354 switch (syncOpState) {
3355 case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
Svet Ganov973edd192016-09-08 20:15:55 -07003356 String packageName = op.owningPackage;
3357 final int userId = UserHandle.getUserId(op.owningUid);
3358 // If the app did not run and has no account access, done
Makoto Onuki850045d2018-08-09 11:31:14 -07003359 if (!wasPackageEverLaunched(packageName, userId)) {
Svet Ganov973edd192016-09-08 20:15:55 -07003360 return;
3361 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003362 mAccountManagerInternal.requestAccountAccess(op.target.account,
Svet Ganov973edd192016-09-08 20:15:55 -07003363 packageName, userId, new RemoteCallback((Bundle result) -> {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003364 if (result != null
3365 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
3366 updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
3367 }
3368 }
3369 ));
3370 } return;
3371
3372 case SYNC_OP_STATE_INVALID: {
3373 return;
3374 }
3375 }
3376
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003377 scheduleSyncOperationH(op);
3378 mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
3379 }
3380
3381 /**
3382 * Remove this periodic sync operation and all one-off operations initiated by it.
3383 */
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003384 private void removePeriodicSyncInternalH(SyncOperation syncOperation, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003385 // Remove this periodic sync and all one-off syncs initiated by it.
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003386 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003387 for (SyncOperation op: ops) {
3388 if (op.sourcePeriodicId == syncOperation.jobId || op.jobId == syncOperation.jobId) {
3389 ActiveSyncContext asc = findActiveSyncContextH(syncOperation.jobId);
3390 if (asc != null) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003391 SyncJobService.callJobFinished(syncOperation.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003392 "removePeriodicSyncInternalH");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003393 runSyncFinishedOrCanceledH(null, asc);
3394 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003395 mLogger.log("removePeriodicSyncInternalH-canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003396 cancelJob(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003397 }
3398 }
3399 }
3400
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003401 private void removePeriodicSyncH(EndPoint target, Bundle extras, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003402 verifyJobScheduler();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003403 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003404 for (SyncOperation op: ops) {
3405 if (op.isPeriodic && op.target.matchesSpec(target)
3406 && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003407 removePeriodicSyncInternalH(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003408 }
3409 }
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003410 }
3411
Matthew Williams1967c8d2015-06-19 19:03:13 -07003412 private boolean isSyncNotUsingNetworkH(ActiveSyncContext activeSyncContext) {
3413 final long bytesTransferredCurrent =
3414 getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
3415 final long deltaBytesTransferred =
3416 bytesTransferredCurrent - activeSyncContext.mBytesTransferredAtLastPoll;
3417
3418 if (Log.isLoggable(TAG, Log.DEBUG)) {
3419 // Bytes transferred
3420 long remainder = deltaBytesTransferred;
3421 long mb = remainder / (1024 * 1024);
3422 remainder %= 1024 * 1024;
3423 long kb = remainder / 1024;
3424 remainder %= 1024;
3425 long b = remainder;
3426 Log.d(TAG, String.format(
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003427 "Time since last update: %ds. Delta transferred: %dMBs,%dKBs,%dBs",
3428 (SystemClock.elapsedRealtime()
3429 - activeSyncContext.mLastPolledTimeElapsed)/1000,
3430 mb, kb, b)
Matthew Williams1967c8d2015-06-19 19:03:13 -07003431 );
3432 }
3433 return (deltaBytesTransferred <= SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES);
3434 }
3435
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003436 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003437 * Determine if a sync is no longer valid and should be dropped.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003438 */
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003439 private int computeSyncOpState(SyncOperation op) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003440 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003441 int state;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003442 final EndPoint target = op.target;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003443
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003444 // Drop the sync if the account of this operation no longer exists.
3445 AccountAndUser[] accounts = mRunningAccounts;
3446 if (!containsAccountAndUser(accounts, target.account, target.userId)) {
3447 if (isLoggable) {
3448 Slog.v(TAG, " Dropping sync operation: account doesn't exist.");
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003449 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003450 return SYNC_OP_STATE_INVALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003451 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003452 // Drop this sync request if it isn't syncable.
Philip P. Moltmann486b2412018-01-03 11:29:01 -08003453 state = computeSyncable(target.account, target.userId, target.provider, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003454 if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003455 if (isLoggable) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003456 Slog.v(TAG, " Dropping sync operation: "
3457 + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003458 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003459 return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003460 }
Svet Ganovdfed1c72016-08-25 15:40:52 -07003461 if (state == AuthorityInfo.NOT_SYNCABLE) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003462 if (isLoggable) {
Svet Ganovdfed1c72016-08-25 15:40:52 -07003463 Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003464 }
3465 return SYNC_OP_STATE_INVALID;
3466 }
3467
3468 final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
3469 && mSyncStorageEngine.getSyncAutomatically(target.account,
3470 target.userId, target.provider);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003471
3472 // We ignore system settings that specify the sync is invalid if:
3473 // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
3474 // or
3475 // 2) it's an initialisation sync - we just need to connect to it.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003476 final boolean ignoreSystemConfiguration = op.isIgnoreSettings() || (state < 0);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003477
3478 // Sync not enabled.
3479 if (!syncEnabled && !ignoreSystemConfiguration) {
3480 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003481 Slog.v(TAG, " Dropping sync operation: disallowed by settings/network.");
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003482 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003483 return SYNC_OP_STATE_INVALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003484 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003485 return SYNC_OP_STATE_VALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003486 }
Fred Quintana918339a2010-10-05 14:00:39 -07003487
Fred Quintana87b14662011-09-12 10:32:55 -07003488 private boolean dispatchSyncOperation(SyncOperation op) {
Fred Quintana918339a2010-10-05 14:00:39 -07003489 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003490 Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
3491 Slog.v(TAG, "num active syncs: " + mActiveSyncContexts.size());
Fred Quintana918339a2010-10-05 14:00:39 -07003492 for (ActiveSyncContext syncContext : mActiveSyncContexts) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003493 Slog.v(TAG, syncContext.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003494 }
3495 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07003496 if (op.isAppStandbyExempted()) {
3497 final UsageStatsManagerInternal usmi = LocalServices.getService(
3498 UsageStatsManagerInternal.class);
3499 if (usmi != null) {
3500 usmi.reportExemptedSyncStart(op.owningPackage,
3501 UserHandle.getUserId(op.owningUid));
3502 }
3503 }
3504
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003505 // Connect to the sync adapter.
3506 int targetUid;
3507 ComponentName targetComponent;
3508 final SyncStorageEngine.EndPoint info = op.target;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003509 SyncAdapterType syncAdapterType =
3510 SyncAdapterType.newKey(info.provider, info.account.type);
3511 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
3512 syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId);
3513 if (syncAdapterInfo == null) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003514 mLogger.log("dispatchSyncOperation() failed: no sync adapter info for ",
3515 syncAdapterType);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003516 Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
3517 + ", removing settings for it");
3518 mSyncStorageEngine.removeAuthority(info);
3519 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003521 targetUid = syncAdapterInfo.uid;
3522 targetComponent = syncAdapterInfo.componentName;
Fred Quintana718d8a22009-04-29 17:53:20 -07003523 ActiveSyncContext activeSyncContext =
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003524 new ActiveSyncContext(op, insertStartSyncEvent(op), targetUid);
Fred Quintana718d8a22009-04-29 17:53:20 -07003525 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003526 Slog.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);
Fred Quintana718d8a22009-04-29 17:53:20 -07003527 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07003528
3529 activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);
3530 mActiveSyncContexts.add(activeSyncContext);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003531
3532 // Post message to begin monitoring this sync's progress.
3533 postMonitorSyncProgressMessage(activeSyncContext);
3534
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003535 if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003536 mLogger.log("dispatchSyncOperation() failed: bind failed. target: ",
3537 targetComponent);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003538 Slog.e(TAG, "Bind attempt failed - target: " + targetComponent);
Fred Quintana918339a2010-10-05 14:00:39 -07003539 closeActiveSyncContext(activeSyncContext);
Fred Quintana87b14662011-09-12 10:32:55 -07003540 return false;
Fred Quintana718d8a22009-04-29 17:53:20 -07003541 }
3542
Fred Quintana87b14662011-09-12 10:32:55 -07003543 return true;
Fred Quintana718d8a22009-04-29 17:53:20 -07003544 }
3545
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003546 private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003547 IBinder syncAdapter) {
Fred Quintana918339a2010-10-05 14:00:39 -07003548 final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
Fred Quintana718d8a22009-04-29 17:53:20 -07003549 try {
Alon Alberteca75112010-12-08 15:02:33 -08003550 activeSyncContext.mIsLinkedToDeath = true;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003551 syncAdapter.linkToDeath(activeSyncContext, 0);
Alon Alberteca75112010-12-08 15:02:33 -08003552
Makoto Onukia9dca242017-06-21 17:06:49 -07003553 mLogger.log("Sync start: account=" + syncOperation.target.account,
3554 " authority=", syncOperation.target.provider,
3555 " reason=", SyncOperation.reasonToString(null, syncOperation.reason),
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003556 " extras=", SyncOperation.extrasToString(syncOperation.extras),
3557 " adapter=", activeSyncContext.mSyncAdapter);
Makoto Onukia9dca242017-06-21 17:06:49 -07003558
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003559 activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter);
3560 activeSyncContext.mSyncAdapter
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003561 .startSync(activeSyncContext, syncOperation.target.provider,
3562 syncOperation.target.account, syncOperation.extras);
Makoto Onukia9dca242017-06-21 17:06:49 -07003563
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003564 mLogger.log("Sync is running now...");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003565 } catch (RemoteException remoteExc) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003566 mLogger.log("Sync failed with RemoteException: ", remoteExc.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003567 Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);
3568 closeActiveSyncContext(activeSyncContext);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003569 increaseBackoffSetting(syncOperation.target);
3570 scheduleSyncOperationH(syncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 } catch (RuntimeException exc) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003572 mLogger.log("Sync failed with RuntimeException: ", exc.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003573 closeActiveSyncContext(activeSyncContext);
Makoto Onukidecc5ba2019-01-15 09:34:05 -08003574 Slog.e(TAG, "Caught RuntimeException while starting the sync "
3575 + logSafe(syncOperation), exc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577 }
3578
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003579 /**
Matthew Williams8ef22042013-07-26 12:56:39 -07003580 * Cancel the sync for the provided target that matches the given bundle.
Matthew Williams1967c8d2015-06-19 19:03:13 -07003581 * @param info Can have null fields to indicate all the active syncs for that field.
3582 * @param extras Can be null to indicate <strong>all</strong> syncs for the given endpoint.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003583 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003584 private void cancelActiveSyncH(SyncStorageEngine.EndPoint info, Bundle extras,
3585 String why) {
Fred Quintana918339a2010-10-05 14:00:39 -07003586 ArrayList<ActiveSyncContext> activeSyncs =
3587 new ArrayList<ActiveSyncContext>(mActiveSyncContexts);
3588 for (ActiveSyncContext activeSyncContext : activeSyncs) {
3589 if (activeSyncContext != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003590 final SyncStorageEngine.EndPoint opInfo =
3591 activeSyncContext.mSyncOperation.target;
Matthew Williams8ef22042013-07-26 12:56:39 -07003592 if (!opInfo.matchesSpec(info)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003593 continue;
Fred Quintana918339a2010-10-05 14:00:39 -07003594 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003595 if (extras != null &&
3596 !syncExtrasEquals(activeSyncContext.mSyncOperation.extras,
3597 extras,
3598 false /* no config settings */)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003599 continue;
3600 }
Makoto Onuki3ab77812018-07-09 14:29:33 -07003601 SyncJobService.callJobFinished(activeSyncContext.mSyncOperation.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003602 why);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003603 runSyncFinishedOrCanceledH(null /* cancel => no result */, activeSyncContext);
Fred Quintana918339a2010-10-05 14:00:39 -07003604 }
3605 }
3606 }
3607
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003608 /**
3609 * Should be called when a one-off instance of a periodic sync completes successfully.
3610 */
3611 private void reschedulePeriodicSyncH(SyncOperation syncOperation) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003612 // Ensure that the periodic sync wasn't removed.
3613 SyncOperation periodicSync = null;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003614 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003615 for (SyncOperation op: ops) {
3616 if (op.isPeriodic && syncOperation.matchesPeriodicOperation(op)) {
3617 periodicSync = op;
3618 break;
3619 }
3620 }
3621 if (periodicSync == null) {
3622 return;
3623 }
3624 scheduleSyncOperationH(periodicSync);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003625 }
3626
Matthew Williams8b76d202015-05-03 18:16:25 -07003627 private void runSyncFinishedOrCanceledH(SyncResult syncResult,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003628 ActiveSyncContext activeSyncContext) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003629 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Alon Alberteca75112010-12-08 15:02:33 -08003630
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003631 final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
3632 final SyncStorageEngine.EndPoint info = syncOperation.target;
3633
Alon Alberteca75112010-12-08 15:02:33 -08003634 if (activeSyncContext.mIsLinkedToDeath) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003635 activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
Alon Alberteca75112010-12-08 15:02:33 -08003636 activeSyncContext.mIsLinkedToDeath = false;
3637 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003638 final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 String historyMessage;
3640 int downstreamActivity;
3641 int upstreamActivity;
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003642
Makoto Onukia9dca242017-06-21 17:06:49 -07003643 mLogger.log("runSyncFinishedOrCanceledH() op=", syncOperation, " result=", syncResult);
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003645 if (syncResult != null) {
3646 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003647 Slog.v(TAG, "runSyncFinishedOrCanceled [finished]: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 + syncOperation + ", result " + syncResult);
3649 }
3650
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003651 // In the non-canceled case, close the active sync context before doing the rest
3652 // of the stuff.
3653 closeActiveSyncContext(activeSyncContext);
3654
3655 // Note this part is probably okay to do before closeActiveSyncContext()...
3656 // But moved here to restore OC-dev's behavior. See b/64597061.
3657 if (!syncOperation.isPeriodic) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003658 cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-finished");
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003659 }
3660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003661 if (!syncResult.hasError()) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07003662 historyMessage = SyncStorageEngine.MESG_SUCCESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663 // TODO: set these correctly when the SyncResult is extended to include it
3664 downstreamActivity = 0;
3665 upstreamActivity = 0;
Makoto Onukia9dca242017-06-21 17:06:49 -07003666 clearBackoffSetting(syncOperation.target, "sync success");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003667
3668 // If the operation completes successfully and it was scheduled due to
3669 // a periodic operation failing, we reschedule the periodic operation to
3670 // start from now.
3671 if (syncOperation.isDerivedFromFailedPeriodicSync()) {
3672 reschedulePeriodicSyncH(syncOperation);
3673 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003674 } else {
Makoto Onukidecc5ba2019-01-15 09:34:05 -08003675 Log.w(TAG, "failed sync operation "
3676 + logSafe(syncOperation) + ", " + syncResult);
Makoto Onukiaad2b512018-02-07 09:31:46 -08003677
3678 syncOperation.retries++;
3679 if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07003680 syncOperation.syncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onukiaad2b512018-02-07 09:31:46 -08003681 }
3682
Fred Quintana307da1a2010-01-21 14:24:20 -08003683 // the operation failed so increase the backoff time
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003684 increaseBackoffSetting(syncOperation.target);
3685 if (!syncOperation.isPeriodic) {
3686 // reschedule the sync if so indicated by the syncResult
3687 maybeRescheduleSync(syncResult, syncOperation);
3688 } else {
3689 // create a normal sync instance that will respect adapter backoffs
Shreyas Basargeba1f7902016-10-01 00:19:44 +01003690 postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation(),
3691 0 /* min delay */);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003692 }
Alon Albert57286f92012-10-09 14:21:38 -07003693 historyMessage = ContentResolver.syncErrorToString(
3694 syncResultToErrorNumber(syncResult));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 // TODO: set these correctly when the SyncResult is extended to include it
3696 downstreamActivity = 0;
3697 upstreamActivity = 0;
3698 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003699 setDelayUntilTime(syncOperation.target, syncResult.delayUntil);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003700 } else {
3701 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003702 Slog.v(TAG, "runSyncFinishedOrCanceled [canceled]: " + syncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003703 }
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003704
3705 if (!syncOperation.isPeriodic) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003706 cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-canceled");
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003707 }
3708
Fred Quintana718d8a22009-04-29 17:53:20 -07003709 if (activeSyncContext.mSyncAdapter != null) {
3710 try {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003711 mLogger.log("Calling cancelSync for runSyncFinishedOrCanceled ",
3712 activeSyncContext, " adapter=", activeSyncContext.mSyncAdapter);
Fred Quintana21bb0de2009-06-16 10:24:58 -07003713 activeSyncContext.mSyncAdapter.cancelSync(activeSyncContext);
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003714 mLogger.log("Canceled");
Fred Quintana718d8a22009-04-29 17:53:20 -07003715 } catch (RemoteException e) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003716 mLogger.log("RemoteException ", Log.getStackTraceString(e));
Fred Quintana718d8a22009-04-29 17:53:20 -07003717 // we don't need to retry this in this case
3718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07003720 historyMessage = SyncStorageEngine.MESG_CANCELED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003721 downstreamActivity = 0;
3722 upstreamActivity = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003724 // In the cancel sync case, close it after calling cancelSync().
3725 closeActiveSyncContext(activeSyncContext);
3726 }
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003728 stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
3729 upstreamActivity, downstreamActivity, elapsedTime);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003730 // Check for full-resync and schedule it after closing off the last sync.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003731 if (syncResult != null && syncResult.tooManyDeletions) {
3732 installHandleTooManyDeletesNotification(info.account,
3733 info.provider, syncResult.stats.numDeletes,
3734 info.userId);
3735 } else {
Chris Wren282cfef2017-03-27 15:01:44 -04003736 mNotificationMgr.cancelAsUser(
3737 Integer.toString(info.account.hashCode() ^ info.provider.hashCode()),
3738 SystemMessage.NOTE_SYNC_ERROR,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003739 new UserHandle(info.userId));
3740 }
3741 if (syncResult != null && syncResult.fullSyncRequested) {
3742 scheduleSyncOperationH(
3743 new SyncOperation(info.account, info.userId,
3744 syncOperation.owningUid, syncOperation.owningPackage,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003745 syncOperation.reason,
3746 syncOperation.syncSource, info.provider, new Bundle(),
Makoto Onuki61283ec2018-01-31 17:22:36 -08003747 syncOperation.allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003748 syncOperation.syncExemptionFlag));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003750 }
3751
Fred Quintana918339a2010-10-05 14:00:39 -07003752 private void closeActiveSyncContext(ActiveSyncContext activeSyncContext) {
3753 activeSyncContext.close();
3754 mActiveSyncContexts.remove(activeSyncContext);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003755 mSyncStorageEngine.removeActiveSync(activeSyncContext.mSyncInfo,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003756 activeSyncContext.mSyncOperation.target.userId);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003757
3758 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003759 Slog.v(TAG, "removing all MESSAGE_MONITOR_SYNC & MESSAGE_SYNC_EXPIRED for "
Matthew Williams1967c8d2015-06-19 19:03:13 -07003760 + activeSyncContext.toString());
3761 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07003762 mSyncHandler.removeMessages(SyncHandler.MESSAGE_MONITOR_SYNC, activeSyncContext);
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003763
3764 mLogger.log("closeActiveSyncContext: ", activeSyncContext);
Fred Quintana918339a2010-10-05 14:00:39 -07003765 }
3766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 /**
3768 * Convert the error-containing SyncResult into the Sync.History error number. Since
3769 * the SyncResult may indicate multiple errors at once, this method just returns the
3770 * most "serious" error.
3771 * @param syncResult the SyncResult from which to read
3772 * @return the most "serious" error set in the SyncResult
3773 * @throws IllegalStateException if the SyncResult does not indicate any errors.
3774 * If SyncResult.error() is true then it is safe to call this.
3775 */
3776 private int syncResultToErrorNumber(SyncResult syncResult) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07003777 if (syncResult.syncAlreadyInProgress)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003778 return ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003779 if (syncResult.stats.numAuthExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003780 return ContentResolver.SYNC_ERROR_AUTHENTICATION;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003781 if (syncResult.stats.numIoExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003782 return ContentResolver.SYNC_ERROR_IO;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003783 if (syncResult.stats.numParseExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003784 return ContentResolver.SYNC_ERROR_PARSE;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003785 if (syncResult.stats.numConflictDetectedExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003786 return ContentResolver.SYNC_ERROR_CONFLICT;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003787 if (syncResult.tooManyDeletions)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003788 return ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003789 if (syncResult.tooManyRetries)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003790 return ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003791 if (syncResult.databaseError)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003792 return ContentResolver.SYNC_ERROR_INTERNAL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003793 throw new IllegalStateException("we are not in an error state, " + syncResult);
3794 }
3795
Fred Quintanad9d2f112009-04-23 13:36:27 -07003796 private void installHandleTooManyDeletesNotification(Account account, String authority,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003797 long numDeletes, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 if (mNotificationMgr == null) return;
Fred Quintanac848b702009-08-25 20:18:46 -07003799
3800 final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
3801 authority, 0 /* flags */);
3802 if (providerInfo == null) {
3803 return;
3804 }
3805 CharSequence authorityName = providerInfo.loadLabel(mContext.getPackageManager());
3806
Fred Quintanab19e62a2010-12-16 13:54:43 -08003807 Intent clickIntent = new Intent(mContext, SyncActivityTooManyDeletes.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003808 clickIntent.putExtra("account", account);
Tadashi G. Takaoka86135d32009-09-24 19:31:44 -07003809 clickIntent.putExtra("authority", authority);
Fred Quintanac848b702009-08-25 20:18:46 -07003810 clickIntent.putExtra("provider", authorityName.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003811 clickIntent.putExtra("numDeletes", numDeletes);
3812
3813 if (!isActivityAvailable(clickIntent)) {
3814 Log.w(TAG, "No activity found to handle too many deletes.");
3815 return;
3816 }
3817
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003818 UserHandle user = new UserHandle(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003819 final PendingIntent pendingIntent = PendingIntent
Dianne Hackborn41203752012-08-31 14:05:51 -07003820 .getActivityAsUser(mContext, 0, clickIntent,
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003821 PendingIntent.FLAG_CANCEL_CURRENT, null, user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822
3823 CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
3824 R.string.contentServiceTooManyDeletesNotificationDesc);
3825
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003826 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003827 Notification notification =
3828 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04003829 .setSmallIcon(R.drawable.stat_notify_sync_error)
3830 .setTicker(mContext.getString(R.string.contentServiceSync))
3831 .setWhen(System.currentTimeMillis())
3832 .setColor(contextForUser.getColor(
3833 com.android.internal.R.color.system_notification_accent_color))
3834 .setContentTitle(contextForUser.getString(
3835 R.string.contentServiceSyncNotificationTitle))
3836 .setContentText(
3837 String.format(tooManyDeletesDescFormat.toString(), authorityName))
3838 .setContentIntent(pendingIntent)
3839 .build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003840 notification.flags |= Notification.FLAG_ONGOING_EVENT;
Chris Wren282cfef2017-03-27 15:01:44 -04003841 mNotificationMgr.notifyAsUser(
3842 Integer.toString(account.hashCode() ^ authority.hashCode()),
3843 SystemMessage.NOTE_SYNC_ERROR,
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003844 notification, user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003845 }
3846
3847 /**
3848 * Checks whether an activity exists on the system image for the given intent.
3849 *
3850 * @param intent The intent for an activity.
3851 * @return Whether or not an activity exists.
3852 */
3853 private boolean isActivityAvailable(Intent intent) {
3854 PackageManager pm = mContext.getPackageManager();
3855 List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
3856 int listSize = list.size();
3857 for (int i = 0; i < listSize; i++) {
3858 ResolveInfo resolveInfo = list.get(i);
3859 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
3860 != 0) {
3861 return true;
3862 }
3863 }
3864
3865 return false;
3866 }
3867
3868 public long insertStartSyncEvent(SyncOperation syncOperation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003869 final long now = System.currentTimeMillis();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003870 EventLog.writeEvent(2720,
3871 syncOperation.toEventLog(SyncStorageEngine.EVENT_START));
3872 return mSyncStorageEngine.insertStartSyncEvent(syncOperation, now);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003873 }
3874
3875 public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003876 int upstreamActivity, int downstreamActivity, long elapsedTime) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003877 EventLog.writeEvent(2720,
3878 syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
Fred Quintana77c560f2010-03-29 22:20:26 -07003879 mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08003880 resultMessage, downstreamActivity, upstreamActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003881 }
3882 }
Fred Quintana918339a2010-10-05 14:00:39 -07003883
Matthew Williams8b76d202015-05-03 18:16:25 -07003884 private boolean isSyncStillActiveH(ActiveSyncContext activeSyncContext) {
Fred Quintana918339a2010-10-05 14:00:39 -07003885 for (ActiveSyncContext sync : mActiveSyncContexts) {
3886 if (sync == activeSyncContext) {
3887 return true;
3888 }
3889 }
3890 return false;
3891 }
Alon Albert57286f92012-10-09 14:21:38 -07003892
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003893 /**
3894 * Sync extra comparison function.
3895 * @param b1 bundle to compare
3896 * @param b2 other bundle to compare
3897 * @param includeSyncSettings if false, ignore system settings in bundle.
3898 */
3899 public static boolean syncExtrasEquals(Bundle b1, Bundle b2, boolean includeSyncSettings) {
3900 if (b1 == b2) {
3901 return true;
3902 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003903 // Exit early if we can.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003904 if (includeSyncSettings && b1.size() != b2.size()) {
3905 return false;
3906 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003907 Bundle bigger = b1.size() > b2.size() ? b1 : b2;
3908 Bundle smaller = b1.size() > b2.size() ? b2 : b1;
3909 for (String key : bigger.keySet()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003910 if (!includeSyncSettings && isSyncSetting(key)) {
3911 continue;
3912 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003913 if (!smaller.containsKey(key)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003914 return false;
3915 }
Matthew Williams9ad2c842015-10-16 12:01:31 -07003916 if (!Objects.equals(bigger.get(key), smaller.get(key))) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003917 return false;
3918 }
3919 }
3920 return true;
3921 }
3922
3923 /**
3924 * @return true if the provided key is used by the SyncManager in scheduling the sync.
3925 */
3926 private static boolean isSyncSetting(String key) {
3927 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
3928 return true;
3929 }
3930 if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
3931 return true;
3932 }
3933 if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF)) {
3934 return true;
3935 }
3936 if (key.equals(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY)) {
3937 return true;
3938 }
3939 if (key.equals(ContentResolver.SYNC_EXTRAS_MANUAL)) {
3940 return true;
3941 }
3942 if (key.equals(ContentResolver.SYNC_EXTRAS_UPLOAD)) {
3943 return true;
3944 }
3945 if (key.equals(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS)) {
3946 return true;
3947 }
3948 if (key.equals(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS)) {
3949 return true;
3950 }
3951 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD)) {
3952 return true;
3953 }
3954 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD)) {
3955 return true;
3956 }
3957 if (key.equals(ContentResolver.SYNC_EXTRAS_PRIORITY)) {
3958 return true;
3959 }
3960 if (key.equals(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED)) {
3961 return true;
3962 }
3963 if (key.equals(ContentResolver.SYNC_EXTRAS_INITIALIZE)) {
3964 return true;
3965 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08003966// if (key.equals(ContentResolver.SYNC_EXTRAS_APP_STANDBY_EXEMPTED)) {
3967// return true;
3968// }
3969 // No need to check virtual flags such as SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003970 return false;
3971 }
3972
Alon Albert57286f92012-10-09 14:21:38 -07003973 static class PrintTable {
Makoto Onuki15e7a252017-06-08 17:12:05 -07003974 private ArrayList<String[]> mTable = Lists.newArrayList();
Alon Albert57286f92012-10-09 14:21:38 -07003975 private final int mCols;
3976
3977 PrintTable(int cols) {
3978 mCols = cols;
3979 }
3980
3981 void set(int row, int col, Object... values) {
3982 if (col + values.length > mCols) {
3983 throw new IndexOutOfBoundsException("Table only has " + mCols +
3984 " columns. can't set " + values.length + " at column " + col);
3985 }
3986 for (int i = mTable.size(); i <= row; i++) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07003987 final String[] list = new String[mCols];
Alon Albert57286f92012-10-09 14:21:38 -07003988 mTable.add(list);
3989 for (int j = 0; j < mCols; j++) {
3990 list[j] = "";
3991 }
3992 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07003993 final String[] rowArray = mTable.get(row);
3994 for (int i = 0; i < values.length; i++) {
3995 final Object value = values[i];
3996 rowArray[col + i] = (value == null) ? "" : value.toString();
3997 }
Alon Albert57286f92012-10-09 14:21:38 -07003998 }
3999
4000 void writeTo(PrintWriter out) {
4001 final String[] formats = new String[mCols];
4002 int totalLength = 0;
4003 for (int col = 0; col < mCols; ++col) {
4004 int maxLength = 0;
4005 for (Object[] row : mTable) {
4006 final int length = row[col].toString().length();
4007 if (length > maxLength) {
4008 maxLength = length;
4009 }
4010 }
4011 totalLength += maxLength;
4012 formats[col] = String.format("%%-%ds", maxLength);
4013 }
Patrick Tjin31068162014-01-30 13:28:46 -08004014 formats[mCols - 1] = "%s";
Alon Albert57286f92012-10-09 14:21:38 -07004015 printRow(out, formats, mTable.get(0));
4016 totalLength += (mCols - 1) * 2;
4017 for (int i = 0; i < totalLength; ++i) {
4018 out.print("-");
4019 }
4020 out.println();
4021 for (int i = 1, mTableSize = mTable.size(); i < mTableSize; i++) {
4022 Object[] row = mTable.get(i);
4023 printRow(out, formats, row);
4024 }
4025 }
4026
4027 private void printRow(PrintWriter out, String[] formats, Object[] row) {
4028 for (int j = 0, rowLength = row.length; j < rowLength; j++) {
4029 out.printf(String.format(formats[j], row[j].toString()));
4030 out.print(" ");
4031 }
4032 out.println();
4033 }
4034
4035 public int getNumRows() {
4036 return mTable.size();
4037 }
4038 }
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004039
4040 private Context getContextForUser(UserHandle user) {
4041 try {
4042 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
4043 } catch (NameNotFoundException e) {
4044 // Default to mContext, not finding the package system is running as is unlikely.
4045 return mContext;
4046 }
4047 }
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004048
4049 private void cancelJob(SyncOperation op, String why) {
4050 if (op == null) {
4051 Slog.wtf(TAG, "Null sync operation detected.");
4052 return;
4053 }
4054 if (op.isPeriodic) {
4055 mLogger.log("Removing periodic sync ", op, " for ", why);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004056 }
4057 getJobScheduler().cancel(op.jobId);
4058 }
4059
Makoto Onuki94986212018-04-11 16:24:46 -07004060 public void resetTodayStats() {
4061 mSyncStorageEngine.resetTodayStats(/*force=*/ true);
4062 }
Makoto Onuki850045d2018-08-09 11:31:14 -07004063
4064 private boolean wasPackageEverLaunched(String packageName, int userId) {
4065 try {
4066 return mPackageManagerInternal.wasPackageEverLaunched(packageName, userId);
4067 } catch (IllegalArgumentException e) {
4068 return false; // Package has been removed.
4069 }
4070 }
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004071}