blob: 8b93e041fa4c7a7831feb9bf018d439cefe3da37 [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
Alon Alberte0bde332011-09-22 14:26:16 -070019import android.accounts.Account;
Amith Yamasanif29f2362012-04-05 18:29:52 -070020import android.accounts.AccountAndUser;
Alon Alberte0bde332011-09-22 14:26:16 -070021import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070022import android.accounts.AccountManagerInternal;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080023import android.annotation.NonNull;
Makoto Onuki3ab77812018-07-09 14:29:33 -070024import android.annotation.Nullable;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080025import android.annotation.UserIdInt;
Fred Quintana33e44692011-12-05 15:04:16 -080026import android.app.ActivityManager;
Amith Yamasani9422bdc2013-04-10 16:58:19 -070027import android.app.AppGlobals;
Alon Alberte0bde332011-09-22 14:26:16 -070028import android.app.Notification;
29import android.app.NotificationManager;
30import android.app.PendingIntent;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000031import android.app.job.JobInfo;
32import android.app.job.JobScheduler;
Makoto Onuki75ad2492018-03-28 14:42:42 -070033import android.app.usage.UsageStatsManagerInternal;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080034import android.content.BroadcastReceiver;
35import android.content.ComponentName;
36import android.content.ContentResolver;
Makoto Onuki75ad2492018-03-28 14:42:42 -070037import android.content.ContentResolver.SyncExemption;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080038import android.content.Context;
39import android.content.ISyncAdapter;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080040import android.content.ISyncAdapterUnsyncableAccountCallback;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080041import android.content.ISyncContext;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080042import android.content.Intent;
43import android.content.IntentFilter;
Matthew Williamsfa774182013-06-18 15:44:11 -070044import android.content.PeriodicSync;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080045import android.content.ServiceConnection;
46import android.content.SyncActivityTooManyDeletes;
47import android.content.SyncAdapterType;
48import android.content.SyncAdaptersCache;
49import android.content.SyncInfo;
50import android.content.SyncResult;
51import android.content.SyncStatusInfo;
Makoto Onuki94986212018-04-11 16:24:46 -070052import android.content.SyncStatusInfo.Stats;
Alon Alberte0bde332011-09-22 14:26:16 -070053import android.content.pm.ApplicationInfo;
Amith Yamasani9422bdc2013-04-10 16:58:19 -070054import android.content.pm.PackageInfo;
Alon Alberte0bde332011-09-22 14:26:16 -070055import android.content.pm.PackageManager;
Todd Kennedy0eb97382017-10-03 16:57:22 -070056import android.content.pm.PackageManager.NameNotFoundException;
Makoto Onukid4764302018-03-30 17:32:57 -070057import android.content.pm.PackageManagerInternal;
Alon Alberte0bde332011-09-22 14:26:16 -070058import android.content.pm.ProviderInfo;
59import android.content.pm.RegisteredServicesCache;
60import android.content.pm.RegisteredServicesCacheListener;
61import android.content.pm.ResolveInfo;
Amith Yamasani04e0d262012-02-14 11:50:53 -080062import android.content.pm.UserInfo;
Matthew Williams8b76d202015-05-03 18:16:25 -070063import android.database.ContentObserver;
Alon Alberte0bde332011-09-22 14:26:16 -070064import android.net.ConnectivityManager;
65import android.net.NetworkInfo;
Matthew Williams1967c8d2015-06-19 19:03:13 -070066import android.net.TrafficStats;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080067import android.os.BatteryStats;
Makoto Onukibbf6d8c2017-08-11 12:11:39 -070068import android.os.Binder;
Makoto Onukidd4b14f2017-08-17 14:03:48 -070069import android.os.Build;
Fred Quintana918339a2010-10-05 14:00:39 -070070import android.os.Bundle;
71import android.os.Handler;
Makoto Onukie08a5c22018-04-27 13:28:46 -070072import android.os.HandlerThread;
Fred Quintana918339a2010-10-05 14:00:39 -070073import android.os.IBinder;
74import android.os.Looper;
75import android.os.Message;
76import android.os.PowerManager;
Makoto Onuki75ad2492018-03-28 14:42:42 -070077import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070078import android.os.RemoteCallback;
Fred Quintana918339a2010-10-05 14:00:39 -070079import android.os.RemoteException;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080080import android.os.ServiceManager;
Fred Quintana918339a2010-10-05 14:00:39 -070081import android.os.SystemClock;
82import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070083import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070084import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070085import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.text.format.Time;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.util.EventLog;
89import android.util.Log;
Fred Quintana307da1a2010-01-21 14:24:20 -080090import android.util.Pair;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000091import android.util.Slog;
Makoto Onuki3ab77812018-07-09 14:29:33 -070092import android.util.SparseBooleanArray;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000093
Alon Albert8e285552012-09-17 15:05:27 -070094import com.android.internal.R;
Makoto Onuki056a9752018-05-08 15:21:56 -070095import com.android.internal.annotations.GuardedBy;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080096import com.android.internal.app.IBatteryStats;
Makoto Onukid4764302018-03-30 17:32:57 -070097import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
98import com.android.internal.notification.SystemNotificationChannels;
Dianne Hackborn8d044e82013-04-30 17:24:15 -070099import com.android.internal.os.BackgroundThread;
Makoto Onukid4764302018-03-30 17:32:57 -0700100import com.android.internal.util.ArrayUtils;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700101import com.android.internal.util.IndentingPrintWriter;
Makoto Onuki94986212018-04-11 16:24:46 -0700102import com.android.internal.util.function.QuadConsumer;
Makoto Onukid4764302018-03-30 17:32:57 -0700103import com.android.server.DeviceIdleController;
104import com.android.server.LocalServices;
105import com.android.server.SystemService;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800106import com.android.server.accounts.AccountManagerService;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000107import com.android.server.backup.AccountSyncSettingsBackupHelper;
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700108import com.android.server.content.SyncStorageEngine.AuthorityInfo;
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700109import com.android.server.content.SyncStorageEngine.EndPoint;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800110import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
Makoto Onukid4764302018-03-30 17:32:57 -0700111import com.android.server.job.JobSchedulerInternal;
112
113import com.google.android.collect.Lists;
114import com.google.android.collect.Maps;
Alon Albert8e285552012-09-17 15:05:27 -0700115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117import java.io.PrintWriter;
118import java.util.ArrayList;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000119import java.util.Arrays;
Fred Quintana918339a2010-10-05 14:00:39 -0700120import java.util.Collection;
121import java.util.Collections;
Alon Alberte0bde332011-09-22 14:26:16 -0700122import java.util.Comparator;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000123import java.util.HashMap;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000124import java.util.HashSet;
125import java.util.List;
126import java.util.Map;
Matthew Williams9ad2c842015-10-16 12:01:31 -0700127import java.util.Objects;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000128import java.util.Random;
129import java.util.Set;
Makoto Onuki94986212018-04-11 16:24:46 -0700130import java.util.function.Function;
Makoto Onuki15e7a252017-06-08 17:12:05 -0700131import java.util.function.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
133/**
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000134 * Implementation details:
135 * All scheduled syncs will be passed on to JobScheduler as jobs
136 * (See {@link #scheduleSyncOperationH(SyncOperation, long)}. This function schedules a job
137 * with JobScheduler with appropriate delay and constraints (according to backoffs and extras).
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000138 * The scheduleSyncOperationH function also assigns a unique jobId to each
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000139 * SyncOperation.
140 *
141 * Periodic Syncs:
142 * Each periodic sync is scheduled as a periodic job. If a periodic sync fails, we create a new
143 * one off SyncOperation and set its {@link SyncOperation#sourcePeriodicId} field to the jobId of the
144 * periodic sync. We don't allow the periodic job to run while any job initiated by it is pending.
145 *
146 * Backoffs:
147 * Each {@link EndPoint} has a backoff associated with it. When a SyncOperation fails, we increase
148 * the backoff on the authority. Then we reschedule all syncs associated with that authority to
149 * run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
150 * are rescheduled. A rescheduled sync will get a new jobId.
151 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 * @hide
153 */
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700154public class SyncManager {
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700155 static final String TAG = "SyncManager";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700157 private static final boolean DEBUG_ACCOUNT_ACCESS = false;
158
Makoto Onukib47e8942017-09-18 14:03:03 -0700159 // Only do the check on a debuggable build.
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700160 private static final boolean ENABLE_SUSPICIOUS_CHECK = Build.IS_DEBUGGABLE;
161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 /** Delay a sync due to local changes this long. In milliseconds */
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700163 private static final long LOCAL_SYNC_DELAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700165 static {
Fred Quintana918339a2010-10-05 14:00:39 -0700166 LOCAL_SYNC_DELAY =
167 SystemProperties.getLong("sync.local_sync_delay", 30 * 1000 /* 30 seconds */);
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 /**
Fred Quintana8570f742010-02-18 10:32:54 -0800171 * How long to wait before retrying a sync that failed due to one already being in progress.
172 */
173 private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
174
Matthew Williams92a1c092014-08-25 19:18:32 -0700175 /**
Matthew Williams1967c8d2015-06-19 19:03:13 -0700176 * How often to periodically poll network traffic for an adapter performing a sync to determine
177 * whether progress is being made.
178 */
179 private static final long SYNC_MONITOR_WINDOW_LENGTH_MILLIS = 60 * 1000; // 60 seconds
180
181 /**
182 * How many bytes must be transferred (Tx + Rx) over the period of time defined by
183 * {@link #SYNC_MONITOR_WINDOW_LENGTH_MILLIS} for the sync to be considered to be making
184 * progress.
185 */
186 private static final int SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES = 10; // 10 bytes
187
188 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000189 * If a previously scheduled sync becomes ready and we are low on storage, it gets
190 * pushed back for this amount of time.
191 */
192 private static final long SYNC_DELAY_ON_LOW_STORAGE = 60*60*1000; // 1 hour
193
194 /**
195 * If a sync becomes ready and it conflicts with an already running sync, it gets
196 * pushed back for this amount of time.
197 */
198 private static final long SYNC_DELAY_ON_CONFLICT = 10*1000; // 10 seconds
Fred Quintana3ec47302010-03-10 10:08:31 -0800199
Shreyas Basargefa272532016-03-09 16:52:48 +0000200 /**
201 * Generate job ids in the range [MIN_SYNC_JOB_ID, MAX_SYNC_JOB_ID) to avoid conflicts with
202 * other jobs scheduled by the system process.
203 */
204 private static final int MIN_SYNC_JOB_ID = 100000;
205 private static final int MAX_SYNC_JOB_ID = 110000;
206
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800207 private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/";
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700208 private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
Fred Quintana918339a2010-10-05 14:00:39 -0700209 private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
210
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700211
212 private static final int SYNC_OP_STATE_VALID = 0;
213 private static final int SYNC_OP_STATE_INVALID = 1;
214 private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
215
Philip P. Moltmann486b2412018-01-03 11:29:01 -0800216 /** Flags used when connecting to a sync adapter service */
217 private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
218 | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
219
Makoto Onuki056a9752018-05-08 15:21:56 -0700220 /** Singleton instance. */
221 @GuardedBy("SyncManager.class")
222 private static SyncManager sInstance;
223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225
Amith Yamasani04e0d262012-02-14 11:50:53 -0800226 private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
227
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700228 // TODO: add better locking around mRunningAccounts
229 private volatile AccountAndUser[] mRunningAccounts = INITIAL_ACCOUNTS_ARRAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230
Fred Quintana918339a2010-10-05 14:00:39 -0700231 volatile private PowerManager.WakeLock mSyncManagerWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 volatile private boolean mDataConnectionIsConnected = false;
233 volatile private boolean mStorageIsLow = false;
Dianne Hackborn4870e9d2015-04-08 16:55:47 -0700234 volatile private boolean mDeviceIsIdle = false;
Dianne Hackborn627dfa12015-11-11 18:10:30 -0800235 volatile private boolean mReportedSyncActive = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
237 private final NotificationManager mNotificationMgr;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800238 private final IBatteryStats mBatteryStats;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000239 private JobScheduler mJobScheduler;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000240 private JobSchedulerInternal mJobSchedulerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700242 private SyncStorageEngine mSyncStorageEngine;
Jeff Sharkeya706e2f2012-10-16 12:02:42 -0700243
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700244 protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
Fred Quintanaf892fb32009-08-27 21:32:08 -0700246 // Synchronized on "this". Instead of using this directly one should instead call
247 // its accessor, getConnManager().
248 private ConnectivityManager mConnManagerDoNotUseDirectly;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249
Matthew Williams8b76d202015-05-03 18:16:25 -0700250 /** Track whether the device has already been provisioned. */
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000251 private volatile boolean mProvisioned;
Matthew Williams8b76d202015-05-03 18:16:25 -0700252
Makoto Onuki94986212018-04-11 16:24:46 -0700253 protected final SyncAdaptersCache mSyncAdapters;
Fred Quintana718d8a22009-04-29 17:53:20 -0700254
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000255 private final Random mRand;
256
Makoto Onukia9dca242017-06-21 17:06:49 -0700257 private final SyncLogger mLogger;
258
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000259 private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
260 for (JobInfo job: pendingJobs) {
261 if (job.getId() == jobId) {
262 return true;
263 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000264 }
265 for (ActiveSyncContext asc: mActiveSyncContexts) {
266 if (asc.mSyncOperation.jobId == jobId) {
267 return true;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000268 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000269 }
270 return false;
271 }
272
273 private int getUnusedJobIdH() {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000274 int newJobId;
275 do {
276 newJobId = MIN_SYNC_JOB_ID + mRand.nextInt(MAX_SYNC_JOB_ID - MIN_SYNC_JOB_ID);
277 } while (isJobIdInUseLockedH(newJobId,
278 mJobSchedulerInternal.getSystemScheduledPendingJobs()));
279 return newJobId;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000280 }
281
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000282 private List<SyncOperation> getAllPendingSyncs() {
283 verifyJobScheduler();
284 List<JobInfo> pendingJobs = mJobSchedulerInternal.getSystemScheduledPendingJobs();
285 List<SyncOperation> pendingSyncs = new ArrayList<SyncOperation>(pendingJobs.size());
286 for (JobInfo job: pendingJobs) {
287 SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
288 if (op != null) {
289 pendingSyncs.add(op);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000290 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000291 }
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000292 return pendingSyncs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000293 }
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700294
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700295 private final BroadcastReceiver mStorageIntentReceiver =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700297 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 public void onReceive(Context context, Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 String action = intent.getAction();
300 if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
301 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000302 Slog.v(TAG, "Internal storage is low.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800303 }
304 mStorageIsLow = true;
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700305 cancelActiveSync(
306 SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
Makoto Onukia9dca242017-06-21 17:06:49 -0700307 null /* any sync */,
308 "storage low");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
310 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000311 Slog.v(TAG, "Internal storage is ok.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 }
313 mStorageIsLow = false;
Makoto Onukia9dca242017-06-21 17:06:49 -0700314 rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
315 "storage ok");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 }
317 }
318 };
319
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700320 private final BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700321 @Override
Amith Yamasanid648a602012-09-26 15:06:10 -0700322 public void onReceive(Context context, Intent intent) {
Makoto Onukifb636cc2017-12-07 15:46:26 -0800323 EndPoint target = new EndPoint(null, null, getSendingUserId());
Shreyas Basargedcb88c82016-02-03 00:09:18 +0000324 updateRunningAccounts(target /* sync targets for user */);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700325 }
326 };
327
Fred Quintanab3029c32010-04-06 13:27:12 -0700328 private final PowerManager mPowerManager;
Ashish Sharma69d95de2012-04-11 17:27:24 -0700329
Amith Yamasani9535c912012-10-10 21:48:33 -0700330 private final UserManager mUserManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700331
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700332 private final AccountManager mAccountManager;
333
334 private final AccountManagerInternal mAccountManagerInternal;
335
Svet Ganov973edd192016-09-08 20:15:55 -0700336 private final PackageManagerInternal mPackageManagerInternal;
337
Amith Yamasani258848d2012-08-10 17:06:33 -0700338 private List<UserInfo> getAllUsers() {
Amith Yamasani9535c912012-10-10 21:48:33 -0700339 return mUserManager.getUsers();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800340 }
341
342 private boolean containsAccountAndUser(AccountAndUser[] accounts, Account account, int userId) {
343 boolean found = false;
344 for (int i = 0; i < accounts.length; i++) {
345 if (accounts[i].userId == userId
346 && accounts[i].account.equals(account)) {
347 found = true;
348 break;
349 }
350 }
351 return found;
352 }
353
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000354 /** target indicates endpoints that should be synced after account info is updated. */
355 private void updateRunningAccounts(EndPoint target) {
356 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_ACCOUNTS_UPDATED");
振淦王60a74312015-12-01 16:37:31 +0800357 // Update accounts in handler thread.
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000358 Message m = mSyncHandler.obtainMessage(SyncHandler.MESSAGE_ACCOUNTS_UPDATED);
359 m.obj = target;
360 m.sendToTarget();
Fred Quintanad9d2f112009-04-23 13:36:27 -0700361 }
362
Makoto Onuki3ab77812018-07-09 14:29:33 -0700363 private void removeStaleAccounts() {
Amith Yamasanidb6a14c2012-10-17 21:16:52 -0700364 for (UserInfo user : mUserManager.getUsers(true)) {
365 // Skip any partially created/removed users
366 if (user.partial) continue;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700367 Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(
368 user.id, mContext.getOpPackageName());
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000369
Makoto Onuki3ab77812018-07-09 14:29:33 -0700370 mSyncStorageEngine.removeStaleAccounts(accountsForUser, user.id);
Jeff Sharkey8f55d112012-10-11 11:00:21 -0700371 }
372 }
373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 private BroadcastReceiver mConnectivityIntentReceiver =
375 new BroadcastReceiver() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000376 @Override
377 public void onReceive(Context context, Intent intent) {
378 final boolean wasConnected = mDataConnectionIsConnected;
Alon Alberted1d2532011-02-15 14:02:14 -0800379
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000380 // Don't use the intent to figure out if network is connected, just check
381 // ConnectivityManager directly.
382 mDataConnectionIsConnected = readDataConnectionState();
383 if (mDataConnectionIsConnected) {
384 if (!wasConnected) {
385 if (Log.isLoggable(TAG, Log.VERBOSE)) {
386 Slog.v(TAG, "Reconnection detected: clearing all backoffs");
387 }
Makoto Onukia9dca242017-06-21 17:06:49 -0700388 // Note the location of this code was wrong from nyc to oc; fixed in DR.
389 clearAllBackoffs("network reconnect");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000390 }
Matthew Williams119aac92014-09-28 20:42:23 -0700391 }
Alon Alberted1d2532011-02-15 14:02:14 -0800392 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000393 };
394
Makoto Onukia9dca242017-06-21 17:06:49 -0700395 private void clearAllBackoffs(String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000396 mSyncStorageEngine.clearAllBackoffsLocked();
Makoto Onukia9dca242017-06-21 17:06:49 -0700397 rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399
Alon Albert1bad83a2011-02-16 10:29:56 -0800400 private boolean readDataConnectionState() {
Alon Alberted1d2532011-02-15 14:02:14 -0800401 NetworkInfo networkInfo = getConnectivityManager().getActiveNetworkInfo();
402 return (networkInfo != null) && networkInfo.isConnected();
403 }
404
Makoto Onukie7b02982017-08-24 14:23:36 -0700405 private String getJobStats() {
406 JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
407 return "JobStats: "
408 + ((js == null) ? "(JobSchedulerInternal==null)"
409 : js.getPersistStats().toString());
410 }
411
Dianne Hackborn55280a92009-05-07 15:53:46 -0700412 private BroadcastReceiver mShutdownIntentReceiver =
413 new BroadcastReceiver() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000414 @Override
415 public void onReceive(Context context, Intent intent) {
416 Log.w(TAG, "Writing sync state before shutdown...");
417 getSyncStorageEngine().writeAllState();
Makoto Onukie7b02982017-08-24 14:23:36 -0700418
419 mLogger.log(getJobStats());
Makoto Onukife224e02017-06-29 14:11:14 -0700420 mLogger.log("Shutting down.");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000421 }
422 };
Dianne Hackborn55280a92009-05-07 15:53:46 -0700423
Makoto Onuki94986212018-04-11 16:24:46 -0700424 private final BroadcastReceiver mOtherIntentsReceiver =
425 new BroadcastReceiver() {
426 @Override
427 public void onReceive(Context context, Intent intent) {
428 if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
429 mSyncStorageEngine.setClockValid();
430 return;
431 }
432 }
433 };
434
Amith Yamasani13593602012-03-22 16:16:17 -0700435 private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
436 @Override
437 public void onReceive(Context context, Intent intent) {
Alon Albert8e285552012-09-17 15:05:27 -0700438 String action = intent.getAction();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700439 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
440 if (userId == UserHandle.USER_NULL) return;
441
Alon Albert8e285552012-09-17 15:05:27 -0700442 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700443 onUserRemoved(userId);
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700444 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
445 onUserUnlocked(userId);
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -0700446 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
447 onUserStopped(userId);
Alon Albert8e285552012-09-17 15:05:27 -0700448 }
Amith Yamasani13593602012-03-22 16:16:17 -0700449 }
450 };
451
Makoto Onukie08a5c22018-04-27 13:28:46 -0700452 private final HandlerThread mThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 private final SyncHandler mSyncHandler;
Makoto Onukiaad2b512018-02-07 09:31:46 -0800454 private final SyncManagerConstants mConstants;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455
Makoto Onuki3ab77812018-07-09 14:29:33 -0700456 @GuardedBy("mUnlockedUsers")
457 private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray();
Fred Quintana4f9cfc52009-09-02 15:20:23 -0700458
Fred Quintanaf892fb32009-08-27 21:32:08 -0700459 private ConnectivityManager getConnectivityManager() {
460 synchronized (this) {
461 if (mConnManagerDoNotUseDirectly == null) {
462 mConnManagerDoNotUseDirectly = (ConnectivityManager)mContext.getSystemService(
463 Context.CONNECTIVITY_SERVICE);
464 }
465 return mConnManagerDoNotUseDirectly;
466 }
467 }
468
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000469 /**
470 * Cancel all unnecessary jobs. This function will be run once after every boot.
471 */
472 private void cleanupJobs() {
473 // O(n^2) in number of jobs, so we run this on the background thread.
474 mSyncHandler.postAtFrontOfQueue(new Runnable() {
475 @Override
476 public void run() {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000477 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000478 Set<String> cleanedKeys = new HashSet<String>();
479 for (SyncOperation opx: ops) {
480 if (cleanedKeys.contains(opx.key)) {
481 continue;
482 }
483 cleanedKeys.add(opx.key);
484 for (SyncOperation opy: ops) {
485 if (opx == opy) {
486 continue;
487 }
488 if (opx.key.equals(opy.key)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700489 mLogger.log("Removing duplicate sync: ", opy);
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700490 cancelJob(opy, "cleanupJobs() x=" + opx + " y=" + opy);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000491 }
492 }
493 }
494 }
495 });
496 }
497
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000498 private synchronized void verifyJobScheduler() {
499 if (mJobScheduler != null) {
500 return;
501 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700502 final long token = Binder.clearCallingIdentity();
503 try {
504 if (Log.isLoggable(TAG, Log.VERBOSE)) {
505 Log.d(TAG, "initializing JobScheduler object.");
506 }
507 mJobScheduler = (JobScheduler) mContext.getSystemService(
508 Context.JOB_SCHEDULER_SERVICE);
509 mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
510 // Get all persisted syncs from JobScheduler
511 List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
512
513 int numPersistedPeriodicSyncs = 0;
514 int numPersistedOneshotSyncs = 0;
515 for (JobInfo job : pendingJobs) {
516 SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
517 if (op != null) {
518 if (op.isPeriodic) {
519 numPersistedPeriodicSyncs++;
520 } else {
521 numPersistedOneshotSyncs++;
522 // Set the pending status of this EndPoint to true. Pending icon is
523 // shown on the settings activity.
524 mSyncStorageEngine.markPending(op.target, true);
525 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000526 }
527 }
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700528 final String summary = "Loaded persisted syncs: "
529 + numPersistedPeriodicSyncs + " periodic syncs, "
530 + numPersistedOneshotSyncs + " oneshot syncs, "
531 + (pendingJobs.size()) + " total system server jobs, "
Makoto Onukie7b02982017-08-24 14:23:36 -0700532 + getJobStats();
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700533 Slog.i(TAG, summary);
534 mLogger.log(summary);
535
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700536 cleanupJobs();
537
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700538 if (ENABLE_SUSPICIOUS_CHECK &&
539 (numPersistedPeriodicSyncs == 0) && likelyHasPeriodicSyncs()) {
540 Slog.wtf(TAG, "Device booted with no persisted periodic syncs: " + summary);
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700541 }
542 } finally {
543 Binder.restoreCallingIdentity(token);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000544 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700545 }
546
547 /**
548 * @return whether the device most likely has some periodic syncs.
549 */
550 private boolean likelyHasPeriodicSyncs() {
551 try {
Makoto Onukib47e8942017-09-18 14:03:03 -0700552 // Each sync adapter has a daily periodic sync by default, but sync adapters can remove
553 // them by themselves. So here, we use an arbitrary threshold. If there are more than
554 // this many sync endpoints, surely one of them should have a periodic sync...
555 return mSyncStorageEngine.getAuthorityCount() >= 6;
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700556 } catch (Throwable th) {
557 // Just in case.
558 }
559 return false;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000560 }
561
562 private JobScheduler getJobScheduler() {
563 verifyJobScheduler();
564 return mJobScheduler;
565 }
566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 public SyncManager(Context context, boolean factoryTest) {
Makoto Onuki056a9752018-05-08 15:21:56 -0700568 synchronized (SyncManager.class) {
569 if (sInstance == null) {
570 sInstance = this;
571 } else {
572 Slog.wtf(TAG, "SyncManager instantiated multiple times");
573 }
574 }
575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 // Initialize the SyncStorageEngine first, before registering observers
577 // and creating threads and so on; it may fail if the disk is full.
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700578 mContext = context;
Amith Yamasani9535c912012-10-10 21:48:33 -0700579
Makoto Onukia9dca242017-06-21 17:06:49 -0700580 mLogger = SyncLogger.getInstance();
581
Makoto Onuki6963bea72017-12-12 10:42:39 -0800582 SyncStorageEngine.init(context, BackgroundThread.get().getLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 mSyncStorageEngine = SyncStorageEngine.getSingleton();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800584 mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700585 @Override
Makoto Onuki61283ec2018-01-31 17:22:36 -0800586 public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras,
Makoto Onukie183a402018-08-29 11:46:41 -0700587 @SyncExemption int syncExemptionFlag, int callingUid, int callingPid) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000588 scheduleSync(info.account, info.userId, reason, info.provider, extras,
Makoto Onukie183a402018-08-29 11:46:41 -0700589 AuthorityInfo.UNDEFINED, syncExemptionFlag, callingUid, callingPid, null);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000590 }
591 });
592
593 mSyncStorageEngine.setPeriodicSyncAddedListener(
594 new SyncStorageEngine.PeriodicSyncAddedListener() {
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000595 @Override
596 public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
597 long flex) {
598 updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
599 }
600 });
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000601
602 mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
603 @Override
604 public void onAuthorityRemoved(EndPoint removedAuthority) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700605 removeSyncsForAuthority(removedAuthority, "onAuthorityRemoved");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800606 }
607 });
608
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700609 mSyncAdapters = new SyncAdaptersCache(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610
Makoto Onukie08a5c22018-04-27 13:28:46 -0700611 mThread = new HandlerThread("SyncManager", android.os.Process.THREAD_PRIORITY_BACKGROUND);
612 mThread.start();
613 mSyncHandler = new SyncHandler(mThread.getLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614
Fred Quintana44037e62010-01-21 13:14:49 -0800615 mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700616 @Override
617 public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
Fred Quintana44037e62010-01-21 13:14:49 -0800618 if (!removed) {
Alon Albert57286f92012-10-09 14:21:38 -0700619 scheduleSync(null, UserHandle.USER_ALL,
620 SyncOperation.REASON_SERVICE_CHANGED,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800621 type.authority, null, AuthorityInfo.UNDEFINED,
Makoto Onukie183a402018-08-29 11:46:41 -0700622 ContentResolver.SYNC_EXEMPTION_NONE,
623 Process.myUid(), -1, null);
Fred Quintana44037e62010-01-21 13:14:49 -0800624 }
625 }
626 }, mSyncHandler);
Fred Quintana718d8a22009-04-29 17:53:20 -0700627
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000628 mRand = new Random(System.currentTimeMillis());
Makoto Onukiaad2b512018-02-07 09:31:46 -0800629 mConstants = new SyncManagerConstants(context);
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
632 context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
633
634 intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
635 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
636 context.registerReceiver(mStorageIntentReceiver, intentFilter);
637
Dianne Hackborn55280a92009-05-07 15:53:46 -0700638 intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
639 intentFilter.setPriority(100);
640 context.registerReceiver(mShutdownIntentReceiver, intentFilter);
641
Amith Yamasani13593602012-03-22 16:16:17 -0700642 intentFilter = new IntentFilter();
643 intentFilter.addAction(Intent.ACTION_USER_REMOVED);
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700644 intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -0700645 intentFilter.addAction(Intent.ACTION_USER_STOPPED);
Alon Albert8e285552012-09-17 15:05:27 -0700646 mContext.registerReceiverAsUser(
647 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
Amith Yamasani13593602012-03-22 16:16:17 -0700648
Makoto Onuki94986212018-04-11 16:24:46 -0700649 intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
650 context.registerReceiver(mOtherIntentsReceiver, intentFilter);
651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 if (!factoryTest) {
653 mNotificationMgr = (NotificationManager)
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000654 context.getSystemService(Context.NOTIFICATION_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 } else {
656 mNotificationMgr = null;
657 }
Fred Quintanab3029c32010-04-06 13:27:12 -0700658 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
Amith Yamasani9535c912012-10-10 21:48:33 -0700659 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700660 mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
661 mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
Svet Ganov973edd192016-09-08 20:15:55 -0700662 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700663
Svet Ganovf6d424f12016-09-20 20:18:53 -0700664 mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
665 // If the UID gained access to the account kick-off syncs lacking account access
666 if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
667 scheduleSync(account, UserHandle.getUserId(uid),
668 SyncOperation.REASON_ACCOUNTS_UPDATED,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800669 null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS,
Makoto Onukie183a402018-08-29 11:46:41 -0700670 ContentResolver.SYNC_EXEMPTION_NONE,
671 Process.myUid(), -2, null);
Svet Ganovf6d424f12016-09-20 20:18:53 -0700672 }
673 });
674
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800675 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
676 BatteryStats.SERVICE_NAME));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677
Fred Quintana918339a2010-10-05 14:00:39 -0700678 // This WakeLock is used to ensure that we stay awake while running the sync loop
679 // message handler. Normally we will hold a sync adapter wake lock while it is being
680 // synced but during the execution of the sync loop it might finish a sync for
681 // one sync adapter before starting the sync for the other sync adapter and we
682 // don't want the device to go to sleep during that window.
683 mSyncManagerWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
684 SYNC_LOOP_WAKE_LOCK);
685 mSyncManagerWakeLock.setReferenceCounted(false);
686
Matthew Williams8b76d202015-05-03 18:16:25 -0700687 mProvisioned = isDeviceProvisioned();
688 if (!mProvisioned) {
689 final ContentResolver resolver = context.getContentResolver();
690 ContentObserver provisionedObserver =
691 new ContentObserver(null /* current thread */) {
692 public void onChange(boolean selfChange) {
693 mProvisioned |= isDeviceProvisioned();
694 if (mProvisioned) {
Matthew Williams8b76d202015-05-03 18:16:25 -0700695 resolver.unregisterContentObserver(this);
696 }
697 }
698 };
699
700 synchronized (mSyncHandler) {
701 resolver.registerContentObserver(
702 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
703 false /* notifyForDescendents */,
704 provisionedObserver);
705
706 // The device *may* have been provisioned while we were registering above observer.
707 // Check again to make sure.
708 mProvisioned |= isDeviceProvisioned();
709 if (mProvisioned) {
710 resolver.unregisterContentObserver(provisionedObserver);
711 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700712 }
Matthew Williams8b76d202015-05-03 18:16:25 -0700713 }
Fred Quintanae91ebe22009-09-29 20:44:30 -0700714
715 if (!factoryTest) {
Amith Yamasanid648a602012-09-26 15:06:10 -0700716 // Register for account list updates for all users
717 mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
718 UserHandle.ALL,
719 new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
Matthew Williams5c6756f2014-10-02 04:12:28 +0000720 null, null);
Fred Quintanae91ebe22009-09-29 20:44:30 -0700721 }
Ashish Sharma69d95de2012-04-11 17:27:24 -0700722
Svet Ganov65712b02016-09-01 10:24:11 -0700723 // Sync adapters were able to access the synced account without the accounts
724 // permission which circumvents our permission model. Therefore, we require
725 // sync adapters that don't have access to the account to get user consent.
726 // This can be noisy, therefore we will white-list sync adapters installed
727 // before we started checking for account access because they already know
728 // the account (they run before) which is the genie is out of the bottle.
729 whiteListExistingSyncAdaptersIfNeeded();
Makoto Onukife224e02017-06-29 14:11:14 -0700730
Makoto Onukie7b02982017-08-24 14:23:36 -0700731 mLogger.log("Sync manager initialized: " + Build.FINGERPRINT);
Svet Ganov65712b02016-09-01 10:24:11 -0700732 }
733
Makoto Onuki3ab77812018-07-09 14:29:33 -0700734 public void onStartUser(int userId) {
735 // Log on the handler to avoid slowing down device boot.
736 mSyncHandler.post(() -> mLogger.log("onStartUser: user=", userId));
Makoto Onukife224e02017-06-29 14:11:14 -0700737 }
738
Makoto Onuki3ab77812018-07-09 14:29:33 -0700739 public void onUnlockUser(int userId) {
740 synchronized (mUnlockedUsers) {
741 mUnlockedUsers.put(userId, true);
742 }
743 // Log on the handler to avoid slowing down device boot.
744 mSyncHandler.post(() -> mLogger.log("onUnlockUser: user=", userId));
Makoto Onukife224e02017-06-29 14:11:14 -0700745 }
746
Makoto Onuki3ab77812018-07-09 14:29:33 -0700747 public void onStopUser(int userId) {
748 synchronized (mUnlockedUsers) {
749 mUnlockedUsers.put(userId, false);
750 }
751 // Log on the handler to avoid slowing down user switch.
752 mSyncHandler.post(() -> mLogger.log("onStopUser: user=", userId));
753 }
754
755 private boolean isUserUnlocked(int userId) {
756 synchronized (mUnlockedUsers) {
757 return mUnlockedUsers.get(userId);
758 }
Makoto Onukife224e02017-06-29 14:11:14 -0700759 }
760
Makoto Onukiaad2b512018-02-07 09:31:46 -0800761 public void onBootPhase(int phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800762 // Note SyncManager only receives PHASE_ACTIVITY_MANAGER_READY and after.
Makoto Onukiaad2b512018-02-07 09:31:46 -0800763 switch (phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800764 case SystemService.PHASE_ACTIVITY_MANAGER_READY:
Makoto Onukiaad2b512018-02-07 09:31:46 -0800765 mConstants.start();
766 break;
767 }
768 }
Makoto Onukife224e02017-06-29 14:11:14 -0700769
Svet Ganov65712b02016-09-01 10:24:11 -0700770 private void whiteListExistingSyncAdaptersIfNeeded() {
771 if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
772 return;
773 }
774 List<UserInfo> users = mUserManager.getUsers(true);
775 final int userCount = users.size();
776 for (int i = 0; i < userCount; i++) {
777 UserHandle userHandle = users.get(i).getUserHandle();
778 final int userId = userHandle.getIdentifier();
779 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
780 : mSyncAdapters.getAllServices(userId)) {
781 String packageName = service.componentName.getPackageName();
782 for (Account account : mAccountManager.getAccountsByTypeAsUser(
783 service.type.accountType, userHandle)) {
784 if (!canAccessAccount(account, packageName, userId)) {
785 mAccountManager.updateAppPermission(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700786 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
Svet Ganov65712b02016-09-01 10:24:11 -0700787 }
788 }
789 }
790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 }
792
Matthew Williams8b76d202015-05-03 18:16:25 -0700793 private boolean isDeviceProvisioned() {
794 final ContentResolver resolver = mContext.getContentResolver();
795 return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
796 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 /**
798 * Return a random value v that satisfies minValue <= v < maxValue. The difference between
799 * maxValue and minValue must be less than Integer.MAX_VALUE.
800 */
801 private long jitterize(long minValue, long maxValue) {
802 Random random = new Random(SystemClock.elapsedRealtime());
803 long spread = maxValue - minValue;
804 if (spread > Integer.MAX_VALUE) {
805 throw new IllegalArgumentException("the difference between the maxValue and the "
806 + "minValue must be less than " + Integer.MAX_VALUE);
807 }
808 return minValue + random.nextInt((int)spread);
809 }
810
Dianne Hackborn231cc602009-04-27 17:10:36 -0700811 public SyncStorageEngine getSyncStorageEngine() {
812 return mSyncStorageEngine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 }
Doug Zongker44f57472009-09-20 15:52:43 -0700814
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700815 private int getIsSyncable(Account account, int userId, String providerName) {
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700816 int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
817 UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
818
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000819 // If it's not a restricted user, return isSyncable.
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700820 if (userInfo == null || !userInfo.isRestricted()) return isSyncable;
821
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000822 // Else check if the sync adapter has opted-in or not.
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700823 RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
824 mSyncAdapters.getServiceInfo(
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000825 SyncAdapterType.newKey(providerName, account.type), userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700826 if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700827
828 PackageInfo pInfo = null;
829 try {
830 pInfo = AppGlobals.getPackageManager().getPackageInfo(
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000831 syncAdapterInfo.componentName.getPackageName(), 0, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700832 if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700833 } catch (RemoteException re) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000834 // Shouldn't happen.
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700835 return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700836 }
837 if (pInfo.restrictedAccountType != null
838 && pInfo.restrictedAccountType.equals(account.type)) {
839 return isSyncable;
840 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700841 return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700842 }
843 }
844
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000845 private void setAuthorityPendingState(EndPoint info) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000846 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000847 for (SyncOperation op: ops) {
848 if (!op.isPeriodic && op.target.matchesSpec(info)) {
849 getSyncStorageEngine().markPending(info, true);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700850 return;
851 }
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700852 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000853 getSyncStorageEngine().markPending(info, false);
Matthew Williamsfa774182013-06-18 15:44:11 -0700854 }
855
856 /**
857 * Initiate a sync. This can start a sync for all providers
858 * (pass null to url, set onlyTicklable to false), only those
859 * providers that are marked as ticklable (pass null to url,
860 * set onlyTicklable to true), or a specific provider (set url
861 * to the content url of the provider).
862 *
863 * <p>If the ContentResolver.SYNC_EXTRAS_UPLOAD boolean in extras is
864 * true then initiate a sync that just checks for local changes to send
865 * to the server, otherwise initiate a sync that first gets any
866 * changes from the server before sending local changes back to
867 * the server.
868 *
869 * <p>If a specific provider is being synced (the url is non-null)
870 * then the extras can contain SyncAdapter-specific information
871 * to control what gets synced (e.g. which specific feed to sync).
872 *
873 * <p>You'll start getting callbacks after this.
874 *
875 * @param requestedAccount the account to sync, may be null to signify all accounts
876 * @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
877 * then all users' accounts are considered.
878 * @param reason for sync request. If this is a positive integer, it is the Linux uid
879 * assigned to the process that requested the sync. If it's negative, the sync was requested by
880 * the SyncManager itself and could be one of the following:
881 * {@link SyncOperation#REASON_BACKGROUND_DATA_SETTINGS_CHANGED}
882 * {@link SyncOperation#REASON_ACCOUNTS_UPDATED}
883 * {@link SyncOperation#REASON_SERVICE_CHANGED}
884 * {@link SyncOperation#REASON_PERIODIC}
885 * {@link SyncOperation#REASON_IS_SYNCABLE}
886 * {@link SyncOperation#REASON_SYNC_AUTO}
887 * {@link SyncOperation#REASON_MASTER_SYNC_AUTO}
888 * {@link SyncOperation#REASON_USER_START}
889 * @param requestedAuthority the authority to sync, may be null to indicate all authorities
890 * @param extras a Map of SyncAdapter-specific information to control
891 * syncs of a specific provider. Can be null. Is ignored
892 * if the url is null.
Svet Ganovf6d424f12016-09-20 20:18:53 -0700893 * @param targetSyncState Only sync authorities that have the specified sync state.
894 * Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
Matthew Williamsfa774182013-06-18 15:44:11 -0700895 */
896 public void scheduleSync(Account requestedAccount, int userId, int reason,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800897 String requestedAuthority, Bundle extras, int targetSyncState,
Makoto Onukie183a402018-08-29 11:46:41 -0700898 @SyncExemption int syncExemptionFlag, int callingUid, int callingPid,
899 String callingPackage) {
Shreyas Basargeba1f7902016-10-01 00:19:44 +0100900 scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
Makoto Onukie183a402018-08-29 11:46:41 -0700901 0 /* min delay */, true /* checkIfAccountReady */, syncExemptionFlag,
902 callingUid, callingPid, callingPackage);
Shreyas Basargeba1f7902016-10-01 00:19:44 +0100903 }
904
905 /**
906 * @param minDelayMillis The sync can't land before this delay expires.
907 */
908 private void scheduleSync(Account requestedAccount, int userId, int reason,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800909 String requestedAuthority, Bundle extras, int targetSyncState,
910 final long minDelayMillis, boolean checkIfAccountReady,
Makoto Onukie183a402018-08-29 11:46:41 -0700911 @SyncExemption int syncExemptionFlag,
912 int callingUid, int callingPid, String callingPackage) {
Matthew Williamsfa774182013-06-18 15:44:11 -0700913 if (extras == null) {
914 extras = new Bundle();
915 }
Makoto Onukie183a402018-08-29 11:46:41 -0700916 extras.size(); // Force unpacel.
917 mLogger.log("scheduleSync: account=", requestedAccount,
918 " u", userId,
919 " authority=", requestedAuthority,
920 " reason=", reason,
921 " extras=", extras,
922 " cuid=", callingUid, " cpid=", callingPid, " cpkg=", callingPackage,
923 " mdm=", minDelayMillis,
924 " ciar=", checkIfAccountReady,
925 " sef=", syncExemptionFlag);
Matthew Williamsfa774182013-06-18 15:44:11 -0700926
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700927 AccountAndUser[] accounts = null;
928 if (requestedAccount != null) {
929 if (userId != UserHandle.USER_ALL) {
930 accounts = new AccountAndUser[]{new AccountAndUser(requestedAccount, userId)};
931 } else {
932 for (AccountAndUser runningAccount : mRunningAccounts) {
933 if (requestedAccount.equals(runningAccount.account)) {
934 accounts = ArrayUtils.appendElement(AccountAndUser.class,
935 accounts, runningAccount);
936 }
937 }
938 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700939 } else {
Matthew Williamsfa774182013-06-18 15:44:11 -0700940 accounts = mRunningAccounts;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700941 }
942
943 if (ArrayUtils.isEmpty(accounts)) {
Makoto Onukie183a402018-08-29 11:46:41 -0700944 mLogger.log("scheduleSync: no accounts configured, dropping");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700945 return;
Matthew Williamsfa774182013-06-18 15:44:11 -0700946 }
947
948 final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
949 final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
950 if (manualSync) {
951 extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
952 extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
953 }
954 final boolean ignoreSettings =
955 extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
956
957 int source;
958 if (uploadOnly) {
959 source = SyncStorageEngine.SOURCE_LOCAL;
960 } else if (manualSync) {
961 source = SyncStorageEngine.SOURCE_USER;
962 } else if (requestedAuthority == null) {
963 source = SyncStorageEngine.SOURCE_POLL;
964 } else {
Makoto Onuki94986212018-04-11 16:24:46 -0700965 if (extras.containsKey("feed")) {
966 source = SyncStorageEngine.SOURCE_FEED;
967 } else{
968 // This isn't strictly server, since arbitrary callers can (and do) request
969 // a non-forced two-way sync on a specific url.
970 source = SyncStorageEngine.SOURCE_OTHER;
971 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700972 }
973
974 for (AccountAndUser account : accounts) {
Fyodor Kupolov6fde2982015-01-06 17:46:37 -0800975 // If userId is specified, do not sync accounts of other users
Xiaohui Chen98404fd2015-08-17 16:09:02 -0700976 if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
Fyodor Kupolov6fde2982015-01-06 17:46:37 -0800977 && userId != account.userId) {
978 continue;
979 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700980 // Compile a list of authorities that have sync adapters.
981 // For each authority sync each account that matches a sync adapter.
982 final HashSet<String> syncableAuthorities = new HashSet<String>();
983 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
984 mSyncAdapters.getAllServices(account.userId)) {
985 syncableAuthorities.add(syncAdapter.type.authority);
986 }
987
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000988 // If the url was specified then replace the list of authorities
Matthew Williamsfa774182013-06-18 15:44:11 -0700989 // with just this authority or clear it if this authority isn't
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000990 // syncable.
Matthew Williamsfa774182013-06-18 15:44:11 -0700991 if (requestedAuthority != null) {
992 final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
993 syncableAuthorities.clear();
994 if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
995 }
996
997 for (String authority : syncableAuthorities) {
Philip P. Moltmann486b2412018-01-03 11:29:01 -0800998 int isSyncable = computeSyncable(account.account, account.userId, authority,
999 !checkIfAccountReady);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001000
Matthew Williams53abfdb2015-06-10 20:06:37 -07001001 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001002 continue;
1003 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001004
1005 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
1006 mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority,
1007 account.account.type), account.userId);
Matthew Williamsfa774182013-06-18 15:44:11 -07001008 if (syncAdapterInfo == null) {
1009 continue;
1010 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001011
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001012 final int owningUid = syncAdapterInfo.uid;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001013
1014 if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
Makoto Onukie183a402018-08-29 11:46:41 -07001015 mLogger.log("scheduleSync: Not scheduling sync operation: "
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001016 + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001017 Bundle finalExtras = new Bundle(extras);
Svet Ganov973edd192016-09-08 20:15:55 -07001018 String packageName = syncAdapterInfo.componentName.getPackageName();
1019 // If the app did not run and has no account access, done
Makoto Onuki850045d2018-08-09 11:31:14 -07001020 if (!wasPackageEverLaunched(packageName, userId)) {
Svet Ganov973edd192016-09-08 20:15:55 -07001021 continue;
1022 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001023 mAccountManagerInternal.requestAccountAccess(account.account,
Svet Ganov973edd192016-09-08 20:15:55 -07001024 packageName, userId,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001025 new RemoteCallback((Bundle result) -> {
1026 if (result != null
1027 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
1028 scheduleSync(account.account, userId, reason, authority,
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001029 finalExtras, targetSyncState, minDelayMillis,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001030 true /* checkIfAccountReady */,
Makoto Onukie183a402018-08-29 11:46:41 -07001031 syncExemptionFlag, callingUid, callingPid,
1032 callingPackage);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001033 }
1034 }
1035 ));
1036 continue;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001037 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001038
Matthew Williamsfa774182013-06-18 15:44:11 -07001039 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
1040 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001041 if (!checkIfAccountReady && isSyncable < 0 && isAlwaysSyncable) {
Matthew Williams53abfdb2015-06-10 20:06:37 -07001042 mSyncStorageEngine.setIsSyncable(
Makoto Onukid4764302018-03-30 17:32:57 -07001043 account.account, account.userId, authority, AuthorityInfo.SYNCABLE,
Makoto Onukie183a402018-08-29 11:46:41 -07001044 callingUid, callingPid);
Matthew Williams53abfdb2015-06-10 20:06:37 -07001045 isSyncable = AuthorityInfo.SYNCABLE;
Matthew Williamsfa774182013-06-18 15:44:11 -07001046 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001047
Svet Ganovf6d424f12016-09-20 20:18:53 -07001048 if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001049 continue;
1050 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07001051
Matthew Williamsfa774182013-06-18 15:44:11 -07001052 if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
1053 continue;
1054 }
1055
Matthew Williamsfa774182013-06-18 15:44:11 -07001056 boolean syncAllowed =
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001057 (isSyncable < 0) // Always allow if the isSyncable state is unknown.
1058 || ignoreSettings
1059 || (mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
Matthew Williamsfa774182013-06-18 15:44:11 -07001060 && mSyncStorageEngine.getSyncAutomatically(account.account,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001061 account.userId, authority));
Matthew Williamsfa774182013-06-18 15:44:11 -07001062 if (!syncAllowed) {
Makoto Onukie183a402018-08-29 11:46:41 -07001063 mLogger.log("scheduleSync: sync of ", account, " ", authority,
1064 " is not allowed, dropping request");
Matthew Williamsfa774182013-06-18 15:44:11 -07001065 continue;
1066 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001067 SyncStorageEngine.EndPoint info =
1068 new SyncStorageEngine.EndPoint(
1069 account.account, authority, account.userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001070 long delayUntil =
1071 mSyncStorageEngine.getDelayUntilTime(info);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001072
1073 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
1074
Svet Ganovf6d424f12016-09-20 20:18:53 -07001075 if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001076 if (checkIfAccountReady) {
1077 Bundle finalExtras = new Bundle(extras);
1078
1079 sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId,
1080 () -> scheduleSync(account.account, account.userId, reason,
1081 authority, finalExtras, targetSyncState, minDelayMillis,
Makoto Onukie183a402018-08-29 11:46:41 -07001082 false, syncExemptionFlag, callingUid, callingPid,
1083 callingPackage));
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001084 } else {
1085 // Initialisation sync.
1086 Bundle newExtras = new Bundle();
1087 newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
Makoto Onukie183a402018-08-29 11:46:41 -07001088
1089 mLogger.log("scheduleSync: schedule initialisation sync ",
1090 account, " ", authority);
1091
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001092 postScheduleSyncMessage(
1093 new SyncOperation(account.account, account.userId,
1094 owningUid, owningPackage, reason, source,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001095 authority, newExtras, allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001096 syncExemptionFlag),
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001097 minDelayMillis
1098 );
Matthew Williamsfa774182013-06-18 15:44:11 -07001099 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07001100 } else if (targetSyncState == AuthorityInfo.UNDEFINED
1101 || targetSyncState == isSyncable) {
Makoto Onukie183a402018-08-29 11:46:41 -07001102 mLogger.log("scheduleSync: scheduling sync ",
1103 account, " ", authority);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001104 postScheduleSyncMessage(
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001105 new SyncOperation(account.account, account.userId,
1106 owningUid, owningPackage, reason, source,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001107 authority, extras, allowParallelSyncs, syncExemptionFlag),
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001108 minDelayMillis
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001109 );
Makoto Onukie183a402018-08-29 11:46:41 -07001110 } else {
1111 mLogger.log("scheduleSync: not handling ",
1112 account, " ", authority);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 }
1114 }
1115 }
1116 }
1117
Svet Ganov96b9c752016-10-17 19:29:58 -07001118 public int computeSyncable(Account account, int userId, String authority,
1119 boolean checkAccountAccess) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001120 final int status = getIsSyncable(account, userId, authority);
1121 if (status == AuthorityInfo.NOT_SYNCABLE) {
1122 return AuthorityInfo.NOT_SYNCABLE;
1123 }
1124 final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
1125 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
1126 mSyncAdapters.getServiceInfo(type, userId);
1127 if (syncAdapterInfo == null) {
1128 return AuthorityInfo.NOT_SYNCABLE;
1129 }
1130 final int owningUid = syncAdapterInfo.uid;
1131 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
1132 try {
Dianne Hackbornc3af19a2017-01-20 17:00:44 -08001133 if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001134 Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
1135 + syncAdapterInfo.componentName
1136 + " -- package not allowed to start");
1137 return AuthorityInfo.NOT_SYNCABLE;
1138 }
1139 } catch (RemoteException e) {
1140 /* ignore - local call */
1141 }
Svet Ganov96b9c752016-10-17 19:29:58 -07001142 if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001143 Log.w(TAG, "Access to " + account + " denied for package "
1144 + owningPackage + " in UID " + syncAdapterInfo.uid);
1145 return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
1146 }
1147
1148 return status;
1149 }
1150
1151 private boolean canAccessAccount(Account account, String packageName, int uid) {
1152 if (mAccountManager.hasAccountAccess(account, packageName,
1153 UserHandle.getUserHandleForUid(uid))) {
1154 return true;
1155 }
1156 // We relax the account access rule to also include the system apps as
1157 // they are trusted and we want to minimize the cases where the user
1158 // involvement is required to grant access to the synced account.
1159 try {
1160 mContext.getPackageManager().getApplicationInfoAsUser(packageName,
1161 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.getUserId(uid));
1162 return true;
1163 } catch (NameNotFoundException e) {
1164 return false;
1165 }
1166 }
1167
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001168 private void removeSyncsForAuthority(EndPoint info, String why) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001169 mLogger.log("removeSyncsForAuthority: ", info);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001170 verifyJobScheduler();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001171 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001172 for (SyncOperation op: ops) {
1173 if (op.target.matchesSpec(info)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001174 mLogger.log("canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001175 cancelJob(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001176 }
1177 }
1178 }
1179
1180 /**
1181 * Remove a specific periodic sync identified by its target and extras.
1182 */
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001183 public void removePeriodicSync(EndPoint target, Bundle extras, String why) {
1184 Message m = mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_REMOVE_PERIODIC_SYNC,
1185 Pair.create(target, why));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001186 m.setData(extras);
1187 m.sendToTarget();
1188 }
1189
1190 /**
1191 * Add a periodic sync. If a sync with same target and extras exists, its period and
1192 * flexMillis will be updated.
1193 */
1194 public void updateOrAddPeriodicSync(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001195 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001196 UpdatePeriodicSyncMessagePayload payload = new UpdatePeriodicSyncMessagePayload(target,
1197 pollFrequency, flex, extras);
1198 mSyncHandler.obtainMessage(SyncHandler.MESSAGE_UPDATE_PERIODIC_SYNC, payload)
1199 .sendToTarget();
1200 }
1201
1202 /**
1203 * Get a list of periodic syncs corresponding to the given target.
1204 */
1205 public List<PeriodicSync> getPeriodicSyncs(EndPoint target) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001206 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001207 List<PeriodicSync> periodicSyncs = new ArrayList<PeriodicSync>();
1208
1209 for (SyncOperation op: ops) {
1210 if (op.isPeriodic && op.target.matchesSpec(target)) {
1211 periodicSyncs.add(new PeriodicSync(op.target.account, op.target.provider,
1212 op.extras, op.periodMillis / 1000, op.flexMillis / 1000));
1213 }
1214 }
1215
1216 return periodicSyncs;
1217 }
1218
Matthew Williamsfa774182013-06-18 15:44:11 -07001219 /**
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001220 * Schedule sync based on local changes to a provider. We wait for at least LOCAL_SYNC_DELAY
1221 * ms to batch syncs.
Matthew Williamsfa774182013-06-18 15:44:11 -07001222 */
Makoto Onuki61283ec2018-01-31 17:22:36 -08001223 public void scheduleLocalSync(Account account, int userId, int reason, String authority,
Makoto Onukie183a402018-08-29 11:46:41 -07001224 @SyncExemption int syncExemptionFlag,
1225 int callingUid, int callingPid, String callingPackage) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 final Bundle extras = new Bundle();
1227 extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
Matthew Williamsfa774182013-06-18 15:44:11 -07001228 scheduleSync(account, userId, reason, authority, extras,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001229 AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */,
Makoto Onukie183a402018-08-29 11:46:41 -07001230 syncExemptionFlag, callingUid, callingPid, callingPackage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 }
1232
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001233 public SyncAdapterType[] getSyncAdapterTypes(int userId) {
1234 final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
1235 serviceInfos = mSyncAdapters.getAllServices(userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -07001236 SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
1237 int i = 0;
1238 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
1239 types[i] = serviceInfo.type;
1240 ++i;
1241 }
1242 return types;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001243 }
1244
Amith Yamasani37a40c22015-06-17 13:25:42 -07001245 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
1246 return mSyncAdapters.getSyncAdapterPackagesForAuthority(authority, userId);
1247 }
1248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001250 SyncResult syncResult) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001251 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 Message msg = mSyncHandler.obtainMessage();
1253 msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001254 msg.obj = new SyncFinishedOrCancelledMessagePayload(syncContext, syncResult);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 mSyncHandler.sendMessage(msg);
1256 }
1257
Makoto Onukia9dca242017-06-21 17:06:49 -07001258 private void sendCancelSyncsMessage(final SyncStorageEngine.EndPoint info, Bundle extras,
1259 String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001260 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_CANCEL");
Makoto Onukia9dca242017-06-21 17:06:49 -07001261
1262 mLogger.log("sendCancelSyncsMessage() ep=", info, " why=", why);
1263
Fred Quintana918339a2010-10-05 14:00:39 -07001264 Message msg = mSyncHandler.obtainMessage();
1265 msg.what = SyncHandler.MESSAGE_CANCEL;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001266 msg.setData(extras);
1267 msg.obj = info;
Fred Quintana918339a2010-10-05 14:00:39 -07001268 mSyncHandler.sendMessage(msg);
1269 }
1270
Matthew Williams92a1c092014-08-25 19:18:32 -07001271 /**
Matthew Williams1967c8d2015-06-19 19:03:13 -07001272 * Post a delayed message that will monitor the given sync context by periodically checking how
1273 * much network has been used by the uid.
Matthew Williams92a1c092014-08-25 19:18:32 -07001274 */
Matthew Williams1967c8d2015-06-19 19:03:13 -07001275 private void postMonitorSyncProgressMessage(ActiveSyncContext activeSyncContext) {
Matthew Williams92a1c092014-08-25 19:18:32 -07001276 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001277 Slog.v(TAG, "posting MESSAGE_SYNC_MONITOR in " +
Matthew Williams1967c8d2015-06-19 19:03:13 -07001278 (SYNC_MONITOR_WINDOW_LENGTH_MILLIS/1000) + "s");
Matthew Williams92a1c092014-08-25 19:18:32 -07001279 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07001280
1281 activeSyncContext.mBytesTransferredAtLastPoll =
1282 getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
1283 activeSyncContext.mLastPolledTimeElapsed = SystemClock.elapsedRealtime();
1284 Message monitorMessage =
1285 mSyncHandler.obtainMessage(
1286 SyncHandler.MESSAGE_MONITOR_SYNC,
1287 activeSyncContext);
1288 mSyncHandler.sendMessageDelayed(monitorMessage, SYNC_MONITOR_WINDOW_LENGTH_MILLIS);
Matthew Williams92a1c092014-08-25 19:18:32 -07001289 }
1290
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001291 private void postScheduleSyncMessage(SyncOperation syncOperation, long minDelayMillis) {
1292 ScheduleSyncMessagePayload payload =
1293 new ScheduleSyncMessagePayload(syncOperation, minDelayMillis);
1294 mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, payload).sendToTarget();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001295 }
1296
Matthew Williams1967c8d2015-06-19 19:03:13 -07001297 /**
1298 * Monitor sync progress by calculating how many bytes it is managing to send to and fro.
1299 */
1300 private long getTotalBytesTransferredByUid(int uid) {
1301 return (TrafficStats.getUidRxBytes(uid) + TrafficStats.getUidTxBytes(uid));
1302 }
1303
1304 /**
1305 * Convenience class for passing parameters for a finished or cancelled sync to the handler
1306 * to be processed.
1307 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001308 private class SyncFinishedOrCancelledMessagePayload {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 public final ActiveSyncContext activeSyncContext;
1310 public final SyncResult syncResult;
1311
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001312 SyncFinishedOrCancelledMessagePayload(ActiveSyncContext syncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001313 SyncResult syncResult) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 this.activeSyncContext = syncContext;
1315 this.syncResult = syncResult;
1316 }
1317 }
1318
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001319 private class UpdatePeriodicSyncMessagePayload {
1320 public final EndPoint target;
1321 public final long pollFrequency;
1322 public final long flex;
1323 public final Bundle extras;
1324
1325 UpdatePeriodicSyncMessagePayload(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001326 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001327 this.target = target;
1328 this.pollFrequency = pollFrequency;
1329 this.flex = flex;
1330 this.extras = extras;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 }
1332 }
1333
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001334 private static class ScheduleSyncMessagePayload {
1335 final SyncOperation syncOperation;
1336 final long minDelayMillis;
1337
1338 ScheduleSyncMessagePayload(SyncOperation syncOperation, long minDelayMillis) {
1339 this.syncOperation = syncOperation;
1340 this.minDelayMillis = minDelayMillis;
1341 }
1342 }
1343
Makoto Onukia9dca242017-06-21 17:06:49 -07001344 private void clearBackoffSetting(EndPoint target, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001345 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
1346 if (backoff != null && backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE &&
1347 backoff.second == SyncStorageEngine.NOT_IN_BACKOFF_MODE) {
1348 return;
1349 }
1350 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1351 Slog.v(TAG, "Clearing backoffs for " + target);
1352 }
1353 mSyncStorageEngine.setBackoff(target,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001354 SyncStorageEngine.NOT_IN_BACKOFF_MODE,
1355 SyncStorageEngine.NOT_IN_BACKOFF_MODE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001356
Makoto Onukia9dca242017-06-21 17:06:49 -07001357 rescheduleSyncs(target, why);
Alon Albert6e079a32010-11-12 12:41:09 -08001358 }
1359
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001360 private void increaseBackoffSetting(EndPoint target) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001361 final long now = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362
Fred Quintana307da1a2010-01-21 14:24:20 -08001363 final Pair<Long, Long> previousSettings =
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001364 mSyncStorageEngine.getBackoff(target);
Alon Albertaeeb6202010-12-09 16:14:02 -08001365 long newDelayInMs = -1;
1366 if (previousSettings != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001367 // Don't increase backoff before current backoff is expired. This will happen for op's
Alon Albertaeeb6202010-12-09 16:14:02 -08001368 // with ignoreBackoff set.
1369 if (now < previousSettings.first) {
1370 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001371 Slog.v(TAG, "Still in backoff, do not increase it. "
1372 + "Remaining: " + ((previousSettings.first - now) / 1000) + " seconds.");
Alon Albertaeeb6202010-12-09 16:14:02 -08001373 }
1374 return;
1375 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001376 // Subsequent delays are the double of the previous delay.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001377 newDelayInMs =
1378 (long) (previousSettings.second * mConstants.getRetryTimeIncreaseFactor());
Alon Albertaeeb6202010-12-09 16:14:02 -08001379 }
1380 if (newDelayInMs <= 0) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001381 // The initial delay is the jitterized INITIAL_SYNC_RETRY_TIME_IN_MS.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001382 final long initialRetryMs = mConstants.getInitialSyncRetryTimeInSeconds() * 1000;
1383 newDelayInMs = jitterize(initialRetryMs, (long)(initialRetryMs * 1.1));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
1385
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001386 // Cap the delay.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001387 final long maxSyncRetryTimeInSeconds = mConstants.getMaxSyncRetryTimeInSeconds();
1388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
1390 newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
1391 }
1392
Alon Albertc1ac7762010-10-28 13:35:55 -07001393 final long backoff = now + newDelayInMs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001394 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1395 Slog.v(TAG, "Backoff until: " + backoff + ", delayTime: " + newDelayInMs);
1396 }
1397 mSyncStorageEngine.setBackoff(target, backoff, newDelayInMs);
Makoto Onukia9dca242017-06-21 17:06:49 -07001398 rescheduleSyncs(target, "increaseBackoffSetting");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001399 }
Alon Albertc1ac7762010-10-28 13:35:55 -07001400
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001401 /**
1402 * Reschedule all scheduled syncs for this EndPoint. The syncs will be scheduled according
1403 * to current backoff and delayUntil values of this EndPoint.
1404 */
Makoto Onukia9dca242017-06-21 17:06:49 -07001405 private void rescheduleSyncs(EndPoint target, String why) {
1406 mLogger.log("rescheduleSyncs() ep=", target, " why=", why);
1407
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001408 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001409 int count = 0;
1410 for (SyncOperation op: ops) {
1411 if (!op.isPeriodic && op.target.matchesSpec(target)) {
1412 count++;
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001413 cancelJob(op, why);
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001414 postScheduleSyncMessage(op, 0 /* min delay */);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001415 }
1416 }
1417 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1418 Slog.v(TAG, "Rescheduled " + count + " syncs for " + target);
Fred Quintana918339a2010-10-05 14:00:39 -07001419 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001420 }
1421
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001422 private void setDelayUntilTime(EndPoint target, long delayUntilSeconds) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001423 final long delayUntil = delayUntilSeconds * 1000;
1424 final long absoluteNow = System.currentTimeMillis();
1425 long newDelayUntilTime;
1426 if (delayUntil > absoluteNow) {
1427 newDelayUntilTime = SystemClock.elapsedRealtime() + (delayUntil - absoluteNow);
1428 } else {
1429 newDelayUntilTime = 0;
1430 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001431 mSyncStorageEngine.setDelayUntilTime(target, newDelayUntilTime);
1432 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1433 Slog.v(TAG, "Delay Until time set to " + newDelayUntilTime + " for " + target);
Fred Quintana918339a2010-10-05 14:00:39 -07001434 }
Makoto Onukia9dca242017-06-21 17:06:49 -07001435 rescheduleSyncs(target, "delayUntil newDelayUntilTime: " + newDelayUntilTime);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001436 }
1437
1438 private boolean isAdapterDelayed(EndPoint target) {
1439 long now = SystemClock.elapsedRealtime();
1440 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
1441 if (backoff != null && backoff.first != SyncStorageEngine.NOT_IN_BACKOFF_MODE
1442 && backoff.first > now) {
1443 return true;
1444 }
1445 if (mSyncStorageEngine.getDelayUntilTime(target) > now) {
1446 return true;
1447 }
1448 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 }
1450
1451 /**
Matthew Williams8ef22042013-07-26 12:56:39 -07001452 * Cancel the active sync if it matches the target.
1453 * @param info object containing info about which syncs to cancel. The target can
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001454 * have null account/provider info to specify all accounts/providers.
1455 * @param extras if non-null, specifies the exact sync to remove.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 */
Makoto Onukia9dca242017-06-21 17:06:49 -07001457 public void cancelActiveSync(SyncStorageEngine.EndPoint info, Bundle extras, String why) {
1458 sendCancelSyncsMessage(info, extras, why);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 }
1460
1461 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001462 * Schedule a sync operation with JobScheduler.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001464 private void scheduleSyncOperationH(SyncOperation syncOperation) {
1465 scheduleSyncOperationH(syncOperation, 0L);
1466 }
1467
1468 private void scheduleSyncOperationH(SyncOperation syncOperation, long minDelay) {
1469 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
1470 if (syncOperation == null) {
1471 Slog.e(TAG, "Can't schedule null sync operation.");
1472 return;
1473 }
1474 if (!syncOperation.ignoreBackoff()) {
1475 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target);
1476 if (backoff == null) {
1477 Slog.e(TAG, "Couldn't find backoff values for " + syncOperation.target);
1478 backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
1479 SyncStorageEngine.NOT_IN_BACKOFF_MODE);
1480 }
1481 long now = SystemClock.elapsedRealtime();
1482 long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0
1483 : backoff.first - now;
1484 long delayUntil = mSyncStorageEngine.getDelayUntilTime(syncOperation.target);
1485 long delayUntilDelay = delayUntil > now ? delayUntil - now : 0;
1486 if (isLoggable) {
1487 Slog.v(TAG, "backoff delay:" + backoffDelay
1488 + " delayUntil delay:" + delayUntilDelay);
1489 }
1490 minDelay = Math.max(minDelay, Math.max(backoffDelay, delayUntilDelay));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 }
1492
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001493 if (minDelay < 0) {
1494 minDelay = 0;
1495 }
1496
1497 // Check if duplicate syncs are pending. If found, keep one with least expected run time.
Makoto Onuki61283ec2018-01-31 17:22:36 -08001498
1499 // If any of the duplicate ones has exemption, then we inherit it.
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001500 if (!syncOperation.isPeriodic) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001501 int inheritedSyncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001502
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001503 // Check currently running syncs
1504 for (ActiveSyncContext asc: mActiveSyncContexts) {
1505 if (asc.mSyncOperation.key.equals(syncOperation.key)) {
1506 if (isLoggable) {
1507 Log.v(TAG, "Duplicate sync is already running. Not scheduling "
1508 + syncOperation);
1509 }
1510 return;
1511 }
1512 }
1513
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001514 int duplicatesCount = 0;
1515 long now = SystemClock.elapsedRealtime();
1516 syncOperation.expectedRuntime = now + minDelay;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001517 List<SyncOperation> pending = getAllPendingSyncs();
Makoto Onuki61283ec2018-01-31 17:22:36 -08001518 SyncOperation syncToRun = syncOperation;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001519 for (SyncOperation op : pending) {
1520 if (op.isPeriodic) {
1521 continue;
1522 }
1523 if (op.key.equals(syncOperation.key)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001524 if (syncToRun.expectedRuntime > op.expectedRuntime) {
1525 syncToRun = op;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001526 }
1527 duplicatesCount++;
1528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001530 if (duplicatesCount > 1) {
1531 Slog.e(TAG, "FATAL ERROR! File a bug if you see this.");
1532 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001533
1534 if (syncOperation != syncToRun) {
1535 // If there's a duplicate with an earlier run time that's not exempted,
1536 // and if the current operation is exempted with no minDelay,
1537 // cancel the duplicate one and keep the current one.
1538 //
1539 // This means the duplicate one has a negative expected run time, but it hasn't
1540 // been executed possibly because of app-standby.
1541
Makoto Onuki75ad2492018-03-28 14:42:42 -07001542 if ((minDelay == 0)
1543 && (syncToRun.syncExemptionFlag < syncOperation.syncExemptionFlag)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001544 syncToRun = syncOperation;
Makoto Onuki75ad2492018-03-28 14:42:42 -07001545 inheritedSyncExemptionFlag =
1546 Math.max(inheritedSyncExemptionFlag, syncToRun.syncExemptionFlag);
Makoto Onuki61283ec2018-01-31 17:22:36 -08001547 }
1548 }
1549
1550 // Cancel all other duplicate syncs.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001551 for (SyncOperation op : pending) {
1552 if (op.isPeriodic) {
1553 continue;
1554 }
1555 if (op.key.equals(syncOperation.key)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001556 if (op != syncToRun) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001557 if (isLoggable) {
1558 Slog.v(TAG, "Cancelling duplicate sync " + op);
1559 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07001560 inheritedSyncExemptionFlag =
1561 Math.max(inheritedSyncExemptionFlag, op.syncExemptionFlag);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001562 cancelJob(op, "scheduleSyncOperationH-duplicate");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001563 }
1564 }
1565 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001566 if (syncToRun != syncOperation) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001567 // Don't schedule because a duplicate sync with earlier expected runtime exists.
1568 if (isLoggable) {
1569 Slog.v(TAG, "Not scheduling because a duplicate exists.");
1570 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001571
1572 // TODO Should we give the winning one SYNC_EXTRAS_APP_STANDBY_EXEMPTED
1573 // if the current one has it?
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001574 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001576
1577 // If any of the duplicates had exemption, we exempt the current one.
Makoto Onuki75ad2492018-03-28 14:42:42 -07001578 //
1579 if (inheritedSyncExemptionFlag > ContentResolver.SYNC_EXEMPTION_NONE) {
1580 syncOperation.syncExemptionFlag = inheritedSyncExemptionFlag;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001583
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001584 // Syncs that are re-scheduled shouldn't get a new job id.
1585 if (syncOperation.jobId == SyncOperation.NO_JOB_ID) {
1586 syncOperation.jobId = getUnusedJobIdH();
1587 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001588
1589 if (isLoggable) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001590 Slog.v(TAG, "scheduling sync operation " + syncOperation.toString());
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001591 }
1592
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001593 int priority = syncOperation.findPriority();
1594
1595 final int networkType = syncOperation.isNotAllowedOnMetered() ?
1596 JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
1597
Makoto Onuki61283ec2018-01-31 17:22:36 -08001598 // Note this logic means when an exempted sync fails,
1599 // the back-off one will inherit it too, and will be exempted from app-standby.
Makoto Onuki75ad2492018-03-28 14:42:42 -07001600 final int jobFlags = syncOperation.isAppStandbyExempted()
Makoto Onuki61283ec2018-01-31 17:22:36 -08001601 ? JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY : 0;
1602
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001603 JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001604 new ComponentName(mContext, SyncJobService.class))
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001605 .setExtras(syncOperation.toJobInfoExtras())
1606 .setRequiredNetworkType(networkType)
1607 .setPersisted(true)
Makoto Onuki61283ec2018-01-31 17:22:36 -08001608 .setPriority(priority)
1609 .setFlags(jobFlags);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001610
1611 if (syncOperation.isPeriodic) {
1612 b.setPeriodic(syncOperation.periodMillis, syncOperation.flexMillis);
1613 } else {
1614 if (minDelay > 0) {
1615 b.setMinimumLatency(minDelay);
1616 }
1617 getSyncStorageEngine().markPending(syncOperation.target, true);
1618 }
1619
1620 if (syncOperation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)) {
1621 b.setRequiresCharging(true);
1622 }
1623
Makoto Onuki75ad2492018-03-28 14:42:42 -07001624 if (syncOperation.syncExemptionFlag
Makoto Onukid5f25d22018-05-22 16:02:17 -07001625 == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001626 DeviceIdleController.LocalService dic =
1627 LocalServices.getService(DeviceIdleController.LocalService.class);
1628 if (dic != null) {
1629 dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID,
1630 syncOperation.owningPackage,
1631 mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
1632 UserHandle.getUserId(syncOperation.owningUid),
1633 /* sync=*/ false, "sync by top app");
1634 }
1635 }
1636
Makoto Onukid5f25d22018-05-22 16:02:17 -07001637 if (syncOperation.isAppStandbyExempted()) {
1638 final UsageStatsManagerInternal usmi = LocalServices.getService(
1639 UsageStatsManagerInternal.class);
1640 if (usmi != null) {
1641 usmi.reportExemptedSyncScheduled(syncOperation.owningPackage,
1642 UserHandle.getUserId(syncOperation.owningUid));
1643 }
1644 }
1645
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001646 getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
Shreyas Basargeeda34e42016-04-26 00:14:02 +01001647 syncOperation.target.userId, syncOperation.wakeLockName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 }
1649
1650 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07001651 * Remove scheduled sync operations.
Matthew Williams8ef22042013-07-26 12:56:39 -07001652 * @param info limit the removals to operations that match this target. The target can
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001653 * have null account/provider info to specify all accounts/providers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 */
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001655 public void clearScheduledSyncOperations(SyncStorageEngine.EndPoint info) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001656 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001657 for (SyncOperation op: ops) {
1658 if (!op.isPeriodic && op.target.matchesSpec(info)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001659 cancelJob(op, "clearScheduledSyncOperations");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001660 getSyncStorageEngine().markPending(op.target, false);
1661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001663 mSyncStorageEngine.setBackoff(info,
Fred Quintana918339a2010-10-05 14:00:39 -07001664 SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 }
1666
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001667 /**
1668 * Remove a specified sync, if it exists.
1669 * @param info Authority for which the sync is to be removed.
1670 * @param extras extras bundle to uniquely identify sync.
1671 */
1672 public void cancelScheduledSyncOperation(SyncStorageEngine.EndPoint info, Bundle extras) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001673 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001674 for (SyncOperation op: ops) {
1675 if (!op.isPeriodic && op.target.matchesSpec(info)
1676 && syncExtrasEquals(extras, op.extras, false)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001677 cancelJob(op, "cancelScheduledSyncOperation");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001678 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001679 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001680 setAuthorityPendingState(info);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001681 // Reset the back-off if there are no more syncs pending.
1682 if (!mSyncStorageEngine.isSyncPending(info)) {
1683 mSyncStorageEngine.setBackoff(info,
1684 SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
1685 }
1686 }
1687
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001688 private void maybeRescheduleSync(SyncResult syncResult, SyncOperation operation) {
1689 final boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 if (isLoggable) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001691 Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 }
1693
Fred Quintana53bd2522010-02-05 15:28:12 -08001694 // The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
1695 // request. Retries of the request will always honor the backoff, so clear the
1696 // flag in case we retry this request.
1697 if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
1698 operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
1699 }
1700
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01001701 if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
1702 && !syncResult.syncAlreadyInProgress) {
1703 // syncAlreadyInProgress flag is set by AbstractThreadedSyncAdapter. The sync adapter
1704 // has no way of knowing that a sync error occured. So we DO retry if the error is
1705 // syncAlreadyInProgress.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001706 if (isLoggable) {
1707 Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
1708 + operation);
1709 }
Fred Quintana918339a2010-10-05 14:00:39 -07001710 } else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)
1711 && !syncResult.syncAlreadyInProgress) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001712 // If this was an upward sync then schedule a two-way sync immediately.
Fred Quintana53bd2522010-02-05 15:28:12 -08001713 operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001714 if (isLoggable) {
1715 Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
1716 + "encountered an error: " + operation);
1717 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001718 scheduleSyncOperationH(operation);
Fred Quintana307da1a2010-01-21 14:24:20 -08001719 } else if (syncResult.tooManyRetries) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001720 // If this sync aborted because the internal sync loop retried too many times then
1721 // don't reschedule. Otherwise we risk getting into a retry loop.
1722 if (isLoggable) {
1723 Log.d(TAG, "not retrying sync operation because it retried too many times: "
1724 + operation);
1725 }
Fred Quintanaaa7edda2009-12-03 14:18:58 -08001726 } else if (syncResult.madeSomeProgress()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001727 // If the operation succeeded to some extent then retry immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 if (isLoggable) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001729 Log.d(TAG, "retrying sync operation because even though it had an error "
1730 + "it achieved some success");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001732 scheduleSyncOperationH(operation);
Fred Quintana8570f742010-02-18 10:32:54 -08001733 } else if (syncResult.syncAlreadyInProgress) {
1734 if (isLoggable) {
1735 Log.d(TAG, "retrying sync operation that failed because there was already a "
1736 + "sync in progress: " + operation);
1737 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001738 scheduleSyncOperationH(operation, DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 } else if (syncResult.hasSoftError()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001740 // If this was a two-way sync then retry soft errors with an exponential backoff.
Fred Quintana307da1a2010-01-21 14:24:20 -08001741 if (isLoggable) {
1742 Log.d(TAG, "retrying sync operation because it encountered a soft error: "
1743 + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001745 scheduleSyncOperationH(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 } else {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001747 // Otherwise do not reschedule.
Fred Quintana307da1a2010-01-21 14:24:20 -08001748 Log.d(TAG, "not retrying sync operation because the error is a hard error: "
1749 + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 }
1751 }
1752
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07001753 private void onUserUnlocked(int userId) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001754 // Make sure that accounts we're about to use are valid.
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001755 AccountManagerService.getSingleton().validateAccounts(userId);
1756
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001757 mSyncAdapters.invalidateCache(userId);
1758
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001759 EndPoint target = new EndPoint(null, null, userId);
1760 updateRunningAccounts(target);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001761
Makoto Onuki61283ec2018-01-31 17:22:36 -08001762 // Schedule sync for any accounts under started user, but only the NOT_INITIALIZED adapters.
Svetoslavf3f02ac2015-09-08 14:36:35 -07001763 final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId,
1764 mContext.getOpPackageName());
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001765 for (Account account : accounts) {
Alon Albert57286f92012-10-09 14:21:38 -07001766 scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
Makoto Onukie183a402018-08-29 11:46:41 -07001767 AuthorityInfo.NOT_INITIALIZED, ContentResolver.SYNC_EXEMPTION_NONE,
1768 Process.myUid(), -3, null);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001769 }
Alon Albert8e285552012-09-17 15:05:27 -07001770 }
Amith Yamasani13593602012-03-22 16:16:17 -07001771
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -07001772 private void onUserStopped(int userId) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001773 updateRunningAccounts(null /* Don't sync any target */);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001774
1775 cancelActiveSync(
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001776 new SyncStorageEngine.EndPoint(
1777 null /* any account */,
1778 null /* any authority */,
1779 userId),
Makoto Onukia9dca242017-06-21 17:06:49 -07001780 null /* any sync. */,
1781 "onUserStopped"
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001782 );
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001783 }
1784
1785 private void onUserRemoved(int userId) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001786 mLogger.log("onUserRemoved: u", userId);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001787 updateRunningAccounts(null /* Don't sync any target */);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001788
Amith Yamasani13593602012-03-22 16:16:17 -07001789 // Clean up the storage engine database
Makoto Onuki3ab77812018-07-09 14:29:33 -07001790 mSyncStorageEngine.removeStaleAccounts(null, userId);
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001791 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001792 for (SyncOperation op: ops) {
1793 if (op.target.userId == userId) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001794 cancelJob(op, "user removed u" + userId);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001795 }
1796 }
1797 }
1798
Amith Yamasani96a0fd652015-04-10 16:16:30 -07001799 /**
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001800 * Construct intent used to bind to an adapter.
1801 *
1802 * @param context Context to create intent for
1803 * @param syncAdapterComponent The adapter description
1804 * @param userId The user the adapter belongs to
1805 *
1806 * @return The intent required to bind to the adapter
1807 */
1808 static @NonNull Intent getAdapterBindIntent(@NonNull Context context,
1809 @NonNull ComponentName syncAdapterComponent, @UserIdInt int userId) {
1810 final Intent intent = new Intent();
1811 intent.setAction("android.content.SyncAdapter");
1812 intent.setComponent(syncAdapterComponent);
1813 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1814 com.android.internal.R.string.sync_binding_label);
1815 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0,
1816 new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId)));
1817
1818 return intent;
1819 }
1820
1821 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 * @hide
1823 */
Alon Alberteca75112010-12-08 15:02:33 -08001824 class ActiveSyncContext extends ISyncContext.Stub
1825 implements ServiceConnection, IBinder.DeathRecipient {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 final SyncOperation mSyncOperation;
1827 final long mHistoryRowId;
Fred Quintana718d8a22009-04-29 17:53:20 -07001828 ISyncAdapter mSyncAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 final long mStartTime;
1830 long mTimeoutStartTime;
Fred Quintana3ec47302010-03-10 10:08:31 -08001831 boolean mBound;
Fred Quintana918339a2010-10-05 14:00:39 -07001832 final PowerManager.WakeLock mSyncWakeLock;
1833 final int mSyncAdapterUid;
1834 SyncInfo mSyncInfo;
Alon Alberteca75112010-12-08 15:02:33 -08001835 boolean mIsLinkedToDeath = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001836 String mEventName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837
Matthew Williams1967c8d2015-06-19 19:03:13 -07001838 /** Total bytes transferred, counted at {@link #mLastPolledTimeElapsed} */
1839 long mBytesTransferredAtLastPoll;
1840 /**
1841 * Last point in {@link SystemClock#elapsedRealtime()} at which we checked the # of bytes
1842 * transferred to/fro by this adapter.
1843 */
1844 long mLastPolledTimeElapsed;
1845
Fred Quintana918339a2010-10-05 14:00:39 -07001846 /**
1847 * Create an ActiveSyncContext for an impending sync and grab the wakelock for that
1848 * sync adapter. Since this grabs the wakelock you need to be sure to call
1849 * close() when you are done with this ActiveSyncContext, whether the sync succeeded
1850 * or not.
1851 * @param syncOperation the SyncOperation we are about to sync
1852 * @param historyRowId the row in which to record the history info for this sync
1853 * @param syncAdapterUid the UID of the application that contains the sync adapter
1854 * for this sync. This is used to attribute the wakelock hold to that application.
1855 */
1856 public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001857 int syncAdapterUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 super();
Fred Quintana918339a2010-10-05 14:00:39 -07001859 mSyncAdapterUid = syncAdapterUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 mSyncOperation = syncOperation;
1861 mHistoryRowId = historyRowId;
Fred Quintana718d8a22009-04-29 17:53:20 -07001862 mSyncAdapter = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 mStartTime = SystemClock.elapsedRealtime();
1864 mTimeoutStartTime = mStartTime;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001865 mSyncWakeLock = mSyncHandler.getSyncWakeLock(mSyncOperation);
Fred Quintana918339a2010-10-05 14:00:39 -07001866 mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
1867 mSyncWakeLock.acquire();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 }
1869
1870 public void sendHeartbeat() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001871 // Heartbeats are no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 }
1873
1874 public void onFinished(SyncResult result) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001875 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "onFinished: " + this);
1876 // Include "this" in the message so that the handler can ignore it if this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 // ActiveSyncContext is no longer the mActiveSyncContext at message handling
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001878 // time.
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001879 mLogger.log("onFinished result=", result, " endpoint=",
1880 (mSyncOperation == null ? "null" : mSyncOperation.target));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 sendSyncFinishedOrCanceledMessage(this, result);
1882 }
1883
1884 public void toString(StringBuilder sb) {
1885 sb.append("startTime ").append(mStartTime)
1886 .append(", mTimeoutStartTime ").append(mTimeoutStartTime)
1887 .append(", mHistoryRowId ").append(mHistoryRowId)
1888 .append(", syncOperation ").append(mSyncOperation);
1889 }
1890
Fred Quintana718d8a22009-04-29 17:53:20 -07001891 public void onServiceConnected(ComponentName name, IBinder service) {
1892 Message msg = mSyncHandler.obtainMessage();
1893 msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001894 msg.obj = new ServiceConnectionData(this, service);
Fred Quintana718d8a22009-04-29 17:53:20 -07001895 mSyncHandler.sendMessage(msg);
1896 }
1897
1898 public void onServiceDisconnected(ComponentName name) {
1899 Message msg = mSyncHandler.obtainMessage();
1900 msg.what = SyncHandler.MESSAGE_SERVICE_DISCONNECTED;
1901 msg.obj = new ServiceConnectionData(this, null);
1902 mSyncHandler.sendMessage(msg);
1903 }
1904
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001905 boolean bindToSyncAdapter(ComponentName serviceComponent, int userId) {
Fred Quintana718d8a22009-04-29 17:53:20 -07001906 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001907 Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
Fred Quintana718d8a22009-04-29 17:53:20 -07001908 }
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001909 Intent intent = getAdapterBindIntent(mContext, serviceComponent, userId);
1910
Fred Quintana3ec47302010-03-10 10:08:31 -08001911 mBound = true;
Amith Yamasani27b89e62013-01-16 12:30:11 -08001912 final boolean bindResult = mContext.bindServiceAsUser(intent, this,
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001913 SYNC_ADAPTER_CONNECTION_FLAGS, new UserHandle(mSyncOperation.target.userId));
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001914 mLogger.log("bindService() returned=", mBound, " for ", this);
Fred Quintana3ec47302010-03-10 10:08:31 -08001915 if (!bindResult) {
1916 mBound = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001917 } else {
1918 try {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08001919 mEventName = mSyncOperation.wakeLockName();
Dianne Hackbornfdb19562014-07-11 16:03:36 -07001920 mBatteryStats.noteSyncStart(mEventName, mSyncAdapterUid);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001921 } catch (RemoteException e) {
1922 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001923 }
1924 return bindResult;
Fred Quintana718d8a22009-04-29 17:53:20 -07001925 }
1926
Fred Quintana918339a2010-10-05 14:00:39 -07001927 /**
1928 * Performs the required cleanup, which is the releasing of the wakelock and
1929 * unbinding from the sync adapter (if actually bound).
1930 */
Fred Quintana3ec47302010-03-10 10:08:31 -08001931 protected void close() {
Fred Quintana718d8a22009-04-29 17:53:20 -07001932 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1933 Log.d(TAG, "unBindFromSyncAdapter: connection " + this);
1934 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001935 if (mBound) {
1936 mBound = false;
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001937 mLogger.log("unbindService for ", this);
Fred Quintana3ec47302010-03-10 10:08:31 -08001938 mContext.unbindService(this);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001939 try {
Dianne Hackbornfdb19562014-07-11 16:03:36 -07001940 mBatteryStats.noteSyncFinish(mEventName, mSyncAdapterUid);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001941 } catch (RemoteException e) {
1942 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001943 }
Fred Quintana918339a2010-10-05 14:00:39 -07001944 mSyncWakeLock.release();
Dianne Hackbornc24ab862011-10-18 15:55:03 -07001945 mSyncWakeLock.setWorkSource(null);
Fred Quintana718d8a22009-04-29 17:53:20 -07001946 }
1947
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001948 public String toString() {
1949 StringBuilder sb = new StringBuilder();
1950 toString(sb);
1951 return sb.toString();
1952 }
Alon Alberteca75112010-12-08 15:02:33 -08001953
1954 @Override
1955 public void binderDied() {
1956 sendSyncFinishedOrCanceledMessage(this, null);
1957 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 }
1959
Makoto Onukia9dca242017-06-21 17:06:49 -07001960 protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001961 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
Makoto Onuki75ad2492018-03-28 14:42:42 -07001962
1963 final SyncAdapterStateFetcher buckets = new SyncAdapterStateFetcher();
1964
1965 dumpSyncState(ipw, buckets);
Makoto Onukiaad2b512018-02-07 09:31:46 -08001966 mConstants.dump(pw, "");
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001967 dumpSyncAdapters(ipw);
Makoto Onukia9dca242017-06-21 17:06:49 -07001968
1969 if (dumpAll) {
1970 ipw.println("Detailed Sync History");
1971 mLogger.dumpAll(pw);
1972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001973 }
1974
Dianne Hackborn231cc602009-04-27 17:10:36 -07001975 static String formatTime(long time) {
Makoto Onukif74cf942018-04-16 17:04:58 -07001976 if (time == 0) {
1977 return "N/A";
1978 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001979 Time tobj = new Time();
1980 tobj.set(time);
1981 return tobj.format("%Y-%m-%d %H:%M:%S");
1982 }
Doug Zongker44f57472009-09-20 15:52:43 -07001983
Makoto Onuki15e7a252017-06-08 17:12:05 -07001984 private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
1985 int res = Integer.compare(op1.target.userId, op2.target.userId);
1986 if (res != 0) return res;
1987
1988 final Comparator<String> stringComparator = String.CASE_INSENSITIVE_ORDER;
1989
1990 res = stringComparator.compare(op1.target.account.type, op2.target.account.type);
1991 if (res != 0) return res;
1992
1993 res = stringComparator.compare(op1.target.account.name, op2.target.account.name);
1994 if (res != 0) return res;
1995
1996 res = stringComparator.compare(op1.target.provider, op2.target.provider);
1997 if (res != 0) return res;
1998
1999 res = Integer.compare(op1.reason, op2.reason);
2000 if (res != 0) return res;
2001
2002 res = Long.compare(op1.periodMillis, op2.periodMillis);
2003 if (res != 0) return res;
2004
2005 res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
2006 if (res != 0) return res;
2007
2008 res = Long.compare(op1.jobId, op2.jobId);
2009 if (res != 0) return res;
2010
2011 return 0;
2012 };
2013
2014 private final static Comparator<SyncOperation> sOpRuntimeComparator = (op1, op2) -> {
2015 int res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
2016 if (res != 0) return res;
2017
2018 return sOpDumpComparator.compare(op1, op2);
2019 };
2020
2021 private static <T> int countIf(Collection<T> col, Predicate<T> p) {
2022 int ret = 0;
2023 for (T item : col) {
2024 if (p.test(item)) ret++;
2025 }
2026 return ret;
2027 }
2028
Makoto Onuki75ad2492018-03-28 14:42:42 -07002029 protected void dumpPendingSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00002030 List<SyncOperation> pendingSyncs = getAllPendingSyncs();
Makoto Onuki15e7a252017-06-08 17:12:05 -07002031
2032 pw.print("Pending Syncs: ");
2033 pw.println(countIf(pendingSyncs, op -> !op.isPeriodic));
2034
2035 Collections.sort(pendingSyncs, sOpRuntimeComparator);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002036 int count = 0;
2037 for (SyncOperation op: pendingSyncs) {
2038 if (!op.isPeriodic) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07002039 pw.println(op.dump(null, false, buckets));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002040 count++;
2041 }
2042 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002043 pw.println();
2044 }
2045
Makoto Onuki75ad2492018-03-28 14:42:42 -07002046 protected void dumpPeriodicSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00002047 List<SyncOperation> pendingSyncs = getAllPendingSyncs();
Makoto Onuki15e7a252017-06-08 17:12:05 -07002048
2049 pw.print("Periodic Syncs: ");
2050 pw.println(countIf(pendingSyncs, op -> op.isPeriodic));
2051
2052 Collections.sort(pendingSyncs, sOpDumpComparator);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002053 int count = 0;
2054 for (SyncOperation op: pendingSyncs) {
2055 if (op.isPeriodic) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07002056 pw.println(op.dump(null, false, buckets));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002057 count++;
2058 }
2059 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002060 pw.println();
2061 }
2062
Makoto Onuki15e7a252017-06-08 17:12:05 -07002063 /**
2064 * Similar to {@link android.util.TimeUtils#formatDuration}, but it's more suitable and concise
2065 * for the sync manager dumpsys. (Don't add the leading + sign, don't show milliseconds.)
2066 */
2067 public static StringBuilder formatDurationHMS(StringBuilder sb, long duration) {
2068 duration /= 1000;
2069 if (duration < 0) {
2070 sb.append('-');
2071 duration = -duration;
2072 }
2073 final long seconds = duration % 60;
2074 duration /= 60;
2075
2076 final long minutes = duration % 60;
2077 duration /= 60;
2078
2079 final long hours = duration % 24;
2080 duration /= 24;
2081
2082 final long days = duration;
2083
2084 boolean print = false;
2085 if (days > 0) {
2086 sb.append(days);
2087 sb.append('d');
2088 print = true;
2089 }
2090 print = printTwoDigitNumber(sb, hours, 'h', print);
2091 print = printTwoDigitNumber(sb, minutes, 'm', print);
2092 print = printTwoDigitNumber(sb, seconds, 's', print);
2093 if (!print) {
2094 sb.append("0s");
2095 }
2096
2097 return sb;
2098 }
2099
2100 private static boolean printTwoDigitNumber(StringBuilder sb, long value, char unit,
2101 boolean always) {
2102 if (!always && (value == 0)) {
2103 return false;
2104 }
2105 if (always && (value < 10)) {
2106 sb.append('0');
2107 }
2108 sb.append(value);
2109 sb.append(unit);
2110 return true;
2111 }
2112
Makoto Onuki75ad2492018-03-28 14:42:42 -07002113 protected void dumpSyncState(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07002114 final StringBuilder sb = new StringBuilder();
2115
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002116 pw.print("Data connected: "); pw.println(mDataConnectionIsConnected);
2117 pw.print("Battery saver: ");
2118 pw.println((mPowerManager != null) && mPowerManager.isPowerSaveMode());
2119
2120 pw.print("Background network restriction: ");
2121 {
2122 final ConnectivityManager cm = getConnectivityManager();
2123 final int status = (cm == null) ? -1 : cm.getRestrictBackgroundStatus();
2124 switch (status) {
2125 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
2126 pw.println(" disabled");
2127 break;
2128 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
2129 pw.println(" whitelisted");
2130 break;
2131 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
2132 pw.println(" enabled");
2133 break;
2134 default:
2135 pw.print("Unknown(");
2136 pw.print(status);
2137 pw.println(")");
2138 break;
2139 }
2140 }
2141
2142 pw.print("Auto sync: ");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002143 List<UserInfo> users = getAllUsers();
2144 if (users != null) {
2145 for (UserInfo user : users) {
2146 pw.print("u" + user.id + "="
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002147 + mSyncStorageEngine.getMasterSyncAutomatically(user.id) + " ");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002148 }
2149 pw.println();
2150 }
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002151 pw.print("Memory low: "); pw.println(mStorageIsLow);
2152 pw.print("Device idle: "); pw.println(mDeviceIsIdle);
2153 pw.print("Reported active: "); pw.println(mReportedSyncActive);
Makoto Onuki94986212018-04-11 16:24:46 -07002154 pw.print("Clock valid: "); pw.println(mSyncStorageEngine.isClockValid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155
Jeff Sharkey6eb96202012-10-10 13:13:54 -07002156 final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002157
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002158 pw.print("Accounts: ");
Fred Quintana53bd2522010-02-05 15:28:12 -08002159 if (accounts != INITIAL_ACCOUNTS_ARRAY) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07002160 pw.println(accounts.length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 } else {
Fred Quintana53bd2522010-02-05 15:28:12 -08002162 pw.println("not known yet");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 final long now = SystemClock.elapsedRealtime();
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002165 pw.print("Now: "); pw.print(now);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002166 pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002167
2168 sb.setLength(0);
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002169 pw.print("Uptime: "); pw.print(formatDurationHMS(sb, now));
Makoto Onuki15e7a252017-06-08 17:12:05 -07002170 pw.println();
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002171 pw.print("Time spent syncing: ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002172
2173 sb.setLength(0);
2174 pw.print(formatDurationHMS(sb,
2175 mSyncHandler.mSyncTimeTracker.timeSpentSyncing()));
2176 pw.print(", sync ");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002177 pw.print(mSyncHandler.mSyncTimeTracker.mLastWasSyncing ? "" : "not ");
2178 pw.println("in progress");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179
Fred Quintana918339a2010-10-05 14:00:39 -07002180 pw.println();
2181 pw.println("Active Syncs: " + mActiveSyncContexts.size());
Alon Albert57286f92012-10-09 14:21:38 -07002182 final PackageManager pm = mContext.getPackageManager();
Fred Quintana918339a2010-10-05 14:00:39 -07002183 for (SyncManager.ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07002184 final long durationInSeconds = (now - activeSyncContext.mStartTime);
Fred Quintana918339a2010-10-05 14:00:39 -07002185 pw.print(" ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002186 sb.setLength(0);
2187 pw.print(formatDurationHMS(sb, durationInSeconds));
Fred Quintana918339a2010-10-05 14:00:39 -07002188 pw.print(" - ");
Makoto Onuki75ad2492018-03-28 14:42:42 -07002189 pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets));
Fred Quintana918339a2010-10-05 14:00:39 -07002190 pw.println();
2191 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002192 pw.println();
2193
Makoto Onuki75ad2492018-03-28 14:42:42 -07002194 dumpPendingSyncs(pw, buckets);
2195 dumpPeriodicSyncs(pw, buckets);
Fred Quintana918339a2010-10-05 14:00:39 -07002196
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002197 // Join the installed sync adapter with the accounts list and emit for everything.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002198 pw.println("Sync Status");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002199
2200 final ArrayList<Pair<EndPoint, SyncStatusInfo>> statuses = new ArrayList<>();
2201
Makoto Onuki94986212018-04-11 16:24:46 -07002202 mSyncStorageEngine.resetTodayStats(/* force=*/ false);
2203
Amith Yamasani04e0d262012-02-14 11:50:53 -08002204 for (AccountAndUser account : accounts) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002205 final boolean unlocked;
2206 synchronized (mUnlockedUsers) {
2207 unlocked = mUnlockedUsers.get(account.userId);
2208 }
2209 pw.printf("Account %s u%d %s%s\n",
2210 account.account.name, account.userId, account.account.type,
2211 (unlocked ? "" : " (locked)"));
Alon Albert57286f92012-10-09 14:21:38 -07002212
2213 pw.println("=======================================================================");
Makoto Onuki94986212018-04-11 16:24:46 -07002214 final PrintTable table = new PrintTable(16);
Alon Albert57286f92012-10-09 14:21:38 -07002215 table.set(0, 0,
2216 "Authority", // 0
2217 "Syncable", // 1
2218 "Enabled", // 2
Makoto Onuki94986212018-04-11 16:24:46 -07002219
2220 "Stats", // 3 "Total", "Today" or "Yesterday".
2221
2222 "Loc", // 4 # of syncs with local sources. (including failures/cancels. )
2223 "Poll", // 5 "poll" syncs.
2224 "Per", // 6 Periodic syncs.
2225 "Feed", // 7 Syncs with a "feed" extra. (subscribedfeeds?)
2226 "User", // 8 User-initiated
2227 "Othr", // 9 Other sources.
2228
2229 "Tot", // 10 Total syncs (including failures / cancels)
2230 "Fail", // 11 (Failure)
2231 "Can", // 12 (Cancel)
2232
2233 "Time", // 13 Total time
2234 "Last Sync", // 14
2235 "Backoff" // 15
Alon Albert57286f92012-10-09 14:21:38 -07002236 );
2237
2238 final List<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> sorted =
2239 Lists.newArrayList();
2240 sorted.addAll(mSyncAdapters.getAllServices(account.userId));
2241 Collections.sort(sorted,
2242 new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002243 @Override
2244 public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00002245 RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002246 return lhs.type.authority.compareTo(rhs.type.authority);
2247 }
2248 });
Alon Albert57286f92012-10-09 14:21:38 -07002249 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType : sorted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002250 if (!syncAdapterType.type.accountType.equals(account.account.type)) {
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002251 continue;
2252 }
Alon Albert57286f92012-10-09 14:21:38 -07002253 int row = table.getNumRows();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002254 Pair<AuthorityInfo, SyncStatusInfo> syncAuthoritySyncStatus =
Georgi Nikolovdbe846b2013-06-25 14:09:56 -07002255 mSyncStorageEngine.getCopyOfAuthorityWithSyncStatus(
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002256 new SyncStorageEngine.EndPoint(
2257 account.account,
2258 syncAdapterType.type.authority,
2259 account.userId));
Georgi Nikolovdbe846b2013-06-25 14:09:56 -07002260 SyncStorageEngine.AuthorityInfo settings = syncAuthoritySyncStatus.first;
2261 SyncStatusInfo status = syncAuthoritySyncStatus.second;
Makoto Onuki15e7a252017-06-08 17:12:05 -07002262 statuses.add(Pair.create(settings.target, status));
Matthew Williams8ef22042013-07-26 12:56:39 -07002263 String authority = settings.target.provider;
Alon Albert57286f92012-10-09 14:21:38 -07002264 if (authority.length() > 50) {
2265 authority = authority.substring(authority.length() - 50);
2266 }
2267 table.set(row, 0, authority, settings.syncable, settings.enabled);
Makoto Onuki15e7a252017-06-08 17:12:05 -07002268
Makoto Onuki94986212018-04-11 16:24:46 -07002269 QuadConsumer<String, Stats, Function<Integer, String>, Integer> c =
2270 (label, stats, filter, r) -> {
2271 sb.setLength(0);
2272 table.set(r, 3,
2273 label,
2274 filter.apply(stats.numSourceLocal),
2275 filter.apply(stats.numSourcePoll),
2276 filter.apply(stats.numSourcePeriodic),
2277 filter.apply(stats.numSourceFeed),
2278 filter.apply(stats.numSourceUser),
2279 filter.apply(stats.numSourceOther),
2280 filter.apply(stats.numSyncs),
2281 filter.apply(stats.numFailures),
2282 filter.apply(stats.numCancels),
2283 formatDurationHMS(sb, stats.totalElapsedTime));
2284 };
2285 c.accept("Total", status.totalStats, (i) -> Integer.toString(i), row);
2286 c.accept("Today", status.todayStats, this::zeroToEmpty, row + 1);
2287 c.accept("Yestr", status.yesterdayStats, this::zeroToEmpty, row + 2);
2288
2289 final int LAST_SYNC = 14;
2290 final int BACKOFF = LAST_SYNC + 1;
Alon Albert57286f92012-10-09 14:21:38 -07002291
Alon Albert57286f92012-10-09 14:21:38 -07002292 int row1 = row;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002293 if (settings.delayUntil > now) {
Makoto Onuki94986212018-04-11 16:24:46 -07002294 table.set(row1++, BACKOFF, "D: " + (settings.delayUntil - now) / 1000);
Alon Albert57286f92012-10-09 14:21:38 -07002295 if (settings.backoffTime > now) {
Makoto Onuki94986212018-04-11 16:24:46 -07002296 table.set(row1++, BACKOFF, "B: " + (settings.backoffTime - now) / 1000);
2297 table.set(row1++, BACKOFF, settings.backoffDelay / 1000);
Alon Albert57286f92012-10-09 14:21:38 -07002298 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002299 }
Alon Albert57286f92012-10-09 14:21:38 -07002300
Makoto Onuki010291d2017-06-06 16:32:47 -07002301 row1 = row;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002302 if (status.lastSuccessTime != 0) {
Makoto Onuki94986212018-04-11 16:24:46 -07002303 table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastSuccessSource]
Alon Albert57286f92012-10-09 14:21:38 -07002304 + " " + "SUCCESS");
Makoto Onuki94986212018-04-11 16:24:46 -07002305 table.set(row1++, LAST_SYNC, formatTime(status.lastSuccessTime));
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002306 }
2307 if (status.lastFailureTime != 0) {
Makoto Onuki94986212018-04-11 16:24:46 -07002308 table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastFailureSource]
Alon Albert57286f92012-10-09 14:21:38 -07002309 + " " + "FAILURE");
Makoto Onuki94986212018-04-11 16:24:46 -07002310 table.set(row1++, LAST_SYNC, formatTime(status.lastFailureTime));
Alon Albert57286f92012-10-09 14:21:38 -07002311 //noinspection UnusedAssignment
Makoto Onuki94986212018-04-11 16:24:46 -07002312 table.set(row1++, LAST_SYNC, status.lastFailureMesg);
Dianne Hackborn231cc602009-04-27 17:10:36 -07002313 }
2314 }
Alon Albert57286f92012-10-09 14:21:38 -07002315 table.writeTo(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002316 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002317
2318 dumpSyncHistory(pw);
2319
2320 pw.println();
2321 pw.println("Per Adapter History");
Makoto Onuki94986212018-04-11 16:24:46 -07002322 pw.println("(SERVER is now split up to FEED and OTHER)");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002323
2324 for (int i = 0; i < statuses.size(); i++) {
2325 final Pair<EndPoint, SyncStatusInfo> event = statuses.get(i);
2326
2327 pw.print(" ");
2328 pw.print(event.first.account.name);
2329 pw.print('/');
2330 pw.print(event.first.account.type);
2331 pw.print(" u");
2332 pw.print(event.first.userId);
2333 pw.print(" [");
2334 pw.print(event.first.provider);
2335 pw.print("]");
2336 pw.println();
2337
Makoto Onukif74cf942018-04-16 17:04:58 -07002338 pw.println(" Per source last syncs:");
2339 for (int j = 0; j < SyncStorageEngine.SOURCES.length; j++) {
2340 pw.print(" ");
2341 pw.print(String.format("%8s", SyncStorageEngine.SOURCES[j]));
2342 pw.print(" Success: ");
2343 pw.print(formatTime(event.second.perSourceLastSuccessTimes[j]));
2344
2345 pw.print(" Failure: ");
2346 pw.println(formatTime(event.second.perSourceLastFailureTimes[j]));
2347 }
2348
2349 pw.println(" Last syncs:");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002350 for (int j = 0; j < event.second.getEventCount(); j++) {
Makoto Onukif74cf942018-04-16 17:04:58 -07002351 pw.print(" ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002352 pw.print(formatTime(event.second.getEventTime(j)));
2353 pw.print(' ');
2354 pw.print(event.second.getEvent(j));
2355 pw.println();
2356 }
Makoto Onukif74cf942018-04-16 17:04:58 -07002357 if (event.second.getEventCount() == 0) {
2358 pw.println(" N/A");
2359 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 }
2362
Makoto Onuki94986212018-04-11 16:24:46 -07002363 private String zeroToEmpty(int value) {
2364 return (value != 0) ? Integer.toString(value) : "";
2365 }
2366
Dianne Hackborn231cc602009-04-27 17:10:36 -07002367 private void dumpTimeSec(PrintWriter pw, long time) {
2368 pw.print(time/1000); pw.print('.'); pw.print((time/100)%10);
2369 pw.print('s');
2370 }
Doug Zongker44f57472009-09-20 15:52:43 -07002371
Dianne Hackborn231cc602009-04-27 17:10:36 -07002372 private void dumpDayStatistic(PrintWriter pw, SyncStorageEngine.DayStats ds) {
2373 pw.print("Success ("); pw.print(ds.successCount);
2374 if (ds.successCount > 0) {
2375 pw.print(" for "); dumpTimeSec(pw, ds.successTime);
2376 pw.print(" avg="); dumpTimeSec(pw, ds.successTime/ds.successCount);
2377 }
2378 pw.print(") Failure ("); pw.print(ds.failureCount);
2379 if (ds.failureCount > 0) {
2380 pw.print(" for "); dumpTimeSec(pw, ds.failureTime);
2381 pw.print(" avg="); dumpTimeSec(pw, ds.failureTime/ds.failureCount);
2382 }
2383 pw.println(")");
2384 }
Doug Zongker44f57472009-09-20 15:52:43 -07002385
Alon Alberte0bde332011-09-22 14:26:16 -07002386 protected void dumpSyncHistory(PrintWriter pw) {
2387 dumpRecentHistory(pw);
2388 dumpDayStatistics(pw);
2389 }
2390
2391 private void dumpRecentHistory(PrintWriter pw) {
2392 final ArrayList<SyncStorageEngine.SyncHistoryItem> items
2393 = mSyncStorageEngine.getSyncHistory();
2394 if (items != null && items.size() > 0) {
2395 final Map<String, AuthoritySyncStats> authorityMap = Maps.newHashMap();
2396 long totalElapsedTime = 0;
2397 long totalTimes = 0;
2398 final int N = items.size();
2399
2400 int maxAuthority = 0;
2401 int maxAccount = 0;
2402 for (SyncStorageEngine.SyncHistoryItem item : items) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002403 SyncStorageEngine.AuthorityInfo authorityInfo
Alon Alberte0bde332011-09-22 14:26:16 -07002404 = mSyncStorageEngine.getAuthority(item.authorityId);
2405 final String authorityName;
2406 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002407 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002408 authorityName = authorityInfo.target.provider;
2409 accountKey = authorityInfo.target.account.name + "/"
2410 + authorityInfo.target.account.type
2411 + " u" + authorityInfo.target.userId;
Alon Alberte0bde332011-09-22 14:26:16 -07002412 } else {
2413 authorityName = "Unknown";
2414 accountKey = "Unknown";
2415 }
2416
2417 int length = authorityName.length();
2418 if (length > maxAuthority) {
2419 maxAuthority = length;
2420 }
2421 length = accountKey.length();
2422 if (length > maxAccount) {
2423 maxAccount = length;
2424 }
2425
2426 final long elapsedTime = item.elapsedTime;
2427 totalElapsedTime += elapsedTime;
2428 totalTimes++;
2429 AuthoritySyncStats authoritySyncStats = authorityMap.get(authorityName);
2430 if (authoritySyncStats == null) {
2431 authoritySyncStats = new AuthoritySyncStats(authorityName);
2432 authorityMap.put(authorityName, authoritySyncStats);
2433 }
2434 authoritySyncStats.elapsedTime += elapsedTime;
2435 authoritySyncStats.times++;
2436 final Map<String, AccountSyncStats> accountMap = authoritySyncStats.accountMap;
2437 AccountSyncStats accountSyncStats = accountMap.get(accountKey);
2438 if (accountSyncStats == null) {
2439 accountSyncStats = new AccountSyncStats(accountKey);
2440 accountMap.put(accountKey, accountSyncStats);
2441 }
2442 accountSyncStats.elapsedTime += elapsedTime;
2443 accountSyncStats.times++;
2444
2445 }
2446
Alon Albert27096822012-01-11 18:06:41 -08002447 if (totalElapsedTime > 0) {
2448 pw.println();
2449 pw.printf("Detailed Statistics (Recent history): "
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002450 + "%d (# of times) %ds (sync time)\n",
Alon Albert27096822012-01-11 18:06:41 -08002451 totalTimes, totalElapsedTime / 1000);
Alon Alberte0bde332011-09-22 14:26:16 -07002452
Alon Albert27096822012-01-11 18:06:41 -08002453 final List<AuthoritySyncStats> sortedAuthorities =
2454 new ArrayList<AuthoritySyncStats>(authorityMap.values());
2455 Collections.sort(sortedAuthorities, new Comparator<AuthoritySyncStats>() {
Alon Albertbf976ba2011-10-03 13:06:43 -07002456 @Override
Alon Albert27096822012-01-11 18:06:41 -08002457 public int compare(AuthoritySyncStats lhs, AuthoritySyncStats rhs) {
Alon Albertbf976ba2011-10-03 13:06:43 -07002458 // reverse order
2459 int compare = Integer.compare(rhs.times, lhs.times);
2460 if (compare == 0) {
2461 compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
Alon Alberte0bde332011-09-22 14:26:16 -07002462 }
Alon Albertbf976ba2011-10-03 13:06:43 -07002463 return compare;
Alon Alberte0bde332011-09-22 14:26:16 -07002464 }
Alon Albertbf976ba2011-10-03 13:06:43 -07002465 });
Alon Albert27096822012-01-11 18:06:41 -08002466
2467 final int maxLength = Math.max(maxAuthority, maxAccount + 3);
2468 final int padLength = 2 + 2 + maxLength + 2 + 10 + 11;
2469 final char chars[] = new char[padLength];
2470 Arrays.fill(chars, '-');
2471 final String separator = new String(chars);
2472
2473 final String authorityFormat =
2474 String.format(" %%-%ds: %%-9s %%-11s\n", maxLength + 2);
2475 final String accountFormat =
2476 String.format(" %%-%ds: %%-9s %%-11s\n", maxLength);
2477
2478 pw.println(separator);
2479 for (AuthoritySyncStats authoritySyncStats : sortedAuthorities) {
2480 String name = authoritySyncStats.name;
2481 long elapsedTime;
2482 int times;
2483 String timeStr;
2484 String timesStr;
2485
2486 elapsedTime = authoritySyncStats.elapsedTime;
2487 times = authoritySyncStats.times;
Alon Albertbf976ba2011-10-03 13:06:43 -07002488 timeStr = String.format("%ds/%d%%",
2489 elapsedTime / 1000,
2490 elapsedTime * 100 / totalElapsedTime);
2491 timesStr = String.format("%d/%d%%",
2492 times,
2493 times * 100 / totalTimes);
Alon Albert27096822012-01-11 18:06:41 -08002494 pw.printf(authorityFormat, name, timesStr, timeStr);
2495
2496 final List<AccountSyncStats> sortedAccounts =
2497 new ArrayList<AccountSyncStats>(
2498 authoritySyncStats.accountMap.values());
2499 Collections.sort(sortedAccounts, new Comparator<AccountSyncStats>() {
2500 @Override
2501 public int compare(AccountSyncStats lhs, AccountSyncStats rhs) {
2502 // reverse order
2503 int compare = Integer.compare(rhs.times, lhs.times);
2504 if (compare == 0) {
2505 compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
2506 }
2507 return compare;
2508 }
2509 });
2510 for (AccountSyncStats stats: sortedAccounts) {
2511 elapsedTime = stats.elapsedTime;
2512 times = stats.times;
2513 timeStr = String.format("%ds/%d%%",
2514 elapsedTime / 1000,
2515 elapsedTime * 100 / totalElapsedTime);
2516 timesStr = String.format("%d/%d%%",
2517 times,
2518 times * 100 / totalTimes);
2519 pw.printf(accountFormat, stats.name, timesStr, timeStr);
2520 }
2521 pw.println(separator);
Alon Alberte0bde332011-09-22 14:26:16 -07002522 }
Alon Alberte0bde332011-09-22 14:26:16 -07002523 }
2524
2525 pw.println();
2526 pw.println("Recent Sync History");
Makoto Onuki94986212018-04-11 16:24:46 -07002527 pw.println("(SERVER is now split up to FEED and OTHER)");
Alon Albert57286f92012-10-09 14:21:38 -07002528 final String format = " %-" + maxAccount + "s %-" + maxAuthority + "s %s\n";
Alon Albertbf976ba2011-10-03 13:06:43 -07002529 final Map<String, Long> lastTimeMap = Maps.newHashMap();
Alon Albert57286f92012-10-09 14:21:38 -07002530 final PackageManager pm = mContext.getPackageManager();
Alon Alberte0bde332011-09-22 14:26:16 -07002531 for (int i = 0; i < N; i++) {
2532 SyncStorageEngine.SyncHistoryItem item = items.get(i);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002533 SyncStorageEngine.AuthorityInfo authorityInfo
Alon Alberte0bde332011-09-22 14:26:16 -07002534 = mSyncStorageEngine.getAuthority(item.authorityId);
2535 final String authorityName;
2536 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002537 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002538 authorityName = authorityInfo.target.provider;
2539 accountKey = authorityInfo.target.account.name + "/"
2540 + authorityInfo.target.account.type
2541 + " u" + authorityInfo.target.userId;
Alon Alberte0bde332011-09-22 14:26:16 -07002542 } else {
2543 authorityName = "Unknown";
2544 accountKey = "Unknown";
2545 }
2546 final long elapsedTime = item.elapsedTime;
2547 final Time time = new Time();
2548 final long eventTime = item.eventTime;
2549 time.set(eventTime);
2550
Alon Albertbf976ba2011-10-03 13:06:43 -07002551 final String key = authorityName + "/" + accountKey;
2552 final Long lastEventTime = lastTimeMap.get(key);
2553 final String diffString;
2554 if (lastEventTime == null) {
2555 diffString = "";
2556 } else {
2557 final long diff = (lastEventTime - eventTime) / 1000;
2558 if (diff < 60) {
2559 diffString = String.valueOf(diff);
2560 } else if (diff < 3600) {
2561 diffString = String.format("%02d:%02d", diff / 60, diff % 60);
2562 } else {
2563 final long sec = diff % 3600;
2564 diffString = String.format("%02d:%02d:%02d",
2565 diff / 3600, sec / 60, sec % 60);
2566 }
2567 }
2568 lastTimeMap.put(key, eventTime);
2569
2570 pw.printf(" #%-3d: %s %8s %5.1fs %8s",
Alon Alberte0bde332011-09-22 14:26:16 -07002571 i + 1,
2572 formatTime(eventTime),
2573 SyncStorageEngine.SOURCES[item.source],
Alon Albertbf976ba2011-10-03 13:06:43 -07002574 ((float) elapsedTime) / 1000,
2575 diffString);
Alon Albert57286f92012-10-09 14:21:38 -07002576 pw.printf(format, accountKey, authorityName,
2577 SyncOperation.reasonToString(pm, item.reason));
Alon Alberte0bde332011-09-22 14:26:16 -07002578
2579 if (item.event != SyncStorageEngine.EVENT_STOP
2580 || item.upstreamActivity != 0
2581 || item.downstreamActivity != 0) {
2582 pw.printf(" event=%d upstreamActivity=%d downstreamActivity=%d\n",
2583 item.event,
2584 item.upstreamActivity,
2585 item.downstreamActivity);
2586 }
2587 if (item.mesg != null
2588 && !SyncStorageEngine.MESG_SUCCESS.equals(item.mesg)) {
2589 pw.printf(" mesg=%s\n", item.mesg);
2590 }
2591 }
Alon Albert57286f92012-10-09 14:21:38 -07002592 pw.println();
2593 pw.println("Recent Sync History Extras");
Makoto Onuki94986212018-04-11 16:24:46 -07002594 pw.println("(SERVER is now split up to FEED and OTHER)");
Alon Albert57286f92012-10-09 14:21:38 -07002595 for (int i = 0; i < N; i++) {
2596 final SyncStorageEngine.SyncHistoryItem item = items.get(i);
2597 final Bundle extras = item.extras;
2598 if (extras == null || extras.size() == 0) {
2599 continue;
2600 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002601 final SyncStorageEngine.AuthorityInfo authorityInfo
Alon Albert57286f92012-10-09 14:21:38 -07002602 = mSyncStorageEngine.getAuthority(item.authorityId);
2603 final String authorityName;
2604 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002605 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002606 authorityName = authorityInfo.target.provider;
2607 accountKey = authorityInfo.target.account.name + "/"
2608 + authorityInfo.target.account.type
2609 + " u" + authorityInfo.target.userId;
Alon Albert57286f92012-10-09 14:21:38 -07002610 } else {
2611 authorityName = "Unknown";
2612 accountKey = "Unknown";
2613 }
2614 final Time time = new Time();
2615 final long eventTime = item.eventTime;
2616 time.set(eventTime);
2617
2618 pw.printf(" #%-3d: %s %8s ",
2619 i + 1,
2620 formatTime(eventTime),
2621 SyncStorageEngine.SOURCES[item.source]);
2622
2623 pw.printf(format, accountKey, authorityName, extras);
2624 }
Alon Alberte0bde332011-09-22 14:26:16 -07002625 }
2626 }
2627
2628 private void dumpDayStatistics(PrintWriter pw) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07002629 SyncStorageEngine.DayStats dses[] = mSyncStorageEngine.getDayStatistics();
2630 if (dses != null && dses[0] != null) {
2631 pw.println();
2632 pw.println("Sync Statistics");
2633 pw.print(" Today: "); dumpDayStatistic(pw, dses[0]);
2634 int today = dses[0].day;
2635 int i;
2636 SyncStorageEngine.DayStats ds;
Doug Zongker44f57472009-09-20 15:52:43 -07002637
Dianne Hackborn231cc602009-04-27 17:10:36 -07002638 // Print each day in the current week.
2639 for (i=1; i<=6 && i < dses.length; i++) {
2640 ds = dses[i];
2641 if (ds == null) break;
2642 int delta = today-ds.day;
2643 if (delta > 6) break;
Doug Zongker44f57472009-09-20 15:52:43 -07002644
Dianne Hackborn231cc602009-04-27 17:10:36 -07002645 pw.print(" Day-"); pw.print(delta); pw.print(": ");
2646 dumpDayStatistic(pw, ds);
2647 }
Doug Zongker44f57472009-09-20 15:52:43 -07002648
Dianne Hackborn231cc602009-04-27 17:10:36 -07002649 // Aggregate all following days into weeks and print totals.
2650 int weekDay = today;
2651 while (i < dses.length) {
2652 SyncStorageEngine.DayStats aggr = null;
2653 weekDay -= 7;
2654 while (i < dses.length) {
2655 ds = dses[i];
2656 if (ds == null) {
2657 i = dses.length;
2658 break;
2659 }
2660 int delta = weekDay-ds.day;
2661 if (delta > 6) break;
2662 i++;
Doug Zongker44f57472009-09-20 15:52:43 -07002663
Dianne Hackborn231cc602009-04-27 17:10:36 -07002664 if (aggr == null) {
2665 aggr = new SyncStorageEngine.DayStats(weekDay);
2666 }
2667 aggr.successCount += ds.successCount;
2668 aggr.successTime += ds.successTime;
2669 aggr.failureCount += ds.failureCount;
2670 aggr.failureTime += ds.failureTime;
2671 }
2672 if (aggr != null) {
2673 pw.print(" Week-"); pw.print((today-weekDay)/7); pw.print(": ");
2674 dumpDayStatistic(pw, aggr);
2675 }
2676 }
2677 }
Alon Alberte0bde332011-09-22 14:26:16 -07002678 }
Doug Zongker44f57472009-09-20 15:52:43 -07002679
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002680 private void dumpSyncAdapters(IndentingPrintWriter pw) {
2681 pw.println();
2682 final List<UserInfo> users = getAllUsers();
2683 if (users != null) {
2684 for (UserInfo user : users) {
2685 pw.println("Sync adapters for " + user + ":");
2686 pw.increaseIndent();
2687 for (RegisteredServicesCache.ServiceInfo<?> info :
2688 mSyncAdapters.getAllServices(user.id)) {
2689 pw.println(info);
2690 }
2691 pw.decreaseIndent();
2692 pw.println();
2693 }
2694 }
2695 }
2696
Alon Alberte0bde332011-09-22 14:26:16 -07002697 private static class AuthoritySyncStats {
2698 String name;
2699 long elapsedTime;
2700 int times;
2701 Map<String, AccountSyncStats> accountMap = Maps.newHashMap();
2702
2703 private AuthoritySyncStats(String name) {
2704 this.name = name;
2705 }
2706 }
2707
2708 private static class AccountSyncStats {
2709 String name;
2710 long elapsedTime;
2711 int times;
2712
2713 private AccountSyncStats(String name) {
2714 this.name = name;
Dianne Hackborn231cc602009-04-27 17:10:36 -07002715 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002716 }
2717
Philip P. Moltmann486b2412018-01-03 11:29:01 -08002718 interface OnReadyCallback {
2719 void onReady();
2720 }
2721
2722 static void sendOnUnsyncableAccount(@NonNull Context context,
2723 @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
2724 @UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) {
2725 OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo,
2726 onReadyCallback);
2727
2728 boolean isBound = context.bindServiceAsUser(
2729 getAdapterBindIntent(context, syncAdapterInfo.componentName, userId),
2730 connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId));
2731
2732 if (isBound) {
2733 // Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection.
2734 (new Handler(Looper.getMainLooper())).postDelayed(
2735 () -> context.unbindService(connection),
2736 OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS);
2737 } else {
2738 /*
2739 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
2740 * there the service cannot be bound, assume the default behavior.
2741 */
2742 connection.onReady();
2743 }
2744 }
2745
2746
2747 /**
2748 * Helper class for calling ISyncAdapter.onUnsyncableAccountDone.
2749 *
2750 * If this returns {@code true} the onReadyCallback is called. Otherwise nothing happens.
2751 */
2752 private static class OnUnsyncableAccountCheck implements ServiceConnection {
2753 static final long SERVICE_BOUND_TIME_MILLIS = 5000;
2754
2755 private final @NonNull OnReadyCallback mOnReadyCallback;
2756 private final @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType>
2757 mSyncAdapterInfo;
2758
2759 OnUnsyncableAccountCheck(
2760 @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
2761 @NonNull OnReadyCallback onReadyCallback) {
2762 mSyncAdapterInfo = syncAdapterInfo;
2763 mOnReadyCallback = onReadyCallback;
2764 }
2765
2766 private void onReady() {
2767 long identity = Binder.clearCallingIdentity();
2768 try {
2769 mOnReadyCallback.onReady();
2770 } finally {
2771 Binder.restoreCallingIdentity(identity);
2772 }
2773 }
2774
2775 @Override
2776 public void onServiceConnected(ComponentName name, IBinder service) {
2777 final ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
2778
2779 try {
2780 adapter.onUnsyncableAccount(new ISyncAdapterUnsyncableAccountCallback.Stub() {
2781 @Override
2782 public void onUnsyncableAccountDone(boolean isReady) {
2783 if (isReady) {
2784 onReady();
2785 }
2786 }
2787 });
2788 } catch (RemoteException e) {
2789 Slog.e(TAG, "Could not call onUnsyncableAccountDone " + mSyncAdapterInfo, e);
2790 /*
2791 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
2792 * there is a crash in the implementation, assume the default behavior.
2793 */
2794 onReady();
2795 }
2796 }
2797
2798 @Override
2799 public void onServiceDisconnected(ComponentName name) {
2800 // Wait until the service connects again
2801 }
2802 }
2803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002804 /**
2805 * A helper object to keep track of the time we have spent syncing since the last boot
2806 */
2807 private class SyncTimeTracker {
2808 /** True if a sync was in progress on the most recent call to update() */
2809 boolean mLastWasSyncing = false;
2810 /** Used to track when lastWasSyncing was last set */
2811 long mWhenSyncStarted = 0;
2812 /** The cumulative time we have spent syncing */
2813 private long mTimeSpentSyncing;
2814
2815 /** Call to let the tracker know that the sync state may have changed */
2816 public synchronized void update() {
Fred Quintana918339a2010-10-05 14:00:39 -07002817 final boolean isSyncInProgress = !mActiveSyncContexts.isEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002818 if (isSyncInProgress == mLastWasSyncing) return;
2819 final long now = SystemClock.elapsedRealtime();
2820 if (isSyncInProgress) {
2821 mWhenSyncStarted = now;
2822 } else {
2823 mTimeSpentSyncing += now - mWhenSyncStarted;
2824 }
2825 mLastWasSyncing = isSyncInProgress;
2826 }
2827
2828 /** Get how long we have been syncing, in ms */
2829 public synchronized long timeSpentSyncing() {
2830 if (!mLastWasSyncing) return mTimeSpentSyncing;
2831
2832 final long now = SystemClock.elapsedRealtime();
2833 return mTimeSpentSyncing + (now - mWhenSyncStarted);
2834 }
2835 }
2836
Fred Quintana718d8a22009-04-29 17:53:20 -07002837 class ServiceConnectionData {
2838 public final ActiveSyncContext activeSyncContext;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002839 public final IBinder adapter;
2840
2841 ServiceConnectionData(ActiveSyncContext activeSyncContext, IBinder adapter) {
Fred Quintana718d8a22009-04-29 17:53:20 -07002842 this.activeSyncContext = activeSyncContext;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002843 this.adapter = adapter;
Fred Quintana718d8a22009-04-29 17:53:20 -07002844 }
2845 }
2846
Makoto Onuki3ab77812018-07-09 14:29:33 -07002847 @Nullable
2848 private static SyncManager getInstance() {
Makoto Onuki056a9752018-05-08 15:21:56 -07002849 synchronized (SyncManager.class) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002850 if (sInstance == null) {
2851 Slog.wtf(TAG, "sInstance == null"); // Maybe called too early?
2852 }
2853 return sInstance;
2854 }
2855 }
2856
2857 /**
2858 * @return whether the device is ready to run sync jobs for a given user.
2859 */
2860 public static boolean readyToSync(int userId) {
2861 final SyncManager instance = getInstance();
2862 return (instance != null) && SyncJobService.isReady()
2863 && instance.mProvisioned && instance.isUserUnlocked(userId);
2864 }
2865
2866 public static void sendMessage(Message message) {
2867 final SyncManager instance = getInstance();
2868 if (instance != null) {
2869 instance.mSyncHandler.sendMessage(message);
Makoto Onuki056a9752018-05-08 15:21:56 -07002870 }
2871 }
2872
2873 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002874 * Handles SyncOperation Messages that are posted to the associated
2875 * HandlerThread.
2876 */
2877 class SyncHandler extends Handler {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002878 // Messages that can be sent on mHandler.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879 private static final int MESSAGE_SYNC_FINISHED = 1;
Fred Quintana718d8a22009-04-29 17:53:20 -07002880 private static final int MESSAGE_SERVICE_CONNECTED = 4;
2881 private static final int MESSAGE_SERVICE_DISCONNECTED = 5;
Fred Quintana918339a2010-10-05 14:00:39 -07002882 private static final int MESSAGE_CANCEL = 6;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002883 static final int MESSAGE_START_SYNC = 10;
2884 static final int MESSAGE_STOP_SYNC = 11;
2885 static final int MESSAGE_SCHEDULE_SYNC = 12;
2886 static final int MESSAGE_UPDATE_PERIODIC_SYNC = 13;
2887 static final int MESSAGE_REMOVE_PERIODIC_SYNC = 14;
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002888
Matthew Williams1967c8d2015-06-19 19:03:13 -07002889 /**
2890 * Posted periodically to monitor network process for long-running syncs.
2891 * obj: {@link com.android.server.content.SyncManager.ActiveSyncContext}
2892 */
2893 private static final int MESSAGE_MONITOR_SYNC = 8;
振淦王60a74312015-12-01 16:37:31 +08002894 private static final int MESSAGE_ACCOUNTS_UPDATED = 9;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002896 public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002897 private final HashMap<String, PowerManager.WakeLock> mWakeLocks = Maps.newHashMap();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002898
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002899 public SyncHandler(Looper looper) {
2900 super(looper);
2901 }
2902
2903 public void handleMessage(Message msg) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002904 // TODO Do we really need this wake lock?? If we actually needed it, this is probably
2905 // not the best place to acquire the lock -- it's probably too late, because the device
2906 // could have gone to sleep before we reach here.
2907 mSyncManagerWakeLock.acquire();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002908 try {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002909 handleSyncMessage(msg);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002910 } finally {
2911 mSyncManagerWakeLock.release();
2912 }
2913 }
2914
2915 private void handleSyncMessage(Message msg) {
2916 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
2917
2918 try {
2919 mDataConnectionIsConnected = readDataConnectionState();
2920 switch (msg.what) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07002921 case MESSAGE_ACCOUNTS_UPDATED:
2922 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2923 Slog.v(TAG, "handleSyncHandlerMessage: MESSAGE_ACCOUNTS_UPDATED");
2924 }
2925 EndPoint targets = (EndPoint) msg.obj;
2926 updateRunningAccountsH(targets);
2927 break;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002928 case MESSAGE_SCHEDULE_SYNC:
Shreyas Basargeba1f7902016-10-01 00:19:44 +01002929 ScheduleSyncMessagePayload syncPayload =
2930 (ScheduleSyncMessagePayload) msg.obj;
2931 SyncOperation op = syncPayload.syncOperation;
2932 scheduleSyncOperationH(op, syncPayload.minDelayMillis);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002933 break;
2934
2935 case MESSAGE_START_SYNC:
2936 op = (SyncOperation) msg.obj;
2937 startSyncH(op);
2938 break;
2939
2940 case MESSAGE_STOP_SYNC:
2941 op = (SyncOperation) msg.obj;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002942 if (isLoggable) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00002943 Slog.v(TAG, "Stop sync received.");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002944 }
2945 ActiveSyncContext asc = findActiveSyncContextH(op.jobId);
2946 if (asc != null) {
2947 runSyncFinishedOrCanceledH(null /* no result */, asc);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00002948 boolean reschedule = msg.arg1 != 0;
2949 boolean applyBackoff = msg.arg2 != 0;
2950 if (isLoggable) {
2951 Slog.v(TAG, "Stopping sync. Reschedule: " + reschedule
2952 + "Backoff: " + applyBackoff);
2953 }
2954 if (applyBackoff) {
2955 increaseBackoffSetting(op.target);
2956 }
2957 if (reschedule) {
2958 deferStoppedSyncH(op, 0);
2959 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002960 }
2961 break;
2962
2963 case MESSAGE_UPDATE_PERIODIC_SYNC:
2964 UpdatePeriodicSyncMessagePayload data =
2965 (UpdatePeriodicSyncMessagePayload) msg.obj;
2966 updateOrAddPeriodicSyncH(data.target, data.pollFrequency,
2967 data.flex, data.extras);
2968 break;
2969 case MESSAGE_REMOVE_PERIODIC_SYNC:
Makoto Onukidd4b14f2017-08-17 14:03:48 -07002970 Pair<EndPoint, String> args = (Pair<EndPoint, String>) (msg.obj);
2971 removePeriodicSyncH(args.first, msg.getData(), args.second);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002972 break;
2973
2974 case SyncHandler.MESSAGE_CANCEL:
2975 SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
2976 Bundle extras = msg.peekData();
2977 if (Log.isLoggable(TAG, Log.DEBUG)) {
2978 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_CANCEL: "
2979 + endpoint + " bundle: " + extras);
2980 }
Makoto Onukia9dca242017-06-21 17:06:49 -07002981 cancelActiveSyncH(endpoint, extras, "MESSAGE_CANCEL");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002982 break;
2983
2984 case SyncHandler.MESSAGE_SYNC_FINISHED:
2985 SyncFinishedOrCancelledMessagePayload payload =
2986 (SyncFinishedOrCancelledMessagePayload) msg.obj;
2987 if (!isSyncStillActiveH(payload.activeSyncContext)) {
2988 Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
2989 + "sync is no longer active: "
2990 + payload.activeSyncContext);
2991 break;
2992 }
2993 if (isLoggable) {
2994 Slog.v(TAG, "syncFinished" + payload.activeSyncContext.mSyncOperation);
2995 }
Makoto Onuki3ab77812018-07-09 14:29:33 -07002996 SyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07002997 payload.activeSyncContext.mSyncOperation.jobId, false,
2998 "sync finished");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002999 runSyncFinishedOrCanceledH(payload.syncResult,
3000 payload.activeSyncContext);
3001 break;
3002
3003 case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
3004 ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
3005 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3006 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
3007 + msgData.activeSyncContext);
3008 }
3009 // Check that this isn't an old message.
3010 if (isSyncStillActiveH(msgData.activeSyncContext)) {
3011 runBoundToAdapterH(
3012 msgData.activeSyncContext,
3013 msgData.adapter);
3014 }
3015 break;
3016 }
3017
3018 case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
3019 final ActiveSyncContext currentSyncContext =
3020 ((ServiceConnectionData) msg.obj).activeSyncContext;
3021 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3022 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
3023 + currentSyncContext);
3024 }
3025 // Check that this isn't an old message.
3026 if (isSyncStillActiveH(currentSyncContext)) {
3027 // cancel the sync if we have a syncadapter, which means one is
3028 // outstanding
3029 try {
3030 if (currentSyncContext.mSyncAdapter != null) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003031 mLogger.log("Calling cancelSync for SERVICE_DISCONNECTED ",
3032 currentSyncContext,
3033 " adapter=", currentSyncContext.mSyncAdapter);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003034 currentSyncContext.mSyncAdapter.cancelSync(currentSyncContext);
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003035 mLogger.log("Canceled");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003036 }
3037 } catch (RemoteException e) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003038 mLogger.log("RemoteException ", Log.getStackTraceString(e));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003039 // We don't need to retry this in this case.
3040 }
3041
3042 // Pretend that the sync failed with an IOException,
3043 // which is a soft error.
3044 SyncResult syncResult = new SyncResult();
3045 syncResult.stats.numIoExceptions++;
Makoto Onuki3ab77812018-07-09 14:29:33 -07003046 SyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003047 currentSyncContext.mSyncOperation.jobId, false,
3048 "service disconnected");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003049 runSyncFinishedOrCanceledH(syncResult, currentSyncContext);
3050 }
3051 break;
3052 }
3053
3054 case SyncHandler.MESSAGE_MONITOR_SYNC:
3055 ActiveSyncContext monitoredSyncContext = (ActiveSyncContext) msg.obj;
3056 if (Log.isLoggable(TAG, Log.DEBUG)) {
3057 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_MONITOR_SYNC: " +
3058 monitoredSyncContext.mSyncOperation.target);
3059 }
3060
3061 if (isSyncNotUsingNetworkH(monitoredSyncContext)) {
3062 Log.w(TAG, String.format(
3063 "Detected sync making no progress for %s. cancelling.",
3064 monitoredSyncContext));
Makoto Onuki3ab77812018-07-09 14:29:33 -07003065 SyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003066 monitoredSyncContext.mSyncOperation.jobId, false,
3067 "no network activity");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003068 runSyncFinishedOrCanceledH(
3069 null /* cancel => no result */, monitoredSyncContext);
3070 } else {
3071 // Repost message to check again.
3072 postMonitorSyncProgressMessage(monitoredSyncContext);
3073 }
3074 break;
3075
3076 }
3077 } finally {
3078 mSyncTimeTracker.update();
Fred Quintanae91ebe22009-09-29 20:44:30 -07003079 }
3080 }
3081
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003082 private PowerManager.WakeLock getSyncWakeLock(SyncOperation operation) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08003083 final String wakeLockKey = operation.wakeLockName();
Fred Quintanab3029c32010-04-06 13:27:12 -07003084 PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
3085 if (wakeLock == null) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08003086 final String name = SYNC_WAKE_LOCK_PREFIX + wakeLockKey;
Fred Quintanab3029c32010-04-06 13:27:12 -07003087 wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
3088 wakeLock.setReferenceCounted(false);
3089 mWakeLocks.put(wakeLockKey, wakeLock);
3090 }
3091 return wakeLock;
3092 }
3093
Matthew Williams8704fc32013-09-27 11:32:35 -07003094 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003095 * Defer the specified SyncOperation by rescheduling it on the JobScheduler with some
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003096 * delay. This is equivalent to a failure. If this is a periodic sync, a delayed one-off
3097 * sync will be scheduled.
Matthew Williams8704fc32013-09-27 11:32:35 -07003098 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003099 private void deferSyncH(SyncOperation op, long delay, String why) {
3100 mLogger.log("deferSyncH() ", (op.isPeriodic ? "periodic " : ""),
3101 "sync. op=", op, " delay=", delay, " why=", why);
Makoto Onuki3ab77812018-07-09 14:29:33 -07003102 SyncJobService.callJobFinished(op.jobId, false, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003103 if (op.isPeriodic) {
3104 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
3105 } else {
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003106 // mSyncJobService.callJobFinished is async, so cancel the job to ensure we don't
3107 // find the this job in the pending jobs list while looking for duplicates
3108 // before scheduling it at a later time.
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003109 cancelJob(op, "deferSyncH()");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003110 scheduleSyncOperationH(op, delay);
Fred Quintanae91ebe22009-09-29 20:44:30 -07003111 }
3112 }
Matthew Williams8704fc32013-09-27 11:32:35 -07003113
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003114 /* Same as deferSyncH, but assumes that job is no longer running on JobScheduler. */
3115 private void deferStoppedSyncH(SyncOperation op, long delay) {
3116 if (op.isPeriodic) {
3117 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
3118 } else {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003119 scheduleSyncOperationH(op, delay);
3120 }
3121 }
3122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003124 * Cancel an active sync and reschedule it on the JobScheduler with some delay.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003125 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003126 private void deferActiveSyncH(ActiveSyncContext asc, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003127 SyncOperation op = asc.mSyncOperation;
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003128 runSyncFinishedOrCanceledH(null, asc);
Makoto Onukia9dca242017-06-21 17:06:49 -07003129 deferSyncH(op, SYNC_DELAY_ON_CONFLICT, why);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 }
3131
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003132 private void startSyncH(SyncOperation op) {
3133 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3134 if (isLoggable) Slog.v(TAG, op.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003135
Makoto Onuki94986212018-04-11 16:24:46 -07003136 // At this point, we know the device has been connected to the server, so
3137 // assume the clock is correct.
3138 mSyncStorageEngine.setClockValid();
3139
Makoto Onuki3ab77812018-07-09 14:29:33 -07003140 SyncJobService.markSyncStarted(op.jobId);
Makoto Onuki5397be12017-12-20 16:22:34 +09003141
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003142 if (mStorageIsLow) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003143 deferSyncH(op, SYNC_DELAY_ON_LOW_STORAGE, "storage low");
Matthew Williams8704fc32013-09-27 11:32:35 -07003144 return;
3145 }
3146
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003147 if (op.isPeriodic) {
3148 // Don't allow this periodic to run if a previous instance failed and is currently
3149 // scheduled according to some backoff criteria.
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003150 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003151 for (SyncOperation syncOperation: ops) {
3152 if (syncOperation.sourcePeriodicId == op.jobId) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003153 SyncJobService.callJobFinished(op.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003154 "periodic sync, pending");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003155 return;
Fred Quintana718d8a22009-04-29 17:53:20 -07003156 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003157 }
3158 // Don't allow this periodic to run if a previous instance failed and is currently
3159 // executing according to some backoff criteria.
3160 for (ActiveSyncContext asc: mActiveSyncContexts) {
3161 if (asc.mSyncOperation.sourcePeriodicId == op.jobId) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003162 SyncJobService.callJobFinished(op.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003163 "periodic sync, already running");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003164 return;
Fred Quintana718d8a22009-04-29 17:53:20 -07003165 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003166 }
3167 // Check for adapter delays.
3168 if (isAdapterDelayed(op.target)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003169 deferSyncH(op, 0 /* No minimum delay */, "backing off");
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003170 return;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003171 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003172 }
Fred Quintana718d8a22009-04-29 17:53:20 -07003173
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003174 // Check for conflicting syncs.
3175 for (ActiveSyncContext asc: mActiveSyncContexts) {
3176 if (asc.mSyncOperation.isConflict(op)) {
3177 // If the provided SyncOperation conflicts with a running one, the lower
3178 // priority sync is pre-empted.
3179 if (asc.mSyncOperation.findPriority() >= op.findPriority()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003180 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003181 Slog.v(TAG, "Rescheduling sync due to conflict " + op.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003183 deferSyncH(op, SYNC_DELAY_ON_CONFLICT, "delay on conflict");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003184 return;
Matthew Williamsfa774182013-06-18 15:44:11 -07003185 } else {
Matthew Williamsfa774182013-06-18 15:44:11 -07003186 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003187 Slog.v(TAG, "Pushing back running sync due to a higher priority sync");
Fred Quintana918339a2010-10-05 14:00:39 -07003188 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003189 deferActiveSyncH(asc, "preempted");
Shreyas Basarge7680dd92016-02-11 14:52:47 +00003190 break;
Alon Albert8e285552012-09-17 15:05:27 -07003191 }
3192 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 }
3194
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003195 final int syncOpState = computeSyncOpState(op);
3196 switch (syncOpState) {
3197 case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
3198 case SYNC_OP_STATE_INVALID: {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003199 SyncJobService.callJobFinished(op.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003200 "invalid op state: " + syncOpState);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003201 } return;
3202 }
3203
3204 if (!dispatchSyncOperation(op)) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003205 SyncJobService.callJobFinished(op.jobId, false, "dispatchSyncOperation() failed");
Fred Quintana918339a2010-10-05 14:00:39 -07003206 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003207
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003208 setAuthorityPendingState(op.target);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003209 }
3210
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003211 private ActiveSyncContext findActiveSyncContextH(int jobId) {
3212 for (ActiveSyncContext asc: mActiveSyncContexts) {
3213 SyncOperation op = asc.mSyncOperation;
3214 if (op != null && op.jobId == jobId) {
3215 return asc;
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003216 }
3217 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003218 return null;
Matthew Williamsa4745542015-12-10 20:29:02 +00003219 }
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003220
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003221 private void updateRunningAccountsH(EndPoint syncTargets) {
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003222 AccountAndUser[] oldAccounts = mRunningAccounts;
振淦王60a74312015-12-01 16:37:31 +08003223 mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003224 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3225 Slog.v(TAG, "Accounts list: ");
3226 for (AccountAndUser acc : mRunningAccounts) {
3227 Slog.v(TAG, acc.toString());
3228 }
3229 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003230 if (mLogger.enabled()) {
3231 mLogger.log("updateRunningAccountsH: ", Arrays.toString(mRunningAccounts));
3232 }
Makoto Onuki3ab77812018-07-09 14:29:33 -07003233 removeStaleAccounts();
振淦王60a74312015-12-01 16:37:31 +08003234
3235 AccountAndUser[] accounts = mRunningAccounts;
3236 for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
3237 if (!containsAccountAndUser(accounts,
3238 currentSyncContext.mSyncOperation.target.account,
3239 currentSyncContext.mSyncOperation.target.userId)) {
3240 Log.d(TAG, "canceling sync since the account is no longer running");
3241 sendSyncFinishedOrCanceledMessage(currentSyncContext,
3242 null /* no result since this is a cancel */);
3243 }
3244 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003245
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003246 // On account add, check if there are any settings to be restored.
3247 for (AccountAndUser aau : mRunningAccounts) {
3248 if (!containsAccountAndUser(oldAccounts, aau.account, aau.userId)) {
3249 if (Log.isLoggable(TAG, Log.DEBUG)) {
3250 Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
3251 }
3252 AccountSyncSettingsBackupHelper.accountAdded(mContext);
3253 break;
3254 }
3255 }
3256
Rubin Xu2c548e02016-04-01 17:47:28 +01003257 // Cancel all jobs from non-existent accounts.
3258 AccountAndUser[] allAccounts = AccountManagerService.getSingleton().getAllAccounts();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003259 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003260 for (SyncOperation op: ops) {
Rubin Xu2c548e02016-04-01 17:47:28 +01003261 if (!containsAccountAndUser(allAccounts, op.target.account, op.target.userId)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003262 mLogger.log("canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003263 cancelJob(op, "updateRunningAccountsH()");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003264 }
3265 }
3266
3267 if (syncTargets != null) {
3268 scheduleSync(syncTargets.account, syncTargets.userId,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003269 SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
Makoto Onuki61283ec2018-01-31 17:22:36 -08003270 null, AuthorityInfo.NOT_INITIALIZED,
Makoto Onukie183a402018-08-29 11:46:41 -07003271 ContentResolver.SYNC_EXEMPTION_NONE, Process.myUid(), -4, null);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003272 }
3273 }
3274
3275 /**
3276 * The given SyncOperation will be removed and a new one scheduled in its place if
3277 * an updated period or flex is specified.
3278 * @param syncOperation SyncOperation whose period and flex is to be updated.
3279 * @param pollFrequencyMillis new period in milliseconds.
3280 * @param flexMillis new flex time in milliseconds.
3281 */
3282 private void maybeUpdateSyncPeriodH(SyncOperation syncOperation, long pollFrequencyMillis,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003283 long flexMillis) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003284 if (!(pollFrequencyMillis == syncOperation.periodMillis
3285 && flexMillis == syncOperation.flexMillis)) {
3286 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3287 Slog.v(TAG, "updating period " + syncOperation + " to " + pollFrequencyMillis
3288 + " and flex to " + flexMillis);
3289 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003290 SyncOperation newOp = new SyncOperation(syncOperation, pollFrequencyMillis,
3291 flexMillis);
3292 newOp.jobId = syncOperation.jobId;
3293 scheduleSyncOperationH(newOp);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003294 }
3295 }
3296
3297 private void updateOrAddPeriodicSyncH(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003298 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003299 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3300 verifyJobScheduler(); // Will fill in mScheduledSyncs cache if it is not already filled.
3301 final long pollFrequencyMillis = pollFrequency * 1000L;
3302 final long flexMillis = flex * 1000L;
3303 if (isLoggable) {
3304 Slog.v(TAG, "Addition to periodic syncs requested: " + target
3305 + " period: " + pollFrequency
3306 + " flexMillis: " + flex
3307 + " extras: " + extras.toString());
3308 }
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003309 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003310 for (SyncOperation op: ops) {
3311 if (op.isPeriodic && op.target.matchesSpec(target)
3312 && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
3313 maybeUpdateSyncPeriodH(op, pollFrequencyMillis, flexMillis);
3314 return;
3315 }
3316 }
3317
3318 if (isLoggable) {
3319 Slog.v(TAG, "Adding new periodic sync: " + target
3320 + " period: " + pollFrequency
3321 + " flexMillis: " + flex
3322 + " extras: " + extras.toString());
3323 }
3324
3325 final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
3326 syncAdapterInfo = mSyncAdapters.getServiceInfo(
3327 SyncAdapterType.newKey(
3328 target.provider, target.account.type),
3329 target.userId);
3330 if (syncAdapterInfo == null) {
3331 return;
3332 }
3333
3334 SyncOperation op = new SyncOperation(target, syncAdapterInfo.uid,
3335 syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC,
3336 SyncStorageEngine.SOURCE_PERIODIC, extras,
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003337 syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003338 pollFrequencyMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003339
3340 final int syncOpState = computeSyncOpState(op);
3341 switch (syncOpState) {
3342 case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
Svet Ganov973edd192016-09-08 20:15:55 -07003343 String packageName = op.owningPackage;
3344 final int userId = UserHandle.getUserId(op.owningUid);
3345 // If the app did not run and has no account access, done
Makoto Onuki850045d2018-08-09 11:31:14 -07003346 if (!wasPackageEverLaunched(packageName, userId)) {
Svet Ganov973edd192016-09-08 20:15:55 -07003347 return;
3348 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003349 mAccountManagerInternal.requestAccountAccess(op.target.account,
Svet Ganov973edd192016-09-08 20:15:55 -07003350 packageName, userId, new RemoteCallback((Bundle result) -> {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003351 if (result != null
3352 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
3353 updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
3354 }
3355 }
3356 ));
3357 } return;
3358
3359 case SYNC_OP_STATE_INVALID: {
3360 return;
3361 }
3362 }
3363
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003364 scheduleSyncOperationH(op);
3365 mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
3366 }
3367
3368 /**
3369 * Remove this periodic sync operation and all one-off operations initiated by it.
3370 */
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003371 private void removePeriodicSyncInternalH(SyncOperation syncOperation, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003372 // Remove this periodic sync and all one-off syncs initiated by it.
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003373 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003374 for (SyncOperation op: ops) {
3375 if (op.sourcePeriodicId == syncOperation.jobId || op.jobId == syncOperation.jobId) {
3376 ActiveSyncContext asc = findActiveSyncContextH(syncOperation.jobId);
3377 if (asc != null) {
Makoto Onuki3ab77812018-07-09 14:29:33 -07003378 SyncJobService.callJobFinished(syncOperation.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003379 "removePeriodicSyncInternalH");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003380 runSyncFinishedOrCanceledH(null, asc);
3381 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003382 mLogger.log("removePeriodicSyncInternalH-canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003383 cancelJob(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003384 }
3385 }
3386 }
3387
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003388 private void removePeriodicSyncH(EndPoint target, Bundle extras, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003389 verifyJobScheduler();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003390 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003391 for (SyncOperation op: ops) {
3392 if (op.isPeriodic && op.target.matchesSpec(target)
3393 && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003394 removePeriodicSyncInternalH(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003395 }
3396 }
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003397 }
3398
Matthew Williams1967c8d2015-06-19 19:03:13 -07003399 private boolean isSyncNotUsingNetworkH(ActiveSyncContext activeSyncContext) {
3400 final long bytesTransferredCurrent =
3401 getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
3402 final long deltaBytesTransferred =
3403 bytesTransferredCurrent - activeSyncContext.mBytesTransferredAtLastPoll;
3404
3405 if (Log.isLoggable(TAG, Log.DEBUG)) {
3406 // Bytes transferred
3407 long remainder = deltaBytesTransferred;
3408 long mb = remainder / (1024 * 1024);
3409 remainder %= 1024 * 1024;
3410 long kb = remainder / 1024;
3411 remainder %= 1024;
3412 long b = remainder;
3413 Log.d(TAG, String.format(
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003414 "Time since last update: %ds. Delta transferred: %dMBs,%dKBs,%dBs",
3415 (SystemClock.elapsedRealtime()
3416 - activeSyncContext.mLastPolledTimeElapsed)/1000,
3417 mb, kb, b)
Matthew Williams1967c8d2015-06-19 19:03:13 -07003418 );
3419 }
3420 return (deltaBytesTransferred <= SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES);
3421 }
3422
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003423 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003424 * Determine if a sync is no longer valid and should be dropped.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003425 */
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003426 private int computeSyncOpState(SyncOperation op) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003427 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003428 int state;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003429 final EndPoint target = op.target;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003430
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003431 // Drop the sync if the account of this operation no longer exists.
3432 AccountAndUser[] accounts = mRunningAccounts;
3433 if (!containsAccountAndUser(accounts, target.account, target.userId)) {
3434 if (isLoggable) {
3435 Slog.v(TAG, " Dropping sync operation: account doesn't exist.");
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003436 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003437 return SYNC_OP_STATE_INVALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003438 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003439 // Drop this sync request if it isn't syncable.
Philip P. Moltmann486b2412018-01-03 11:29:01 -08003440 state = computeSyncable(target.account, target.userId, target.provider, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003441 if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003442 if (isLoggable) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003443 Slog.v(TAG, " Dropping sync operation: "
3444 + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003445 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003446 return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003447 }
Svet Ganovdfed1c72016-08-25 15:40:52 -07003448 if (state == AuthorityInfo.NOT_SYNCABLE) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003449 if (isLoggable) {
Svet Ganovdfed1c72016-08-25 15:40:52 -07003450 Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003451 }
3452 return SYNC_OP_STATE_INVALID;
3453 }
3454
3455 final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
3456 && mSyncStorageEngine.getSyncAutomatically(target.account,
3457 target.userId, target.provider);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003458
3459 // We ignore system settings that specify the sync is invalid if:
3460 // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
3461 // or
3462 // 2) it's an initialisation sync - we just need to connect to it.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003463 final boolean ignoreSystemConfiguration = op.isIgnoreSettings() || (state < 0);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003464
3465 // Sync not enabled.
3466 if (!syncEnabled && !ignoreSystemConfiguration) {
3467 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003468 Slog.v(TAG, " Dropping sync operation: disallowed by settings/network.");
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003469 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003470 return SYNC_OP_STATE_INVALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003471 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003472 return SYNC_OP_STATE_VALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003473 }
Fred Quintana918339a2010-10-05 14:00:39 -07003474
Fred Quintana87b14662011-09-12 10:32:55 -07003475 private boolean dispatchSyncOperation(SyncOperation op) {
Fred Quintana918339a2010-10-05 14:00:39 -07003476 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003477 Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
3478 Slog.v(TAG, "num active syncs: " + mActiveSyncContexts.size());
Fred Quintana918339a2010-10-05 14:00:39 -07003479 for (ActiveSyncContext syncContext : mActiveSyncContexts) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003480 Slog.v(TAG, syncContext.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003481 }
3482 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07003483 if (op.isAppStandbyExempted()) {
3484 final UsageStatsManagerInternal usmi = LocalServices.getService(
3485 UsageStatsManagerInternal.class);
3486 if (usmi != null) {
3487 usmi.reportExemptedSyncStart(op.owningPackage,
3488 UserHandle.getUserId(op.owningUid));
3489 }
3490 }
3491
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003492 // Connect to the sync adapter.
3493 int targetUid;
3494 ComponentName targetComponent;
3495 final SyncStorageEngine.EndPoint info = op.target;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003496 SyncAdapterType syncAdapterType =
3497 SyncAdapterType.newKey(info.provider, info.account.type);
3498 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
3499 syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId);
3500 if (syncAdapterInfo == null) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003501 mLogger.log("dispatchSyncOperation() failed: no sync adapter info for ",
3502 syncAdapterType);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003503 Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
3504 + ", removing settings for it");
3505 mSyncStorageEngine.removeAuthority(info);
3506 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003508 targetUid = syncAdapterInfo.uid;
3509 targetComponent = syncAdapterInfo.componentName;
Fred Quintana718d8a22009-04-29 17:53:20 -07003510 ActiveSyncContext activeSyncContext =
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003511 new ActiveSyncContext(op, insertStartSyncEvent(op), targetUid);
Fred Quintana718d8a22009-04-29 17:53:20 -07003512 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003513 Slog.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);
Fred Quintana718d8a22009-04-29 17:53:20 -07003514 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07003515
3516 activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);
3517 mActiveSyncContexts.add(activeSyncContext);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003518
3519 // Post message to begin monitoring this sync's progress.
3520 postMonitorSyncProgressMessage(activeSyncContext);
3521
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003522 if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003523 mLogger.log("dispatchSyncOperation() failed: bind failed. target: ",
3524 targetComponent);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003525 Slog.e(TAG, "Bind attempt failed - target: " + targetComponent);
Fred Quintana918339a2010-10-05 14:00:39 -07003526 closeActiveSyncContext(activeSyncContext);
Fred Quintana87b14662011-09-12 10:32:55 -07003527 return false;
Fred Quintana718d8a22009-04-29 17:53:20 -07003528 }
3529
Fred Quintana87b14662011-09-12 10:32:55 -07003530 return true;
Fred Quintana718d8a22009-04-29 17:53:20 -07003531 }
3532
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003533 private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003534 IBinder syncAdapter) {
Fred Quintana918339a2010-10-05 14:00:39 -07003535 final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
Fred Quintana718d8a22009-04-29 17:53:20 -07003536 try {
Alon Alberteca75112010-12-08 15:02:33 -08003537 activeSyncContext.mIsLinkedToDeath = true;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003538 syncAdapter.linkToDeath(activeSyncContext, 0);
Alon Alberteca75112010-12-08 15:02:33 -08003539
Makoto Onukia9dca242017-06-21 17:06:49 -07003540 mLogger.log("Sync start: account=" + syncOperation.target.account,
3541 " authority=", syncOperation.target.provider,
3542 " reason=", SyncOperation.reasonToString(null, syncOperation.reason),
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003543 " extras=", SyncOperation.extrasToString(syncOperation.extras),
3544 " adapter=", activeSyncContext.mSyncAdapter);
Makoto Onukia9dca242017-06-21 17:06:49 -07003545
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003546 activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter);
3547 activeSyncContext.mSyncAdapter
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003548 .startSync(activeSyncContext, syncOperation.target.provider,
3549 syncOperation.target.account, syncOperation.extras);
Makoto Onukia9dca242017-06-21 17:06:49 -07003550
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003551 mLogger.log("Sync is running now...");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003552 } catch (RemoteException remoteExc) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003553 mLogger.log("Sync failed with RemoteException: ", remoteExc.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003554 Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);
3555 closeActiveSyncContext(activeSyncContext);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003556 increaseBackoffSetting(syncOperation.target);
3557 scheduleSyncOperationH(syncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 } catch (RuntimeException exc) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003559 mLogger.log("Sync failed with RuntimeException: ", exc.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003560 closeActiveSyncContext(activeSyncContext);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003561 Slog.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003563 }
3564
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003565 /**
Matthew Williams8ef22042013-07-26 12:56:39 -07003566 * Cancel the sync for the provided target that matches the given bundle.
Matthew Williams1967c8d2015-06-19 19:03:13 -07003567 * @param info Can have null fields to indicate all the active syncs for that field.
3568 * @param extras Can be null to indicate <strong>all</strong> syncs for the given endpoint.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003569 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003570 private void cancelActiveSyncH(SyncStorageEngine.EndPoint info, Bundle extras,
3571 String why) {
Fred Quintana918339a2010-10-05 14:00:39 -07003572 ArrayList<ActiveSyncContext> activeSyncs =
3573 new ArrayList<ActiveSyncContext>(mActiveSyncContexts);
3574 for (ActiveSyncContext activeSyncContext : activeSyncs) {
3575 if (activeSyncContext != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003576 final SyncStorageEngine.EndPoint opInfo =
3577 activeSyncContext.mSyncOperation.target;
Matthew Williams8ef22042013-07-26 12:56:39 -07003578 if (!opInfo.matchesSpec(info)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003579 continue;
Fred Quintana918339a2010-10-05 14:00:39 -07003580 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003581 if (extras != null &&
3582 !syncExtrasEquals(activeSyncContext.mSyncOperation.extras,
3583 extras,
3584 false /* no config settings */)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003585 continue;
3586 }
Makoto Onuki3ab77812018-07-09 14:29:33 -07003587 SyncJobService.callJobFinished(activeSyncContext.mSyncOperation.jobId, false,
Makoto Onukia9dca242017-06-21 17:06:49 -07003588 why);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003589 runSyncFinishedOrCanceledH(null /* cancel => no result */, activeSyncContext);
Fred Quintana918339a2010-10-05 14:00:39 -07003590 }
3591 }
3592 }
3593
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003594 /**
3595 * Should be called when a one-off instance of a periodic sync completes successfully.
3596 */
3597 private void reschedulePeriodicSyncH(SyncOperation syncOperation) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003598 // Ensure that the periodic sync wasn't removed.
3599 SyncOperation periodicSync = null;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003600 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003601 for (SyncOperation op: ops) {
3602 if (op.isPeriodic && syncOperation.matchesPeriodicOperation(op)) {
3603 periodicSync = op;
3604 break;
3605 }
3606 }
3607 if (periodicSync == null) {
3608 return;
3609 }
3610 scheduleSyncOperationH(periodicSync);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003611 }
3612
Matthew Williams8b76d202015-05-03 18:16:25 -07003613 private void runSyncFinishedOrCanceledH(SyncResult syncResult,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003614 ActiveSyncContext activeSyncContext) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003615 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Alon Alberteca75112010-12-08 15:02:33 -08003616
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003617 final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
3618 final SyncStorageEngine.EndPoint info = syncOperation.target;
3619
Alon Alberteca75112010-12-08 15:02:33 -08003620 if (activeSyncContext.mIsLinkedToDeath) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003621 activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
Alon Alberteca75112010-12-08 15:02:33 -08003622 activeSyncContext.mIsLinkedToDeath = false;
3623 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625 String historyMessage;
3626 int downstreamActivity;
3627 int upstreamActivity;
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003628
Makoto Onukia9dca242017-06-21 17:06:49 -07003629 mLogger.log("runSyncFinishedOrCanceledH() op=", syncOperation, " result=", syncResult);
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003631 if (syncResult != null) {
3632 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003633 Slog.v(TAG, "runSyncFinishedOrCanceled [finished]: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003634 + syncOperation + ", result " + syncResult);
3635 }
3636
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003637 // In the non-canceled case, close the active sync context before doing the rest
3638 // of the stuff.
3639 closeActiveSyncContext(activeSyncContext);
3640
3641 // Note this part is probably okay to do before closeActiveSyncContext()...
3642 // But moved here to restore OC-dev's behavior. See b/64597061.
3643 if (!syncOperation.isPeriodic) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003644 cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-finished");
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003645 }
3646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003647 if (!syncResult.hasError()) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07003648 historyMessage = SyncStorageEngine.MESG_SUCCESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003649 // TODO: set these correctly when the SyncResult is extended to include it
3650 downstreamActivity = 0;
3651 upstreamActivity = 0;
Makoto Onukia9dca242017-06-21 17:06:49 -07003652 clearBackoffSetting(syncOperation.target, "sync success");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003653
3654 // If the operation completes successfully and it was scheduled due to
3655 // a periodic operation failing, we reschedule the periodic operation to
3656 // start from now.
3657 if (syncOperation.isDerivedFromFailedPeriodicSync()) {
3658 reschedulePeriodicSyncH(syncOperation);
3659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003660 } else {
Makoto Onukiaad2b512018-02-07 09:31:46 -08003661 Log.w(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
3662
3663 syncOperation.retries++;
3664 if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07003665 syncOperation.syncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onukiaad2b512018-02-07 09:31:46 -08003666 }
3667
Fred Quintana307da1a2010-01-21 14:24:20 -08003668 // the operation failed so increase the backoff time
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003669 increaseBackoffSetting(syncOperation.target);
3670 if (!syncOperation.isPeriodic) {
3671 // reschedule the sync if so indicated by the syncResult
3672 maybeRescheduleSync(syncResult, syncOperation);
3673 } else {
3674 // create a normal sync instance that will respect adapter backoffs
Shreyas Basargeba1f7902016-10-01 00:19:44 +01003675 postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation(),
3676 0 /* min delay */);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003677 }
Alon Albert57286f92012-10-09 14:21:38 -07003678 historyMessage = ContentResolver.syncErrorToString(
3679 syncResultToErrorNumber(syncResult));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003680 // TODO: set these correctly when the SyncResult is extended to include it
3681 downstreamActivity = 0;
3682 upstreamActivity = 0;
3683 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003684 setDelayUntilTime(syncOperation.target, syncResult.delayUntil);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003685 } else {
3686 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003687 Slog.v(TAG, "runSyncFinishedOrCanceled [canceled]: " + syncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688 }
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003689
3690 if (!syncOperation.isPeriodic) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003691 cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-canceled");
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003692 }
3693
Fred Quintana718d8a22009-04-29 17:53:20 -07003694 if (activeSyncContext.mSyncAdapter != null) {
3695 try {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003696 mLogger.log("Calling cancelSync for runSyncFinishedOrCanceled ",
3697 activeSyncContext, " adapter=", activeSyncContext.mSyncAdapter);
Fred Quintana21bb0de2009-06-16 10:24:58 -07003698 activeSyncContext.mSyncAdapter.cancelSync(activeSyncContext);
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003699 mLogger.log("Canceled");
Fred Quintana718d8a22009-04-29 17:53:20 -07003700 } catch (RemoteException e) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003701 mLogger.log("RemoteException ", Log.getStackTraceString(e));
Fred Quintana718d8a22009-04-29 17:53:20 -07003702 // we don't need to retry this in this case
3703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003704 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07003705 historyMessage = SyncStorageEngine.MESG_CANCELED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 downstreamActivity = 0;
3707 upstreamActivity = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003708
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003709 // In the cancel sync case, close it after calling cancelSync().
3710 closeActiveSyncContext(activeSyncContext);
3711 }
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713 stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
3714 upstreamActivity, downstreamActivity, elapsedTime);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003715 // Check for full-resync and schedule it after closing off the last sync.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003716 if (syncResult != null && syncResult.tooManyDeletions) {
3717 installHandleTooManyDeletesNotification(info.account,
3718 info.provider, syncResult.stats.numDeletes,
3719 info.userId);
3720 } else {
Chris Wren282cfef2017-03-27 15:01:44 -04003721 mNotificationMgr.cancelAsUser(
3722 Integer.toString(info.account.hashCode() ^ info.provider.hashCode()),
3723 SystemMessage.NOTE_SYNC_ERROR,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003724 new UserHandle(info.userId));
3725 }
3726 if (syncResult != null && syncResult.fullSyncRequested) {
3727 scheduleSyncOperationH(
3728 new SyncOperation(info.account, info.userId,
3729 syncOperation.owningUid, syncOperation.owningPackage,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003730 syncOperation.reason,
3731 syncOperation.syncSource, info.provider, new Bundle(),
Makoto Onuki61283ec2018-01-31 17:22:36 -08003732 syncOperation.allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003733 syncOperation.syncExemptionFlag));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003735 }
3736
Fred Quintana918339a2010-10-05 14:00:39 -07003737 private void closeActiveSyncContext(ActiveSyncContext activeSyncContext) {
3738 activeSyncContext.close();
3739 mActiveSyncContexts.remove(activeSyncContext);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003740 mSyncStorageEngine.removeActiveSync(activeSyncContext.mSyncInfo,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003741 activeSyncContext.mSyncOperation.target.userId);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003742
3743 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003744 Slog.v(TAG, "removing all MESSAGE_MONITOR_SYNC & MESSAGE_SYNC_EXPIRED for "
Matthew Williams1967c8d2015-06-19 19:03:13 -07003745 + activeSyncContext.toString());
3746 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07003747 mSyncHandler.removeMessages(SyncHandler.MESSAGE_MONITOR_SYNC, activeSyncContext);
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003748
3749 mLogger.log("closeActiveSyncContext: ", activeSyncContext);
Fred Quintana918339a2010-10-05 14:00:39 -07003750 }
3751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003752 /**
3753 * Convert the error-containing SyncResult into the Sync.History error number. Since
3754 * the SyncResult may indicate multiple errors at once, this method just returns the
3755 * most "serious" error.
3756 * @param syncResult the SyncResult from which to read
3757 * @return the most "serious" error set in the SyncResult
3758 * @throws IllegalStateException if the SyncResult does not indicate any errors.
3759 * If SyncResult.error() is true then it is safe to call this.
3760 */
3761 private int syncResultToErrorNumber(SyncResult syncResult) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07003762 if (syncResult.syncAlreadyInProgress)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003763 return ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003764 if (syncResult.stats.numAuthExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003765 return ContentResolver.SYNC_ERROR_AUTHENTICATION;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003766 if (syncResult.stats.numIoExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003767 return ContentResolver.SYNC_ERROR_IO;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003768 if (syncResult.stats.numParseExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003769 return ContentResolver.SYNC_ERROR_PARSE;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003770 if (syncResult.stats.numConflictDetectedExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003771 return ContentResolver.SYNC_ERROR_CONFLICT;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003772 if (syncResult.tooManyDeletions)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003773 return ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003774 if (syncResult.tooManyRetries)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003775 return ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003776 if (syncResult.databaseError)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003777 return ContentResolver.SYNC_ERROR_INTERNAL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003778 throw new IllegalStateException("we are not in an error state, " + syncResult);
3779 }
3780
Fred Quintanad9d2f112009-04-23 13:36:27 -07003781 private void installHandleTooManyDeletesNotification(Account account, String authority,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003782 long numDeletes, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003783 if (mNotificationMgr == null) return;
Fred Quintanac848b702009-08-25 20:18:46 -07003784
3785 final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
3786 authority, 0 /* flags */);
3787 if (providerInfo == null) {
3788 return;
3789 }
3790 CharSequence authorityName = providerInfo.loadLabel(mContext.getPackageManager());
3791
Fred Quintanab19e62a2010-12-16 13:54:43 -08003792 Intent clickIntent = new Intent(mContext, SyncActivityTooManyDeletes.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003793 clickIntent.putExtra("account", account);
Tadashi G. Takaoka86135d32009-09-24 19:31:44 -07003794 clickIntent.putExtra("authority", authority);
Fred Quintanac848b702009-08-25 20:18:46 -07003795 clickIntent.putExtra("provider", authorityName.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 clickIntent.putExtra("numDeletes", numDeletes);
3797
3798 if (!isActivityAvailable(clickIntent)) {
3799 Log.w(TAG, "No activity found to handle too many deletes.");
3800 return;
3801 }
3802
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003803 UserHandle user = new UserHandle(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 final PendingIntent pendingIntent = PendingIntent
Dianne Hackborn41203752012-08-31 14:05:51 -07003805 .getActivityAsUser(mContext, 0, clickIntent,
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003806 PendingIntent.FLAG_CANCEL_CURRENT, null, user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003807
3808 CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
3809 R.string.contentServiceTooManyDeletesNotificationDesc);
3810
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003811 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003812 Notification notification =
3813 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04003814 .setSmallIcon(R.drawable.stat_notify_sync_error)
3815 .setTicker(mContext.getString(R.string.contentServiceSync))
3816 .setWhen(System.currentTimeMillis())
3817 .setColor(contextForUser.getColor(
3818 com.android.internal.R.color.system_notification_accent_color))
3819 .setContentTitle(contextForUser.getString(
3820 R.string.contentServiceSyncNotificationTitle))
3821 .setContentText(
3822 String.format(tooManyDeletesDescFormat.toString(), authorityName))
3823 .setContentIntent(pendingIntent)
3824 .build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003825 notification.flags |= Notification.FLAG_ONGOING_EVENT;
Chris Wren282cfef2017-03-27 15:01:44 -04003826 mNotificationMgr.notifyAsUser(
3827 Integer.toString(account.hashCode() ^ authority.hashCode()),
3828 SystemMessage.NOTE_SYNC_ERROR,
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003829 notification, user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 }
3831
3832 /**
3833 * Checks whether an activity exists on the system image for the given intent.
3834 *
3835 * @param intent The intent for an activity.
3836 * @return Whether or not an activity exists.
3837 */
3838 private boolean isActivityAvailable(Intent intent) {
3839 PackageManager pm = mContext.getPackageManager();
3840 List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
3841 int listSize = list.size();
3842 for (int i = 0; i < listSize; i++) {
3843 ResolveInfo resolveInfo = list.get(i);
3844 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
3845 != 0) {
3846 return true;
3847 }
3848 }
3849
3850 return false;
3851 }
3852
3853 public long insertStartSyncEvent(SyncOperation syncOperation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003854 final long now = System.currentTimeMillis();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003855 EventLog.writeEvent(2720,
3856 syncOperation.toEventLog(SyncStorageEngine.EVENT_START));
3857 return mSyncStorageEngine.insertStartSyncEvent(syncOperation, now);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003858 }
3859
3860 public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003861 int upstreamActivity, int downstreamActivity, long elapsedTime) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003862 EventLog.writeEvent(2720,
3863 syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
Fred Quintana77c560f2010-03-29 22:20:26 -07003864 mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08003865 resultMessage, downstreamActivity, upstreamActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003866 }
3867 }
Fred Quintana918339a2010-10-05 14:00:39 -07003868
Matthew Williams8b76d202015-05-03 18:16:25 -07003869 private boolean isSyncStillActiveH(ActiveSyncContext activeSyncContext) {
Fred Quintana918339a2010-10-05 14:00:39 -07003870 for (ActiveSyncContext sync : mActiveSyncContexts) {
3871 if (sync == activeSyncContext) {
3872 return true;
3873 }
3874 }
3875 return false;
3876 }
Alon Albert57286f92012-10-09 14:21:38 -07003877
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003878 /**
3879 * Sync extra comparison function.
3880 * @param b1 bundle to compare
3881 * @param b2 other bundle to compare
3882 * @param includeSyncSettings if false, ignore system settings in bundle.
3883 */
3884 public static boolean syncExtrasEquals(Bundle b1, Bundle b2, boolean includeSyncSettings) {
3885 if (b1 == b2) {
3886 return true;
3887 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003888 // Exit early if we can.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003889 if (includeSyncSettings && b1.size() != b2.size()) {
3890 return false;
3891 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003892 Bundle bigger = b1.size() > b2.size() ? b1 : b2;
3893 Bundle smaller = b1.size() > b2.size() ? b2 : b1;
3894 for (String key : bigger.keySet()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003895 if (!includeSyncSettings && isSyncSetting(key)) {
3896 continue;
3897 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003898 if (!smaller.containsKey(key)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003899 return false;
3900 }
Matthew Williams9ad2c842015-10-16 12:01:31 -07003901 if (!Objects.equals(bigger.get(key), smaller.get(key))) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003902 return false;
3903 }
3904 }
3905 return true;
3906 }
3907
3908 /**
3909 * @return true if the provided key is used by the SyncManager in scheduling the sync.
3910 */
3911 private static boolean isSyncSetting(String key) {
3912 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
3913 return true;
3914 }
3915 if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
3916 return true;
3917 }
3918 if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF)) {
3919 return true;
3920 }
3921 if (key.equals(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY)) {
3922 return true;
3923 }
3924 if (key.equals(ContentResolver.SYNC_EXTRAS_MANUAL)) {
3925 return true;
3926 }
3927 if (key.equals(ContentResolver.SYNC_EXTRAS_UPLOAD)) {
3928 return true;
3929 }
3930 if (key.equals(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS)) {
3931 return true;
3932 }
3933 if (key.equals(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS)) {
3934 return true;
3935 }
3936 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD)) {
3937 return true;
3938 }
3939 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD)) {
3940 return true;
3941 }
3942 if (key.equals(ContentResolver.SYNC_EXTRAS_PRIORITY)) {
3943 return true;
3944 }
3945 if (key.equals(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED)) {
3946 return true;
3947 }
3948 if (key.equals(ContentResolver.SYNC_EXTRAS_INITIALIZE)) {
3949 return true;
3950 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08003951// if (key.equals(ContentResolver.SYNC_EXTRAS_APP_STANDBY_EXEMPTED)) {
3952// return true;
3953// }
3954 // No need to check virtual flags such as SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003955 return false;
3956 }
3957
Alon Albert57286f92012-10-09 14:21:38 -07003958 static class PrintTable {
Makoto Onuki15e7a252017-06-08 17:12:05 -07003959 private ArrayList<String[]> mTable = Lists.newArrayList();
Alon Albert57286f92012-10-09 14:21:38 -07003960 private final int mCols;
3961
3962 PrintTable(int cols) {
3963 mCols = cols;
3964 }
3965
3966 void set(int row, int col, Object... values) {
3967 if (col + values.length > mCols) {
3968 throw new IndexOutOfBoundsException("Table only has " + mCols +
3969 " columns. can't set " + values.length + " at column " + col);
3970 }
3971 for (int i = mTable.size(); i <= row; i++) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07003972 final String[] list = new String[mCols];
Alon Albert57286f92012-10-09 14:21:38 -07003973 mTable.add(list);
3974 for (int j = 0; j < mCols; j++) {
3975 list[j] = "";
3976 }
3977 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07003978 final String[] rowArray = mTable.get(row);
3979 for (int i = 0; i < values.length; i++) {
3980 final Object value = values[i];
3981 rowArray[col + i] = (value == null) ? "" : value.toString();
3982 }
Alon Albert57286f92012-10-09 14:21:38 -07003983 }
3984
3985 void writeTo(PrintWriter out) {
3986 final String[] formats = new String[mCols];
3987 int totalLength = 0;
3988 for (int col = 0; col < mCols; ++col) {
3989 int maxLength = 0;
3990 for (Object[] row : mTable) {
3991 final int length = row[col].toString().length();
3992 if (length > maxLength) {
3993 maxLength = length;
3994 }
3995 }
3996 totalLength += maxLength;
3997 formats[col] = String.format("%%-%ds", maxLength);
3998 }
Patrick Tjin31068162014-01-30 13:28:46 -08003999 formats[mCols - 1] = "%s";
Alon Albert57286f92012-10-09 14:21:38 -07004000 printRow(out, formats, mTable.get(0));
4001 totalLength += (mCols - 1) * 2;
4002 for (int i = 0; i < totalLength; ++i) {
4003 out.print("-");
4004 }
4005 out.println();
4006 for (int i = 1, mTableSize = mTable.size(); i < mTableSize; i++) {
4007 Object[] row = mTable.get(i);
4008 printRow(out, formats, row);
4009 }
4010 }
4011
4012 private void printRow(PrintWriter out, String[] formats, Object[] row) {
4013 for (int j = 0, rowLength = row.length; j < rowLength; j++) {
4014 out.printf(String.format(formats[j], row[j].toString()));
4015 out.print(" ");
4016 }
4017 out.println();
4018 }
4019
4020 public int getNumRows() {
4021 return mTable.size();
4022 }
4023 }
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004024
4025 private Context getContextForUser(UserHandle user) {
4026 try {
4027 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
4028 } catch (NameNotFoundException e) {
4029 // Default to mContext, not finding the package system is running as is unlikely.
4030 return mContext;
4031 }
4032 }
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004033
4034 private void cancelJob(SyncOperation op, String why) {
4035 if (op == null) {
4036 Slog.wtf(TAG, "Null sync operation detected.");
4037 return;
4038 }
4039 if (op.isPeriodic) {
4040 mLogger.log("Removing periodic sync ", op, " for ", why);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004041 }
4042 getJobScheduler().cancel(op.jobId);
4043 }
4044
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004045 private void wtfWithLog(String message) {
4046 Slog.wtf(TAG, message);
4047 mLogger.log("WTF: ", message);
4048 }
Makoto Onuki94986212018-04-11 16:24:46 -07004049
4050 public void resetTodayStats() {
4051 mSyncStorageEngine.resetTodayStats(/*force=*/ true);
4052 }
Makoto Onuki850045d2018-08-09 11:31:14 -07004053
4054 private boolean wasPackageEverLaunched(String packageName, int userId) {
4055 try {
4056 return mPackageManagerInternal.wasPackageEverLaunched(packageName, userId);
4057 } catch (IllegalArgumentException e) {
4058 return false; // Package has been removed.
4059 }
4060 }
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004061}