blob: 132bf0bc997865707e1848b3b27629ef6c1d8081 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.content;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Makoto Onuki5fc60022019-01-15 09:34:05 -080019import static com.android.server.content.SyncLogger.logSafe;
20
Alon Alberte0bde332011-09-22 14:26:16 -070021import android.accounts.Account;
Amith Yamasanif29f2362012-04-05 18:29:52 -070022import android.accounts.AccountAndUser;
Alon Alberte0bde332011-09-22 14:26:16 -070023import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070024import android.accounts.AccountManagerInternal;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080025import android.annotation.NonNull;
26import android.annotation.UserIdInt;
Fred Quintana33e44692011-12-05 15:04:16 -080027import android.app.ActivityManager;
Amith Yamasani9422bdc2013-04-10 16:58:19 -070028import android.app.AppGlobals;
Alon Alberte0bde332011-09-22 14:26:16 -070029import android.app.Notification;
30import android.app.NotificationManager;
31import android.app.PendingIntent;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000032import android.app.job.JobInfo;
33import android.app.job.JobScheduler;
Makoto Onuki75ad2492018-03-28 14:42:42 -070034import android.app.usage.UsageStatsManagerInternal;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080035import android.content.BroadcastReceiver;
36import android.content.ComponentName;
37import android.content.ContentResolver;
Makoto Onuki75ad2492018-03-28 14:42:42 -070038import android.content.ContentResolver.SyncExemption;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080039import android.content.Context;
40import android.content.ISyncAdapter;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080041import android.content.ISyncAdapterUnsyncableAccountCallback;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080042import android.content.ISyncContext;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080043import android.content.Intent;
44import android.content.IntentFilter;
Matthew Williamsfa774182013-06-18 15:44:11 -070045import android.content.PeriodicSync;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080046import android.content.ServiceConnection;
47import android.content.SyncActivityTooManyDeletes;
48import android.content.SyncAdapterType;
49import android.content.SyncAdaptersCache;
50import android.content.SyncInfo;
51import android.content.SyncResult;
52import android.content.SyncStatusInfo;
Makoto Onuki94986212018-04-11 16:24:46 -070053import android.content.SyncStatusInfo.Stats;
Alon Alberte0bde332011-09-22 14:26:16 -070054import android.content.pm.ApplicationInfo;
Amith Yamasani9422bdc2013-04-10 16:58:19 -070055import android.content.pm.PackageInfo;
Alon Alberte0bde332011-09-22 14:26:16 -070056import android.content.pm.PackageManager;
Todd Kennedy0eb97382017-10-03 16:57:22 -070057import android.content.pm.PackageManager.NameNotFoundException;
Makoto Onukid4764302018-03-30 17:32:57 -070058import android.content.pm.PackageManagerInternal;
Alon Alberte0bde332011-09-22 14:26:16 -070059import android.content.pm.ProviderInfo;
60import android.content.pm.RegisteredServicesCache;
61import android.content.pm.RegisteredServicesCacheListener;
62import android.content.pm.ResolveInfo;
Amith Yamasani04e0d262012-02-14 11:50:53 -080063import android.content.pm.UserInfo;
Matthew Williams8b76d202015-05-03 18:16:25 -070064import android.database.ContentObserver;
Alon Alberte0bde332011-09-22 14:26:16 -070065import android.net.ConnectivityManager;
66import android.net.NetworkInfo;
Matthew Williams1967c8d2015-06-19 19:03:13 -070067import android.net.TrafficStats;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080068import android.os.BatteryStats;
Makoto Onukibbf6d8c2017-08-11 12:11:39 -070069import android.os.Binder;
Makoto Onukidd4b14f2017-08-17 14:03:48 -070070import android.os.Build;
Fred Quintana918339a2010-10-05 14:00:39 -070071import android.os.Bundle;
72import android.os.Handler;
Makoto Onukie08a5c22018-04-27 13:28:46 -070073import android.os.HandlerThread;
Fred Quintana918339a2010-10-05 14:00:39 -070074import android.os.IBinder;
75import android.os.Looper;
76import android.os.Message;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000077import android.os.Messenger;
Fred Quintana918339a2010-10-05 14:00:39 -070078import android.os.PowerManager;
Makoto Onuki75ad2492018-03-28 14:42:42 -070079import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070080import android.os.RemoteCallback;
Fred Quintana918339a2010-10-05 14:00:39 -070081import android.os.RemoteException;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080082import android.os.ServiceManager;
Fred Quintana918339a2010-10-05 14:00:39 -070083import android.os.SystemClock;
84import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070085import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070086import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070087import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.text.format.Time;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.util.EventLog;
91import android.util.Log;
Fred Quintana307da1a2010-01-21 14:24:20 -080092import android.util.Pair;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000093import android.util.Slog;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000094
Alon Albert8e285552012-09-17 15:05:27 -070095import com.android.internal.R;
Makoto Onuki056a9752018-05-08 15:21:56 -070096import com.android.internal.annotations.GuardedBy;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080097import com.android.internal.app.IBatteryStats;
Makoto Onukid4764302018-03-30 17:32:57 -070098import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
99import com.android.internal.notification.SystemNotificationChannels;
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700100import com.android.internal.os.BackgroundThread;
Makoto Onukid4764302018-03-30 17:32:57 -0700101import com.android.internal.util.ArrayUtils;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700102import com.android.internal.util.IndentingPrintWriter;
Makoto Onuki94986212018-04-11 16:24:46 -0700103import com.android.internal.util.function.QuadConsumer;
Makoto Onukid4764302018-03-30 17:32:57 -0700104import com.android.server.DeviceIdleController;
105import com.android.server.LocalServices;
106import com.android.server.SystemService;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800107import com.android.server.accounts.AccountManagerService;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000108import com.android.server.backup.AccountSyncSettingsBackupHelper;
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700109import com.android.server.content.SyncStorageEngine.AuthorityInfo;
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700110import com.android.server.content.SyncStorageEngine.EndPoint;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800111import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
Makoto Onukid4764302018-03-30 17:32:57 -0700112import com.android.server.job.JobSchedulerInternal;
113
114import com.google.android.collect.Lists;
115import com.google.android.collect.Maps;
Alon Albert8e285552012-09-17 15:05:27 -0700116
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import java.io.PrintWriter;
119import java.util.ArrayList;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000120import java.util.Arrays;
Fred Quintana918339a2010-10-05 14:00:39 -0700121import java.util.Collection;
122import java.util.Collections;
Alon Alberte0bde332011-09-22 14:26:16 -0700123import java.util.Comparator;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000124import java.util.HashMap;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000125import java.util.HashSet;
126import java.util.List;
127import java.util.Map;
Matthew Williams9ad2c842015-10-16 12:01:31 -0700128import java.util.Objects;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000129import java.util.Random;
130import java.util.Set;
Makoto Onuki94986212018-04-11 16:24:46 -0700131import java.util.function.Function;
Makoto Onuki15e7a252017-06-08 17:12:05 -0700132import java.util.function.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133
134/**
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000135 * Implementation details:
136 * All scheduled syncs will be passed on to JobScheduler as jobs
137 * (See {@link #scheduleSyncOperationH(SyncOperation, long)}. This function schedules a job
138 * with JobScheduler with appropriate delay and constraints (according to backoffs and extras).
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000139 * The scheduleSyncOperationH function also assigns a unique jobId to each
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000140 * SyncOperation.
141 *
142 * Periodic Syncs:
143 * Each periodic sync is scheduled as a periodic job. If a periodic sync fails, we create a new
144 * one off SyncOperation and set its {@link SyncOperation#sourcePeriodicId} field to the jobId of the
145 * periodic sync. We don't allow the periodic job to run while any job initiated by it is pending.
146 *
147 * Backoffs:
148 * Each {@link EndPoint} has a backoff associated with it. When a SyncOperation fails, we increase
149 * the backoff on the authority. Then we reschedule all syncs associated with that authority to
150 * run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
151 * are rescheduled. A rescheduled sync will get a new jobId.
152 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 * @hide
154 */
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700155public class SyncManager {
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700156 static final String TAG = "SyncManager";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700158 private static final boolean DEBUG_ACCOUNT_ACCESS = false;
159
Makoto Onukib47e8942017-09-18 14:03:03 -0700160 // Only do the check on a debuggable build.
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700161 private static final boolean ENABLE_SUSPICIOUS_CHECK = Build.IS_DEBUGGABLE;
162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 /** Delay a sync due to local changes this long. In milliseconds */
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700164 private static final long LOCAL_SYNC_DELAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700166 static {
Fred Quintana918339a2010-10-05 14:00:39 -0700167 LOCAL_SYNC_DELAY =
168 SystemProperties.getLong("sync.local_sync_delay", 30 * 1000 /* 30 seconds */);
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700169 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 /**
Fred Quintana8570f742010-02-18 10:32:54 -0800172 * How long to wait before retrying a sync that failed due to one already being in progress.
173 */
174 private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
175
Matthew Williams92a1c092014-08-25 19:18:32 -0700176 /**
Matthew Williams1967c8d2015-06-19 19:03:13 -0700177 * How often to periodically poll network traffic for an adapter performing a sync to determine
178 * whether progress is being made.
179 */
180 private static final long SYNC_MONITOR_WINDOW_LENGTH_MILLIS = 60 * 1000; // 60 seconds
181
182 /**
183 * How many bytes must be transferred (Tx + Rx) over the period of time defined by
184 * {@link #SYNC_MONITOR_WINDOW_LENGTH_MILLIS} for the sync to be considered to be making
185 * progress.
186 */
187 private static final int SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES = 10; // 10 bytes
188
189 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000190 * If a previously scheduled sync becomes ready and we are low on storage, it gets
191 * pushed back for this amount of time.
192 */
193 private static final long SYNC_DELAY_ON_LOW_STORAGE = 60*60*1000; // 1 hour
194
195 /**
196 * If a sync becomes ready and it conflicts with an already running sync, it gets
197 * pushed back for this amount of time.
198 */
199 private static final long SYNC_DELAY_ON_CONFLICT = 10*1000; // 10 seconds
Fred Quintana3ec47302010-03-10 10:08:31 -0800200
Shreyas Basargefa272532016-03-09 16:52:48 +0000201 /**
202 * Generate job ids in the range [MIN_SYNC_JOB_ID, MAX_SYNC_JOB_ID) to avoid conflicts with
203 * other jobs scheduled by the system process.
204 */
205 private static final int MIN_SYNC_JOB_ID = 100000;
206 private static final int MAX_SYNC_JOB_ID = 110000;
207
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800208 private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/";
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700209 private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
Fred Quintana918339a2010-10-05 14:00:39 -0700210 private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
211
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700212
213 private static final int SYNC_OP_STATE_VALID = 0;
214 private static final int SYNC_OP_STATE_INVALID = 1;
215 private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
216
Philip P. Moltmann486b2412018-01-03 11:29:01 -0800217 /** Flags used when connecting to a sync adapter service */
218 private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
219 | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
220
Makoto Onuki056a9752018-05-08 15:21:56 -0700221 /** Singleton instance. */
222 @GuardedBy("SyncManager.class")
223 private static SyncManager sInstance;
224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226
Amith Yamasani04e0d262012-02-14 11:50:53 -0800227 private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
228
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700229 // TODO: add better locking around mRunningAccounts
230 private volatile AccountAndUser[] mRunningAccounts = INITIAL_ACCOUNTS_ARRAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
Fred Quintana918339a2010-10-05 14:00:39 -0700233 volatile private PowerManager.WakeLock mSyncManagerWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 volatile private boolean mDataConnectionIsConnected = false;
235 volatile private boolean mStorageIsLow = false;
Dianne Hackborn4870e9d2015-04-08 16:55:47 -0700236 volatile private boolean mDeviceIsIdle = false;
Dianne Hackborn627dfa12015-11-11 18:10:30 -0800237 volatile private boolean mReportedSyncActive = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 private final NotificationManager mNotificationMgr;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800240 private final IBatteryStats mBatteryStats;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000241 private JobScheduler mJobScheduler;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000242 private JobSchedulerInternal mJobSchedulerInternal;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000243 private SyncJobService mSyncJobService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700245 private SyncStorageEngine mSyncStorageEngine;
Jeff Sharkeya706e2f2012-10-16 12:02:42 -0700246
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700247 protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248
Fred Quintanaf892fb32009-08-27 21:32:08 -0700249 // Synchronized on "this". Instead of using this directly one should instead call
250 // its accessor, getConnManager().
251 private ConnectivityManager mConnManagerDoNotUseDirectly;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
Matthew Williams8b76d202015-05-03 18:16:25 -0700253 /** Track whether the device has already been provisioned. */
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000254 private volatile boolean mProvisioned;
Matthew Williams8b76d202015-05-03 18:16:25 -0700255
Makoto Onuki94986212018-04-11 16:24:46 -0700256 protected final SyncAdaptersCache mSyncAdapters;
Fred Quintana718d8a22009-04-29 17:53:20 -0700257
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000258 private final Random mRand;
259
Makoto Onukia9dca242017-06-21 17:06:49 -0700260 private final SyncLogger mLogger;
261
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000262 private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
263 for (JobInfo job: pendingJobs) {
264 if (job.getId() == jobId) {
265 return true;
266 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000267 }
268 for (ActiveSyncContext asc: mActiveSyncContexts) {
269 if (asc.mSyncOperation.jobId == jobId) {
270 return true;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000271 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000272 }
273 return false;
274 }
275
276 private int getUnusedJobIdH() {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000277 int newJobId;
278 do {
279 newJobId = MIN_SYNC_JOB_ID + mRand.nextInt(MAX_SYNC_JOB_ID - MIN_SYNC_JOB_ID);
280 } while (isJobIdInUseLockedH(newJobId,
281 mJobSchedulerInternal.getSystemScheduledPendingJobs()));
282 return newJobId;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000283 }
284
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000285 private List<SyncOperation> getAllPendingSyncs() {
286 verifyJobScheduler();
287 List<JobInfo> pendingJobs = mJobSchedulerInternal.getSystemScheduledPendingJobs();
288 List<SyncOperation> pendingSyncs = new ArrayList<SyncOperation>(pendingJobs.size());
289 for (JobInfo job: pendingJobs) {
290 SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
291 if (op != null) {
292 pendingSyncs.add(op);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000293 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000294 }
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000295 return pendingSyncs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000296 }
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700297
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700298 private final BroadcastReceiver mStorageIntentReceiver =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700300 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 public void onReceive(Context context, Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 String action = intent.getAction();
303 if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
304 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000305 Slog.v(TAG, "Internal storage is low.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 }
307 mStorageIsLow = true;
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700308 cancelActiveSync(
309 SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
Makoto Onukia9dca242017-06-21 17:06:49 -0700310 null /* any sync */,
311 "storage low");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
313 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000314 Slog.v(TAG, "Internal storage is ok.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316 mStorageIsLow = false;
Makoto Onukia9dca242017-06-21 17:06:49 -0700317 rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
318 "storage ok");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
320 }
321 };
322
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700323 private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700324 @Override
Fred Quintana60307342009-03-24 22:48:12 -0700325 public void onReceive(Context context, Intent intent) {
Matthew Williams8b76d202015-05-03 18:16:25 -0700326 mBootCompleted = true;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000327 // Called because it gets all pending jobs and stores them in mScheduledSyncs cache.
328 verifyJobScheduler();
Fred Quintanae91ebe22009-09-29 20:44:30 -0700329 mSyncHandler.onBootCompleted();
Fred Quintana60307342009-03-24 22:48:12 -0700330 }
331 };
332
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700333 private final BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700334 @Override
Amith Yamasanid648a602012-09-26 15:06:10 -0700335 public void onReceive(Context context, Intent intent) {
Makoto Onukifb636cc2017-12-07 15:46:26 -0800336 EndPoint target = new EndPoint(null, null, getSendingUserId());
Shreyas Basargedcb88c82016-02-03 00:09:18 +0000337 updateRunningAccounts(target /* sync targets for user */);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700338 }
339 };
340
Fred Quintanab3029c32010-04-06 13:27:12 -0700341 private final PowerManager mPowerManager;
Ashish Sharma69d95de2012-04-11 17:27:24 -0700342
Amith Yamasani9535c912012-10-10 21:48:33 -0700343 private final UserManager mUserManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700344
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700345 private final AccountManager mAccountManager;
346
347 private final AccountManagerInternal mAccountManagerInternal;
348
Svet Ganov973edd192016-09-08 20:15:55 -0700349 private final PackageManagerInternal mPackageManagerInternal;
350
Amith Yamasani258848d2012-08-10 17:06:33 -0700351 private List<UserInfo> getAllUsers() {
Amith Yamasani9535c912012-10-10 21:48:33 -0700352 return mUserManager.getUsers();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800353 }
354
355 private boolean containsAccountAndUser(AccountAndUser[] accounts, Account account, int userId) {
356 boolean found = false;
357 for (int i = 0; i < accounts.length; i++) {
358 if (accounts[i].userId == userId
359 && accounts[i].account.equals(account)) {
360 found = true;
361 break;
362 }
363 }
364 return found;
365 }
366
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000367 /** target indicates endpoints that should be synced after account info is updated. */
368 private void updateRunningAccounts(EndPoint target) {
369 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_ACCOUNTS_UPDATED");
振淦王60a74312015-12-01 16:37:31 +0800370 // Update accounts in handler thread.
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000371 Message m = mSyncHandler.obtainMessage(SyncHandler.MESSAGE_ACCOUNTS_UPDATED);
372 m.obj = target;
373 m.sendToTarget();
Fred Quintanad9d2f112009-04-23 13:36:27 -0700374 }
375
Jeff Sharkey8f55d112012-10-11 11:00:21 -0700376 private void doDatabaseCleanup() {
Amith Yamasanidb6a14c2012-10-17 21:16:52 -0700377 for (UserInfo user : mUserManager.getUsers(true)) {
378 // Skip any partially created/removed users
379 if (user.partial) continue;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700380 Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(
381 user.id, mContext.getOpPackageName());
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000382
Jeff Sharkey8f55d112012-10-11 11:00:21 -0700383 mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
384 }
385 }
386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 private BroadcastReceiver mConnectivityIntentReceiver =
388 new BroadcastReceiver() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000389 @Override
390 public void onReceive(Context context, Intent intent) {
391 final boolean wasConnected = mDataConnectionIsConnected;
Alon Alberted1d2532011-02-15 14:02:14 -0800392
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000393 // Don't use the intent to figure out if network is connected, just check
394 // ConnectivityManager directly.
395 mDataConnectionIsConnected = readDataConnectionState();
396 if (mDataConnectionIsConnected) {
397 if (!wasConnected) {
398 if (Log.isLoggable(TAG, Log.VERBOSE)) {
399 Slog.v(TAG, "Reconnection detected: clearing all backoffs");
400 }
Makoto Onukia9dca242017-06-21 17:06:49 -0700401 // Note the location of this code was wrong from nyc to oc; fixed in DR.
402 clearAllBackoffs("network reconnect");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000403 }
Matthew Williams119aac92014-09-28 20:42:23 -0700404 }
Alon Alberted1d2532011-02-15 14:02:14 -0800405 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000406 };
407
Makoto Onukia9dca242017-06-21 17:06:49 -0700408 private void clearAllBackoffs(String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000409 mSyncStorageEngine.clearAllBackoffsLocked();
Makoto Onukia9dca242017-06-21 17:06:49 -0700410 rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000411 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412
Alon Albert1bad83a2011-02-16 10:29:56 -0800413 private boolean readDataConnectionState() {
Alon Alberted1d2532011-02-15 14:02:14 -0800414 NetworkInfo networkInfo = getConnectivityManager().getActiveNetworkInfo();
415 return (networkInfo != null) && networkInfo.isConnected();
416 }
417
Makoto Onukie7b02982017-08-24 14:23:36 -0700418 private String getJobStats() {
419 JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
420 return "JobStats: "
421 + ((js == null) ? "(JobSchedulerInternal==null)"
422 : js.getPersistStats().toString());
423 }
424
Dianne Hackborn55280a92009-05-07 15:53:46 -0700425 private BroadcastReceiver mShutdownIntentReceiver =
426 new BroadcastReceiver() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000427 @Override
428 public void onReceive(Context context, Intent intent) {
429 Log.w(TAG, "Writing sync state before shutdown...");
430 getSyncStorageEngine().writeAllState();
Makoto Onukie7b02982017-08-24 14:23:36 -0700431
432 mLogger.log(getJobStats());
Makoto Onukife224e02017-06-29 14:11:14 -0700433 mLogger.log("Shutting down.");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000434 }
435 };
Dianne Hackborn55280a92009-05-07 15:53:46 -0700436
Makoto Onuki94986212018-04-11 16:24:46 -0700437 private final BroadcastReceiver mOtherIntentsReceiver =
438 new BroadcastReceiver() {
439 @Override
440 public void onReceive(Context context, Intent intent) {
441 if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
442 mSyncStorageEngine.setClockValid();
443 return;
444 }
445 }
446 };
447
Amith Yamasani13593602012-03-22 16:16:17 -0700448 private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
449 @Override
450 public void onReceive(Context context, Intent intent) {
Alon Albert8e285552012-09-17 15:05:27 -0700451 String action = intent.getAction();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700452 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
453 if (userId == UserHandle.USER_NULL) return;
454
Alon Albert8e285552012-09-17 15:05:27 -0700455 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700456 onUserRemoved(userId);
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700457 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
458 onUserUnlocked(userId);
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -0700459 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
460 onUserStopped(userId);
Alon Albert8e285552012-09-17 15:05:27 -0700461 }
Amith Yamasani13593602012-03-22 16:16:17 -0700462 }
463 };
464
Makoto Onukie08a5c22018-04-27 13:28:46 -0700465 private final HandlerThread mThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 private final SyncHandler mSyncHandler;
Makoto Onukiaad2b512018-02-07 09:31:46 -0800467 private final SyncManagerConstants mConstants;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468
Fred Quintana4f9cfc52009-09-02 15:20:23 -0700469 private volatile boolean mBootCompleted = false;
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +0100470 private volatile boolean mJobServiceReady = false;
Fred Quintana4f9cfc52009-09-02 15:20:23 -0700471
Fred Quintanaf892fb32009-08-27 21:32:08 -0700472 private ConnectivityManager getConnectivityManager() {
473 synchronized (this) {
474 if (mConnManagerDoNotUseDirectly == null) {
475 mConnManagerDoNotUseDirectly = (ConnectivityManager)mContext.getSystemService(
476 Context.CONNECTIVITY_SERVICE);
477 }
478 return mConnManagerDoNotUseDirectly;
479 }
480 }
481
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000482 /**
483 * Cancel all unnecessary jobs. This function will be run once after every boot.
484 */
485 private void cleanupJobs() {
486 // O(n^2) in number of jobs, so we run this on the background thread.
487 mSyncHandler.postAtFrontOfQueue(new Runnable() {
488 @Override
489 public void run() {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000490 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000491 Set<String> cleanedKeys = new HashSet<String>();
492 for (SyncOperation opx: ops) {
493 if (cleanedKeys.contains(opx.key)) {
494 continue;
495 }
496 cleanedKeys.add(opx.key);
497 for (SyncOperation opy: ops) {
498 if (opx == opy) {
499 continue;
500 }
501 if (opx.key.equals(opy.key)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700502 mLogger.log("Removing duplicate sync: ", opy);
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700503 cancelJob(opy, "cleanupJobs() x=" + opx + " y=" + opy);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000504 }
505 }
506 }
507 }
508 });
509 }
510
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000511 private synchronized void verifyJobScheduler() {
512 if (mJobScheduler != null) {
513 return;
514 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700515 final long token = Binder.clearCallingIdentity();
516 try {
517 if (Log.isLoggable(TAG, Log.VERBOSE)) {
518 Log.d(TAG, "initializing JobScheduler object.");
519 }
520 mJobScheduler = (JobScheduler) mContext.getSystemService(
521 Context.JOB_SCHEDULER_SERVICE);
522 mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
523 // Get all persisted syncs from JobScheduler
524 List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
525
526 int numPersistedPeriodicSyncs = 0;
527 int numPersistedOneshotSyncs = 0;
528 for (JobInfo job : pendingJobs) {
529 SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
530 if (op != null) {
531 if (op.isPeriodic) {
532 numPersistedPeriodicSyncs++;
533 } else {
534 numPersistedOneshotSyncs++;
535 // Set the pending status of this EndPoint to true. Pending icon is
536 // shown on the settings activity.
537 mSyncStorageEngine.markPending(op.target, true);
538 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000539 }
540 }
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700541 final String summary = "Loaded persisted syncs: "
542 + numPersistedPeriodicSyncs + " periodic syncs, "
543 + numPersistedOneshotSyncs + " oneshot syncs, "
544 + (pendingJobs.size()) + " total system server jobs, "
Makoto Onukie7b02982017-08-24 14:23:36 -0700545 + getJobStats();
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700546 Slog.i(TAG, summary);
547 mLogger.log(summary);
548
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700549 cleanupJobs();
550
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700551 if (ENABLE_SUSPICIOUS_CHECK &&
552 (numPersistedPeriodicSyncs == 0) && likelyHasPeriodicSyncs()) {
553 Slog.wtf(TAG, "Device booted with no persisted periodic syncs: " + summary);
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700554 }
555 } finally {
556 Binder.restoreCallingIdentity(token);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000557 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700558 }
559
560 /**
561 * @return whether the device most likely has some periodic syncs.
562 */
563 private boolean likelyHasPeriodicSyncs() {
564 try {
Makoto Onukib47e8942017-09-18 14:03:03 -0700565 // Each sync adapter has a daily periodic sync by default, but sync adapters can remove
566 // them by themselves. So here, we use an arbitrary threshold. If there are more than
567 // this many sync endpoints, surely one of them should have a periodic sync...
568 return mSyncStorageEngine.getAuthorityCount() >= 6;
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700569 } catch (Throwable th) {
570 // Just in case.
571 }
572 return false;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000573 }
574
575 private JobScheduler getJobScheduler() {
576 verifyJobScheduler();
577 return mJobScheduler;
578 }
579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 public SyncManager(Context context, boolean factoryTest) {
Makoto Onuki056a9752018-05-08 15:21:56 -0700581 synchronized (SyncManager.class) {
582 if (sInstance == null) {
583 sInstance = this;
584 } else {
585 Slog.wtf(TAG, "SyncManager instantiated multiple times");
586 }
587 }
588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 // Initialize the SyncStorageEngine first, before registering observers
590 // and creating threads and so on; it may fail if the disk is full.
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700591 mContext = context;
Amith Yamasani9535c912012-10-10 21:48:33 -0700592
Makoto Onukia9dca242017-06-21 17:06:49 -0700593 mLogger = SyncLogger.getInstance();
594
Makoto Onuki6963bea72017-12-12 10:42:39 -0800595 SyncStorageEngine.init(context, BackgroundThread.get().getLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 mSyncStorageEngine = SyncStorageEngine.getSingleton();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800597 mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700598 @Override
Makoto Onuki61283ec2018-01-31 17:22:36 -0800599 public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700600 @SyncExemption int syncExemptionFlag) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000601 scheduleSync(info.account, info.userId, reason, info.provider, extras,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700602 AuthorityInfo.UNDEFINED, syncExemptionFlag);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000603 }
604 });
605
606 mSyncStorageEngine.setPeriodicSyncAddedListener(
607 new SyncStorageEngine.PeriodicSyncAddedListener() {
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000608 @Override
609 public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
610 long flex) {
611 updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
612 }
613 });
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000614
615 mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
616 @Override
617 public void onAuthorityRemoved(EndPoint removedAuthority) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700618 removeSyncsForAuthority(removedAuthority, "onAuthorityRemoved");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800619 }
620 });
621
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700622 mSyncAdapters = new SyncAdaptersCache(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623
Makoto Onukie08a5c22018-04-27 13:28:46 -0700624 mThread = new HandlerThread("SyncManager", android.os.Process.THREAD_PRIORITY_BACKGROUND);
625 mThread.start();
626 mSyncHandler = new SyncHandler(mThread.getLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627
Fred Quintana44037e62010-01-21 13:14:49 -0800628 mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700629 @Override
630 public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
Fred Quintana44037e62010-01-21 13:14:49 -0800631 if (!removed) {
Alon Albert57286f92012-10-09 14:21:38 -0700632 scheduleSync(null, UserHandle.USER_ALL,
633 SyncOperation.REASON_SERVICE_CHANGED,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800634 type.authority, null, AuthorityInfo.UNDEFINED,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700635 ContentResolver.SYNC_EXEMPTION_NONE);
Fred Quintana44037e62010-01-21 13:14:49 -0800636 }
637 }
638 }, mSyncHandler);
Fred Quintana718d8a22009-04-29 17:53:20 -0700639
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000640 mRand = new Random(System.currentTimeMillis());
Makoto Onukiaad2b512018-02-07 09:31:46 -0800641 mConstants = new SyncManagerConstants(context);
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
644 context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
645
Fred Quintanae91ebe22009-09-29 20:44:30 -0700646 if (!factoryTest) {
647 intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Dianne Hackbornd83a0962014-05-02 16:28:33 -0700648 intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Fred Quintanae91ebe22009-09-29 20:44:30 -0700649 context.registerReceiver(mBootCompletedReceiver, intentFilter);
650 }
Fred Quintana60307342009-03-24 22:48:12 -0700651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
653 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
654 context.registerReceiver(mStorageIntentReceiver, intentFilter);
655
Dianne Hackborn55280a92009-05-07 15:53:46 -0700656 intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
657 intentFilter.setPriority(100);
658 context.registerReceiver(mShutdownIntentReceiver, intentFilter);
659
Amith Yamasani13593602012-03-22 16:16:17 -0700660 intentFilter = new IntentFilter();
661 intentFilter.addAction(Intent.ACTION_USER_REMOVED);
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700662 intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -0700663 intentFilter.addAction(Intent.ACTION_USER_STOPPED);
Alon Albert8e285552012-09-17 15:05:27 -0700664 mContext.registerReceiverAsUser(
665 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
Amith Yamasani13593602012-03-22 16:16:17 -0700666
Makoto Onuki94986212018-04-11 16:24:46 -0700667 intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
668 context.registerReceiver(mOtherIntentsReceiver, intentFilter);
669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 if (!factoryTest) {
671 mNotificationMgr = (NotificationManager)
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000672 context.getSystemService(Context.NOTIFICATION_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 } else {
674 mNotificationMgr = null;
675 }
Fred Quintanab3029c32010-04-06 13:27:12 -0700676 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
Amith Yamasani9535c912012-10-10 21:48:33 -0700677 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700678 mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
679 mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
Svet Ganov973edd192016-09-08 20:15:55 -0700680 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700681
Svet Ganovf6d424f12016-09-20 20:18:53 -0700682 mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
683 // If the UID gained access to the account kick-off syncs lacking account access
684 if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
685 scheduleSync(account, UserHandle.getUserId(uid),
686 SyncOperation.REASON_ACCOUNTS_UPDATED,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800687 null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700688 ContentResolver.SYNC_EXEMPTION_NONE);
Svet Ganovf6d424f12016-09-20 20:18:53 -0700689 }
690 });
691
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800692 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
693 BatteryStats.SERVICE_NAME));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694
695 // This WakeLock is used to ensure that we stay awake between the time that we receive
696 // a sync alarm notification and when we finish processing it. We need to do this
697 // because we don't do the work in the alarm handler, rather we do it in a message
698 // handler.
Fred Quintanab3029c32010-04-06 13:27:12 -0700699 mHandleAlarmWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 HANDLE_SYNC_ALARM_WAKE_LOCK);
701 mHandleAlarmWakeLock.setReferenceCounted(false);
702
Fred Quintana918339a2010-10-05 14:00:39 -0700703 // This WakeLock is used to ensure that we stay awake while running the sync loop
704 // message handler. Normally we will hold a sync adapter wake lock while it is being
705 // synced but during the execution of the sync loop it might finish a sync for
706 // one sync adapter before starting the sync for the other sync adapter and we
707 // don't want the device to go to sleep during that window.
708 mSyncManagerWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
709 SYNC_LOOP_WAKE_LOCK);
710 mSyncManagerWakeLock.setReferenceCounted(false);
711
Matthew Williams8b76d202015-05-03 18:16:25 -0700712 mProvisioned = isDeviceProvisioned();
713 if (!mProvisioned) {
714 final ContentResolver resolver = context.getContentResolver();
715 ContentObserver provisionedObserver =
716 new ContentObserver(null /* current thread */) {
717 public void onChange(boolean selfChange) {
718 mProvisioned |= isDeviceProvisioned();
719 if (mProvisioned) {
720 mSyncHandler.onDeviceProvisioned();
721 resolver.unregisterContentObserver(this);
722 }
723 }
724 };
725
726 synchronized (mSyncHandler) {
727 resolver.registerContentObserver(
728 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
729 false /* notifyForDescendents */,
730 provisionedObserver);
731
732 // The device *may* have been provisioned while we were registering above observer.
733 // Check again to make sure.
734 mProvisioned |= isDeviceProvisioned();
735 if (mProvisioned) {
736 resolver.unregisterContentObserver(provisionedObserver);
737 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700738 }
Matthew Williams8b76d202015-05-03 18:16:25 -0700739 }
Fred Quintanae91ebe22009-09-29 20:44:30 -0700740
741 if (!factoryTest) {
Amith Yamasanid648a602012-09-26 15:06:10 -0700742 // Register for account list updates for all users
743 mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
744 UserHandle.ALL,
745 new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
Matthew Williams5c6756f2014-10-02 04:12:28 +0000746 null, null);
Fred Quintanae91ebe22009-09-29 20:44:30 -0700747 }
Ashish Sharma69d95de2012-04-11 17:27:24 -0700748
Christopher Tate734c91d2016-02-02 12:46:18 -0800749 // Set up the communication channel between the scheduled job and the sync manager.
750 // This is posted to the *main* looper intentionally, to defer calling startService()
751 // until after the lengthy primary boot sequence completes on that thread, to avoid
752 // spurious ANR triggering.
753 final Intent startServiceIntent = new Intent(mContext, SyncJobService.class);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000754 startServiceIntent.putExtra(SyncJobService.EXTRA_MESSENGER, new Messenger(mSyncHandler));
Christopher Tate734c91d2016-02-02 12:46:18 -0800755 new Handler(mContext.getMainLooper()).post(new Runnable() {
756 @Override
757 public void run() {
758 mContext.startService(startServiceIntent);
759 }
760 });
Svet Ganov65712b02016-09-01 10:24:11 -0700761
762 // Sync adapters were able to access the synced account without the accounts
763 // permission which circumvents our permission model. Therefore, we require
764 // sync adapters that don't have access to the account to get user consent.
765 // This can be noisy, therefore we will white-list sync adapters installed
766 // before we started checking for account access because they already know
767 // the account (they run before) which is the genie is out of the bottle.
768 whiteListExistingSyncAdaptersIfNeeded();
Makoto Onukife224e02017-06-29 14:11:14 -0700769
Makoto Onukie7b02982017-08-24 14:23:36 -0700770 mLogger.log("Sync manager initialized: " + Build.FINGERPRINT);
Svet Ganov65712b02016-09-01 10:24:11 -0700771 }
772
Makoto Onukife224e02017-06-29 14:11:14 -0700773 public void onStartUser(int userHandle) {
Makoto Onukif15a9422017-12-11 15:50:58 -0800774 mSyncHandler.post(() -> mLogger.log("onStartUser: user=", userHandle));
Makoto Onukife224e02017-06-29 14:11:14 -0700775 }
776
777 public void onUnlockUser(int userHandle) {
Makoto Onukif15a9422017-12-11 15:50:58 -0800778 mSyncHandler.post(() -> mLogger.log("onUnlockUser: user=", userHandle));
Makoto Onukife224e02017-06-29 14:11:14 -0700779 }
780
781 public void onStopUser(int userHandle) {
Makoto Onukif15a9422017-12-11 15:50:58 -0800782 mSyncHandler.post(() -> mLogger.log("onStopUser: user=", userHandle));
Makoto Onukife224e02017-06-29 14:11:14 -0700783 }
784
Makoto Onukiaad2b512018-02-07 09:31:46 -0800785 public void onBootPhase(int phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800786 // Note SyncManager only receives PHASE_ACTIVITY_MANAGER_READY and after.
Makoto Onukiaad2b512018-02-07 09:31:46 -0800787 switch (phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800788 case SystemService.PHASE_ACTIVITY_MANAGER_READY:
Makoto Onukiaad2b512018-02-07 09:31:46 -0800789 mConstants.start();
790 break;
791 }
792 }
Makoto Onukife224e02017-06-29 14:11:14 -0700793
Svet Ganov65712b02016-09-01 10:24:11 -0700794 private void whiteListExistingSyncAdaptersIfNeeded() {
795 if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
796 return;
797 }
798 List<UserInfo> users = mUserManager.getUsers(true);
799 final int userCount = users.size();
800 for (int i = 0; i < userCount; i++) {
801 UserHandle userHandle = users.get(i).getUserHandle();
802 final int userId = userHandle.getIdentifier();
803 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
804 : mSyncAdapters.getAllServices(userId)) {
805 String packageName = service.componentName.getPackageName();
806 for (Account account : mAccountManager.getAccountsByTypeAsUser(
807 service.type.accountType, userHandle)) {
808 if (!canAccessAccount(account, packageName, userId)) {
809 mAccountManager.updateAppPermission(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700810 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
Svet Ganov65712b02016-09-01 10:24:11 -0700811 }
812 }
813 }
814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 }
816
Matthew Williams8b76d202015-05-03 18:16:25 -0700817 private boolean isDeviceProvisioned() {
818 final ContentResolver resolver = mContext.getContentResolver();
819 return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
820 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 /**
822 * Return a random value v that satisfies minValue <= v < maxValue. The difference between
823 * maxValue and minValue must be less than Integer.MAX_VALUE.
824 */
825 private long jitterize(long minValue, long maxValue) {
826 Random random = new Random(SystemClock.elapsedRealtime());
827 long spread = maxValue - minValue;
828 if (spread > Integer.MAX_VALUE) {
829 throw new IllegalArgumentException("the difference between the maxValue and the "
830 + "minValue must be less than " + Integer.MAX_VALUE);
831 }
832 return minValue + random.nextInt((int)spread);
833 }
834
Dianne Hackborn231cc602009-04-27 17:10:36 -0700835 public SyncStorageEngine getSyncStorageEngine() {
836 return mSyncStorageEngine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
Doug Zongker44f57472009-09-20 15:52:43 -0700838
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700839 private int getIsSyncable(Account account, int userId, String providerName) {
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700840 int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
841 UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
842
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000843 // If it's not a restricted user, return isSyncable.
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700844 if (userInfo == null || !userInfo.isRestricted()) return isSyncable;
845
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000846 // Else check if the sync adapter has opted-in or not.
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700847 RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
848 mSyncAdapters.getServiceInfo(
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000849 SyncAdapterType.newKey(providerName, account.type), userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700850 if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700851
852 PackageInfo pInfo = null;
853 try {
854 pInfo = AppGlobals.getPackageManager().getPackageInfo(
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000855 syncAdapterInfo.componentName.getPackageName(), 0, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700856 if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700857 } catch (RemoteException re) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000858 // Shouldn't happen.
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700859 return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700860 }
861 if (pInfo.restrictedAccountType != null
862 && pInfo.restrictedAccountType.equals(account.type)) {
863 return isSyncable;
864 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700865 return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700866 }
867 }
868
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000869 private void setAuthorityPendingState(EndPoint info) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000870 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000871 for (SyncOperation op: ops) {
872 if (!op.isPeriodic && op.target.matchesSpec(info)) {
873 getSyncStorageEngine().markPending(info, true);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700874 return;
875 }
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700876 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000877 getSyncStorageEngine().markPending(info, false);
Matthew Williamsfa774182013-06-18 15:44:11 -0700878 }
879
880 /**
881 * Initiate a sync. This can start a sync for all providers
882 * (pass null to url, set onlyTicklable to false), only those
883 * providers that are marked as ticklable (pass null to url,
884 * set onlyTicklable to true), or a specific provider (set url
885 * to the content url of the provider).
886 *
887 * <p>If the ContentResolver.SYNC_EXTRAS_UPLOAD boolean in extras is
888 * true then initiate a sync that just checks for local changes to send
889 * to the server, otherwise initiate a sync that first gets any
890 * changes from the server before sending local changes back to
891 * the server.
892 *
893 * <p>If a specific provider is being synced (the url is non-null)
894 * then the extras can contain SyncAdapter-specific information
895 * to control what gets synced (e.g. which specific feed to sync).
896 *
897 * <p>You'll start getting callbacks after this.
898 *
899 * @param requestedAccount the account to sync, may be null to signify all accounts
900 * @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
901 * then all users' accounts are considered.
902 * @param reason for sync request. If this is a positive integer, it is the Linux uid
903 * assigned to the process that requested the sync. If it's negative, the sync was requested by
904 * the SyncManager itself and could be one of the following:
905 * {@link SyncOperation#REASON_BACKGROUND_DATA_SETTINGS_CHANGED}
906 * {@link SyncOperation#REASON_ACCOUNTS_UPDATED}
907 * {@link SyncOperation#REASON_SERVICE_CHANGED}
908 * {@link SyncOperation#REASON_PERIODIC}
909 * {@link SyncOperation#REASON_IS_SYNCABLE}
910 * {@link SyncOperation#REASON_SYNC_AUTO}
911 * {@link SyncOperation#REASON_MASTER_SYNC_AUTO}
912 * {@link SyncOperation#REASON_USER_START}
913 * @param requestedAuthority the authority to sync, may be null to indicate all authorities
914 * @param extras a Map of SyncAdapter-specific information to control
915 * syncs of a specific provider. Can be null. Is ignored
916 * if the url is null.
Svet Ganovf6d424f12016-09-20 20:18:53 -0700917 * @param targetSyncState Only sync authorities that have the specified sync state.
918 * Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
Matthew Williamsfa774182013-06-18 15:44:11 -0700919 */
920 public void scheduleSync(Account requestedAccount, int userId, int reason,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800921 String requestedAuthority, Bundle extras, int targetSyncState,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700922 @SyncExemption int syncExemptionFlag) {
Shreyas Basargeba1f7902016-10-01 00:19:44 +0100923 scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700924 0 /* min delay */, true /* checkIfAccountReady */, syncExemptionFlag);
Shreyas Basargeba1f7902016-10-01 00:19:44 +0100925 }
926
927 /**
928 * @param minDelayMillis The sync can't land before this delay expires.
929 */
930 private void scheduleSync(Account requestedAccount, int userId, int reason,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800931 String requestedAuthority, Bundle extras, int targetSyncState,
932 final long minDelayMillis, boolean checkIfAccountReady,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700933 @SyncExemption int syncExemptionFlag) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000934 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Matthew Williamsfa774182013-06-18 15:44:11 -0700935 if (extras == null) {
936 extras = new Bundle();
937 }
938 if (isLoggable) {
939 Log.d(TAG, "one-time sync for: " + requestedAccount + " " + extras.toString() + " "
Makoto Onukiaad2b512018-02-07 09:31:46 -0800940 + requestedAuthority
941 + " reason=" + reason
942 + " checkIfAccountReady=" + checkIfAccountReady
Makoto Onuki75ad2492018-03-28 14:42:42 -0700943 + " syncExemptionFlag=" + syncExemptionFlag);
Matthew Williamsfa774182013-06-18 15:44:11 -0700944 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700945
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700946 AccountAndUser[] accounts = null;
947 if (requestedAccount != null) {
948 if (userId != UserHandle.USER_ALL) {
949 accounts = new AccountAndUser[]{new AccountAndUser(requestedAccount, userId)};
950 } else {
951 for (AccountAndUser runningAccount : mRunningAccounts) {
952 if (requestedAccount.equals(runningAccount.account)) {
953 accounts = ArrayUtils.appendElement(AccountAndUser.class,
954 accounts, runningAccount);
955 }
956 }
957 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700958 } else {
Matthew Williamsfa774182013-06-18 15:44:11 -0700959 accounts = mRunningAccounts;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700960 }
961
962 if (ArrayUtils.isEmpty(accounts)) {
963 if (isLoggable) {
964 Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
Matthew Williamsfa774182013-06-18 15:44:11 -0700965 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700966 return;
Matthew Williamsfa774182013-06-18 15:44:11 -0700967 }
968
969 final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
970 final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
971 if (manualSync) {
972 extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
973 extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
974 }
975 final boolean ignoreSettings =
976 extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
977
978 int source;
979 if (uploadOnly) {
980 source = SyncStorageEngine.SOURCE_LOCAL;
981 } else if (manualSync) {
982 source = SyncStorageEngine.SOURCE_USER;
983 } else if (requestedAuthority == null) {
984 source = SyncStorageEngine.SOURCE_POLL;
985 } else {
Makoto Onuki94986212018-04-11 16:24:46 -0700986 if (extras.containsKey("feed")) {
987 source = SyncStorageEngine.SOURCE_FEED;
988 } else{
989 // This isn't strictly server, since arbitrary callers can (and do) request
990 // a non-forced two-way sync on a specific url.
991 source = SyncStorageEngine.SOURCE_OTHER;
992 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700993 }
994
995 for (AccountAndUser account : accounts) {
Fyodor Kupolov6fde2982015-01-06 17:46:37 -0800996 // If userId is specified, do not sync accounts of other users
Xiaohui Chen98404fd2015-08-17 16:09:02 -0700997 if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
Fyodor Kupolov6fde2982015-01-06 17:46:37 -0800998 && userId != account.userId) {
999 continue;
1000 }
Matthew Williamsfa774182013-06-18 15:44:11 -07001001 // Compile a list of authorities that have sync adapters.
1002 // For each authority sync each account that matches a sync adapter.
1003 final HashSet<String> syncableAuthorities = new HashSet<String>();
1004 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
1005 mSyncAdapters.getAllServices(account.userId)) {
1006 syncableAuthorities.add(syncAdapter.type.authority);
1007 }
1008
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001009 // If the url was specified then replace the list of authorities
Matthew Williamsfa774182013-06-18 15:44:11 -07001010 // with just this authority or clear it if this authority isn't
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001011 // syncable.
Matthew Williamsfa774182013-06-18 15:44:11 -07001012 if (requestedAuthority != null) {
1013 final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
1014 syncableAuthorities.clear();
1015 if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
1016 }
1017
1018 for (String authority : syncableAuthorities) {
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001019 int isSyncable = computeSyncable(account.account, account.userId, authority,
1020 !checkIfAccountReady);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001021
Matthew Williams53abfdb2015-06-10 20:06:37 -07001022 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001023 continue;
1024 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001025
1026 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
1027 mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority,
1028 account.account.type), account.userId);
Matthew Williamsfa774182013-06-18 15:44:11 -07001029 if (syncAdapterInfo == null) {
1030 continue;
1031 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001032
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001033 final int owningUid = syncAdapterInfo.uid;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001034
1035 if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
1036 if (isLoggable) {
1037 Slog.v(TAG, " Not scheduling sync operation: "
1038 + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001039 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001040 Bundle finalExtras = new Bundle(extras);
Svet Ganov973edd192016-09-08 20:15:55 -07001041 String packageName = syncAdapterInfo.componentName.getPackageName();
1042 // If the app did not run and has no account access, done
Amith Yamasani2cbfa1e2017-03-28 10:34:01 -07001043 try {
1044 if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
1045 continue;
1046 }
1047 } catch (IllegalArgumentException e) {
1048 // Package not found, race with an uninstall
Svet Ganov973edd192016-09-08 20:15:55 -07001049 continue;
1050 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001051 mAccountManagerInternal.requestAccountAccess(account.account,
Svet Ganov973edd192016-09-08 20:15:55 -07001052 packageName, userId,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001053 new RemoteCallback((Bundle result) -> {
1054 if (result != null
1055 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
1056 scheduleSync(account.account, userId, reason, authority,
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001057 finalExtras, targetSyncState, minDelayMillis,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001058 true /* checkIfAccountReady */,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001059 syncExemptionFlag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001060 }
1061 }
1062 ));
1063 continue;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001064 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001065
Matthew Williamsfa774182013-06-18 15:44:11 -07001066 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
1067 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001068 if (!checkIfAccountReady && isSyncable < 0 && isAlwaysSyncable) {
Matthew Williams53abfdb2015-06-10 20:06:37 -07001069 mSyncStorageEngine.setIsSyncable(
Makoto Onukid4764302018-03-30 17:32:57 -07001070 account.account, account.userId, authority, AuthorityInfo.SYNCABLE,
1071 SyncLogger.CALLING_UID_SELF);
Matthew Williams53abfdb2015-06-10 20:06:37 -07001072 isSyncable = AuthorityInfo.SYNCABLE;
Matthew Williamsfa774182013-06-18 15:44:11 -07001073 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001074
Svet Ganovf6d424f12016-09-20 20:18:53 -07001075 if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001076 continue;
1077 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07001078
Matthew Williamsfa774182013-06-18 15:44:11 -07001079 if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
1080 continue;
1081 }
1082
Matthew Williamsfa774182013-06-18 15:44:11 -07001083 boolean syncAllowed =
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001084 (isSyncable < 0) // Always allow if the isSyncable state is unknown.
1085 || ignoreSettings
1086 || (mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
Matthew Williamsfa774182013-06-18 15:44:11 -07001087 && mSyncStorageEngine.getSyncAutomatically(account.account,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001088 account.userId, authority));
Matthew Williamsfa774182013-06-18 15:44:11 -07001089 if (!syncAllowed) {
1090 if (isLoggable) {
1091 Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
1092 + " is not allowed, dropping request");
1093 }
1094 continue;
1095 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001096 SyncStorageEngine.EndPoint info =
1097 new SyncStorageEngine.EndPoint(
1098 account.account, authority, account.userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001099 long delayUntil =
1100 mSyncStorageEngine.getDelayUntilTime(info);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001101
1102 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
1103
Svet Ganovf6d424f12016-09-20 20:18:53 -07001104 if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001105 if (checkIfAccountReady) {
1106 Bundle finalExtras = new Bundle(extras);
1107
1108 sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId,
1109 () -> scheduleSync(account.account, account.userId, reason,
1110 authority, finalExtras, targetSyncState, minDelayMillis,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001111 false, syncExemptionFlag));
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001112 } else {
1113 // Initialisation sync.
1114 Bundle newExtras = new Bundle();
1115 newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
1116 if (isLoggable) {
1117 Slog.v(TAG, "schedule initialisation Sync:"
1118 + ", delay until " + delayUntil
1119 + ", run by " + 0
1120 + ", flexMillis " + 0
1121 + ", source " + source
1122 + ", account " + account
1123 + ", authority " + authority
1124 + ", extras " + newExtras);
1125 }
1126 postScheduleSyncMessage(
1127 new SyncOperation(account.account, account.userId,
1128 owningUid, owningPackage, reason, source,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001129 authority, newExtras, allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001130 syncExemptionFlag),
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001131 minDelayMillis
1132 );
Matthew Williamsfa774182013-06-18 15:44:11 -07001133 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07001134 } else if (targetSyncState == AuthorityInfo.UNDEFINED
1135 || targetSyncState == isSyncable) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001136 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001137 Slog.v(TAG, "scheduleSync:"
Matthew Williamsfa774182013-06-18 15:44:11 -07001138 + " delay until " + delayUntil
Matthew Williamsfa774182013-06-18 15:44:11 -07001139 + ", source " + source
1140 + ", account " + account
1141 + ", authority " + authority
1142 + ", extras " + extras);
1143 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001144 postScheduleSyncMessage(
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001145 new SyncOperation(account.account, account.userId,
1146 owningUid, owningPackage, reason, source,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001147 authority, extras, allowParallelSyncs, syncExemptionFlag),
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001148 minDelayMillis
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001149 );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 }
1151 }
1152 }
1153 }
1154
Svet Ganov96b9c752016-10-17 19:29:58 -07001155 public int computeSyncable(Account account, int userId, String authority,
1156 boolean checkAccountAccess) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001157 final int status = getIsSyncable(account, userId, authority);
1158 if (status == AuthorityInfo.NOT_SYNCABLE) {
1159 return AuthorityInfo.NOT_SYNCABLE;
1160 }
1161 final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
1162 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
1163 mSyncAdapters.getServiceInfo(type, userId);
1164 if (syncAdapterInfo == null) {
1165 return AuthorityInfo.NOT_SYNCABLE;
1166 }
1167 final int owningUid = syncAdapterInfo.uid;
1168 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
1169 try {
Dianne Hackbornc3af19a2017-01-20 17:00:44 -08001170 if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001171 Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
1172 + syncAdapterInfo.componentName
1173 + " -- package not allowed to start");
1174 return AuthorityInfo.NOT_SYNCABLE;
1175 }
1176 } catch (RemoteException e) {
1177 /* ignore - local call */
1178 }
Svet Ganov96b9c752016-10-17 19:29:58 -07001179 if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
Makoto Onuki5fc60022019-01-15 09:34:05 -08001180 Log.w(TAG, "Access to " + logSafe(account) + " denied for package "
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001181 + owningPackage + " in UID " + syncAdapterInfo.uid);
1182 return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
1183 }
1184
1185 return status;
1186 }
1187
1188 private boolean canAccessAccount(Account account, String packageName, int uid) {
1189 if (mAccountManager.hasAccountAccess(account, packageName,
1190 UserHandle.getUserHandleForUid(uid))) {
1191 return true;
1192 }
1193 // We relax the account access rule to also include the system apps as
1194 // they are trusted and we want to minimize the cases where the user
1195 // involvement is required to grant access to the synced account.
1196 try {
1197 mContext.getPackageManager().getApplicationInfoAsUser(packageName,
1198 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.getUserId(uid));
1199 return true;
1200 } catch (NameNotFoundException e) {
1201 return false;
1202 }
1203 }
1204
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001205 private void removeSyncsForAuthority(EndPoint info, String why) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001206 mLogger.log("removeSyncsForAuthority: ", info);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001207 verifyJobScheduler();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001208 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001209 for (SyncOperation op: ops) {
1210 if (op.target.matchesSpec(info)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001211 mLogger.log("canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001212 cancelJob(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001213 }
1214 }
1215 }
1216
1217 /**
1218 * Remove a specific periodic sync identified by its target and extras.
1219 */
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001220 public void removePeriodicSync(EndPoint target, Bundle extras, String why) {
1221 Message m = mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_REMOVE_PERIODIC_SYNC,
1222 Pair.create(target, why));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001223 m.setData(extras);
1224 m.sendToTarget();
1225 }
1226
1227 /**
1228 * Add a periodic sync. If a sync with same target and extras exists, its period and
1229 * flexMillis will be updated.
1230 */
1231 public void updateOrAddPeriodicSync(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001232 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001233 UpdatePeriodicSyncMessagePayload payload = new UpdatePeriodicSyncMessagePayload(target,
1234 pollFrequency, flex, extras);
1235 mSyncHandler.obtainMessage(SyncHandler.MESSAGE_UPDATE_PERIODIC_SYNC, payload)
1236 .sendToTarget();
1237 }
1238
1239 /**
1240 * Get a list of periodic syncs corresponding to the given target.
1241 */
1242 public List<PeriodicSync> getPeriodicSyncs(EndPoint target) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001243 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001244 List<PeriodicSync> periodicSyncs = new ArrayList<PeriodicSync>();
1245
1246 for (SyncOperation op: ops) {
1247 if (op.isPeriodic && op.target.matchesSpec(target)) {
1248 periodicSyncs.add(new PeriodicSync(op.target.account, op.target.provider,
1249 op.extras, op.periodMillis / 1000, op.flexMillis / 1000));
1250 }
1251 }
1252
1253 return periodicSyncs;
1254 }
1255
Matthew Williamsfa774182013-06-18 15:44:11 -07001256 /**
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001257 * Schedule sync based on local changes to a provider. We wait for at least LOCAL_SYNC_DELAY
1258 * ms to batch syncs.
Matthew Williamsfa774182013-06-18 15:44:11 -07001259 */
Makoto Onuki61283ec2018-01-31 17:22:36 -08001260 public void scheduleLocalSync(Account account, int userId, int reason, String authority,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001261 @SyncExemption int syncExemptionFlag) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 final Bundle extras = new Bundle();
1263 extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
Matthew Williamsfa774182013-06-18 15:44:11 -07001264 scheduleSync(account, userId, reason, authority, extras,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001265 AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001266 syncExemptionFlag);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 }
1268
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001269 public SyncAdapterType[] getSyncAdapterTypes(int userId) {
1270 final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
1271 serviceInfos = mSyncAdapters.getAllServices(userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -07001272 SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
1273 int i = 0;
1274 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
1275 types[i] = serviceInfo.type;
1276 ++i;
1277 }
1278 return types;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 }
1280
Amith Yamasani37a40c22015-06-17 13:25:42 -07001281 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
1282 return mSyncAdapters.getSyncAdapterPackagesForAuthority(authority, userId);
1283 }
1284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001286 SyncResult syncResult) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001287 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 Message msg = mSyncHandler.obtainMessage();
1289 msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001290 msg.obj = new SyncFinishedOrCancelledMessagePayload(syncContext, syncResult);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 mSyncHandler.sendMessage(msg);
1292 }
1293
Makoto Onukia9dca242017-06-21 17:06:49 -07001294 private void sendCancelSyncsMessage(final SyncStorageEngine.EndPoint info, Bundle extras,
1295 String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001296 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_CANCEL");
Makoto Onukia9dca242017-06-21 17:06:49 -07001297
1298 mLogger.log("sendCancelSyncsMessage() ep=", info, " why=", why);
1299
Fred Quintana918339a2010-10-05 14:00:39 -07001300 Message msg = mSyncHandler.obtainMessage();
1301 msg.what = SyncHandler.MESSAGE_CANCEL;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001302 msg.setData(extras);
1303 msg.obj = info;
Fred Quintana918339a2010-10-05 14:00:39 -07001304 mSyncHandler.sendMessage(msg);
1305 }
1306
Matthew Williams92a1c092014-08-25 19:18:32 -07001307 /**
Matthew Williams1967c8d2015-06-19 19:03:13 -07001308 * Post a delayed message that will monitor the given sync context by periodically checking how
1309 * much network has been used by the uid.
Matthew Williams92a1c092014-08-25 19:18:32 -07001310 */
Matthew Williams1967c8d2015-06-19 19:03:13 -07001311 private void postMonitorSyncProgressMessage(ActiveSyncContext activeSyncContext) {
Matthew Williams92a1c092014-08-25 19:18:32 -07001312 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001313 Slog.v(TAG, "posting MESSAGE_SYNC_MONITOR in " +
Matthew Williams1967c8d2015-06-19 19:03:13 -07001314 (SYNC_MONITOR_WINDOW_LENGTH_MILLIS/1000) + "s");
Matthew Williams92a1c092014-08-25 19:18:32 -07001315 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07001316
1317 activeSyncContext.mBytesTransferredAtLastPoll =
1318 getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
1319 activeSyncContext.mLastPolledTimeElapsed = SystemClock.elapsedRealtime();
1320 Message monitorMessage =
1321 mSyncHandler.obtainMessage(
1322 SyncHandler.MESSAGE_MONITOR_SYNC,
1323 activeSyncContext);
1324 mSyncHandler.sendMessageDelayed(monitorMessage, SYNC_MONITOR_WINDOW_LENGTH_MILLIS);
Matthew Williams92a1c092014-08-25 19:18:32 -07001325 }
1326
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001327 private void postScheduleSyncMessage(SyncOperation syncOperation, long minDelayMillis) {
1328 ScheduleSyncMessagePayload payload =
1329 new ScheduleSyncMessagePayload(syncOperation, minDelayMillis);
1330 mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, payload).sendToTarget();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001331 }
1332
Matthew Williams1967c8d2015-06-19 19:03:13 -07001333 /**
1334 * Monitor sync progress by calculating how many bytes it is managing to send to and fro.
1335 */
1336 private long getTotalBytesTransferredByUid(int uid) {
1337 return (TrafficStats.getUidRxBytes(uid) + TrafficStats.getUidTxBytes(uid));
1338 }
1339
1340 /**
1341 * Convenience class for passing parameters for a finished or cancelled sync to the handler
1342 * to be processed.
1343 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001344 private class SyncFinishedOrCancelledMessagePayload {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 public final ActiveSyncContext activeSyncContext;
1346 public final SyncResult syncResult;
1347
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001348 SyncFinishedOrCancelledMessagePayload(ActiveSyncContext syncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001349 SyncResult syncResult) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 this.activeSyncContext = syncContext;
1351 this.syncResult = syncResult;
1352 }
1353 }
1354
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001355 private class UpdatePeriodicSyncMessagePayload {
1356 public final EndPoint target;
1357 public final long pollFrequency;
1358 public final long flex;
1359 public final Bundle extras;
1360
1361 UpdatePeriodicSyncMessagePayload(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001362 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001363 this.target = target;
1364 this.pollFrequency = pollFrequency;
1365 this.flex = flex;
1366 this.extras = extras;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 }
1368 }
1369
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001370 private static class ScheduleSyncMessagePayload {
1371 final SyncOperation syncOperation;
1372 final long minDelayMillis;
1373
1374 ScheduleSyncMessagePayload(SyncOperation syncOperation, long minDelayMillis) {
1375 this.syncOperation = syncOperation;
1376 this.minDelayMillis = minDelayMillis;
1377 }
1378 }
1379
Makoto Onukia9dca242017-06-21 17:06:49 -07001380 private void clearBackoffSetting(EndPoint target, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001381 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
1382 if (backoff != null && backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE &&
1383 backoff.second == SyncStorageEngine.NOT_IN_BACKOFF_MODE) {
1384 return;
1385 }
1386 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1387 Slog.v(TAG, "Clearing backoffs for " + target);
1388 }
1389 mSyncStorageEngine.setBackoff(target,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001390 SyncStorageEngine.NOT_IN_BACKOFF_MODE,
1391 SyncStorageEngine.NOT_IN_BACKOFF_MODE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001392
Makoto Onukia9dca242017-06-21 17:06:49 -07001393 rescheduleSyncs(target, why);
Alon Albert6e079a32010-11-12 12:41:09 -08001394 }
1395
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001396 private void increaseBackoffSetting(EndPoint target) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001397 final long now = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398
Fred Quintana307da1a2010-01-21 14:24:20 -08001399 final Pair<Long, Long> previousSettings =
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001400 mSyncStorageEngine.getBackoff(target);
Alon Albertaeeb6202010-12-09 16:14:02 -08001401 long newDelayInMs = -1;
1402 if (previousSettings != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001403 // Don't increase backoff before current backoff is expired. This will happen for op's
Alon Albertaeeb6202010-12-09 16:14:02 -08001404 // with ignoreBackoff set.
1405 if (now < previousSettings.first) {
1406 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001407 Slog.v(TAG, "Still in backoff, do not increase it. "
1408 + "Remaining: " + ((previousSettings.first - now) / 1000) + " seconds.");
Alon Albertaeeb6202010-12-09 16:14:02 -08001409 }
1410 return;
1411 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001412 // Subsequent delays are the double of the previous delay.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001413 newDelayInMs =
1414 (long) (previousSettings.second * mConstants.getRetryTimeIncreaseFactor());
Alon Albertaeeb6202010-12-09 16:14:02 -08001415 }
1416 if (newDelayInMs <= 0) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001417 // The initial delay is the jitterized INITIAL_SYNC_RETRY_TIME_IN_MS.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001418 final long initialRetryMs = mConstants.getInitialSyncRetryTimeInSeconds() * 1000;
1419 newDelayInMs = jitterize(initialRetryMs, (long)(initialRetryMs * 1.1));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 }
1421
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001422 // Cap the delay.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001423 final long maxSyncRetryTimeInSeconds = mConstants.getMaxSyncRetryTimeInSeconds();
1424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
1426 newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
1427 }
1428
Alon Albertc1ac7762010-10-28 13:35:55 -07001429 final long backoff = now + newDelayInMs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001430 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1431 Slog.v(TAG, "Backoff until: " + backoff + ", delayTime: " + newDelayInMs);
1432 }
1433 mSyncStorageEngine.setBackoff(target, backoff, newDelayInMs);
Makoto Onukia9dca242017-06-21 17:06:49 -07001434 rescheduleSyncs(target, "increaseBackoffSetting");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001435 }
Alon Albertc1ac7762010-10-28 13:35:55 -07001436
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001437 /**
1438 * Reschedule all scheduled syncs for this EndPoint. The syncs will be scheduled according
1439 * to current backoff and delayUntil values of this EndPoint.
1440 */
Makoto Onukia9dca242017-06-21 17:06:49 -07001441 private void rescheduleSyncs(EndPoint target, String why) {
1442 mLogger.log("rescheduleSyncs() ep=", target, " why=", why);
1443
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001444 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001445 int count = 0;
1446 for (SyncOperation op: ops) {
1447 if (!op.isPeriodic && op.target.matchesSpec(target)) {
1448 count++;
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001449 cancelJob(op, why);
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001450 postScheduleSyncMessage(op, 0 /* min delay */);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001451 }
1452 }
1453 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1454 Slog.v(TAG, "Rescheduled " + count + " syncs for " + target);
Fred Quintana918339a2010-10-05 14:00:39 -07001455 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001456 }
1457
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001458 private void setDelayUntilTime(EndPoint target, long delayUntilSeconds) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001459 final long delayUntil = delayUntilSeconds * 1000;
1460 final long absoluteNow = System.currentTimeMillis();
1461 long newDelayUntilTime;
1462 if (delayUntil > absoluteNow) {
1463 newDelayUntilTime = SystemClock.elapsedRealtime() + (delayUntil - absoluteNow);
1464 } else {
1465 newDelayUntilTime = 0;
1466 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001467 mSyncStorageEngine.setDelayUntilTime(target, newDelayUntilTime);
1468 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1469 Slog.v(TAG, "Delay Until time set to " + newDelayUntilTime + " for " + target);
Fred Quintana918339a2010-10-05 14:00:39 -07001470 }
Makoto Onukia9dca242017-06-21 17:06:49 -07001471 rescheduleSyncs(target, "delayUntil newDelayUntilTime: " + newDelayUntilTime);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001472 }
1473
1474 private boolean isAdapterDelayed(EndPoint target) {
1475 long now = SystemClock.elapsedRealtime();
1476 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
1477 if (backoff != null && backoff.first != SyncStorageEngine.NOT_IN_BACKOFF_MODE
1478 && backoff.first > now) {
1479 return true;
1480 }
1481 if (mSyncStorageEngine.getDelayUntilTime(target) > now) {
1482 return true;
1483 }
1484 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 }
1486
1487 /**
Matthew Williams8ef22042013-07-26 12:56:39 -07001488 * Cancel the active sync if it matches the target.
1489 * @param info object containing info about which syncs to cancel. The target can
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001490 * have null account/provider info to specify all accounts/providers.
1491 * @param extras if non-null, specifies the exact sync to remove.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 */
Makoto Onukia9dca242017-06-21 17:06:49 -07001493 public void cancelActiveSync(SyncStorageEngine.EndPoint info, Bundle extras, String why) {
1494 sendCancelSyncsMessage(info, extras, why);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 }
1496
1497 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001498 * Schedule a sync operation with JobScheduler.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001500 private void scheduleSyncOperationH(SyncOperation syncOperation) {
1501 scheduleSyncOperationH(syncOperation, 0L);
1502 }
1503
1504 private void scheduleSyncOperationH(SyncOperation syncOperation, long minDelay) {
1505 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
1506 if (syncOperation == null) {
1507 Slog.e(TAG, "Can't schedule null sync operation.");
1508 return;
1509 }
1510 if (!syncOperation.ignoreBackoff()) {
1511 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target);
1512 if (backoff == null) {
Makoto Onuki5fc60022019-01-15 09:34:05 -08001513 Slog.e(TAG, "Couldn't find backoff values for "
1514 + logSafe(syncOperation.target));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001515 backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
1516 SyncStorageEngine.NOT_IN_BACKOFF_MODE);
1517 }
1518 long now = SystemClock.elapsedRealtime();
1519 long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0
1520 : backoff.first - now;
1521 long delayUntil = mSyncStorageEngine.getDelayUntilTime(syncOperation.target);
1522 long delayUntilDelay = delayUntil > now ? delayUntil - now : 0;
1523 if (isLoggable) {
1524 Slog.v(TAG, "backoff delay:" + backoffDelay
1525 + " delayUntil delay:" + delayUntilDelay);
1526 }
1527 minDelay = Math.max(minDelay, Math.max(backoffDelay, delayUntilDelay));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 }
1529
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001530 if (minDelay < 0) {
1531 minDelay = 0;
1532 }
1533
1534 // Check if duplicate syncs are pending. If found, keep one with least expected run time.
Makoto Onuki61283ec2018-01-31 17:22:36 -08001535
1536 // If any of the duplicate ones has exemption, then we inherit it.
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001537 if (!syncOperation.isPeriodic) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001538 int inheritedSyncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001539
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001540 // Check currently running syncs
1541 for (ActiveSyncContext asc: mActiveSyncContexts) {
1542 if (asc.mSyncOperation.key.equals(syncOperation.key)) {
1543 if (isLoggable) {
1544 Log.v(TAG, "Duplicate sync is already running. Not scheduling "
1545 + syncOperation);
1546 }
1547 return;
1548 }
1549 }
1550
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001551 int duplicatesCount = 0;
1552 long now = SystemClock.elapsedRealtime();
1553 syncOperation.expectedRuntime = now + minDelay;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001554 List<SyncOperation> pending = getAllPendingSyncs();
Makoto Onuki61283ec2018-01-31 17:22:36 -08001555 SyncOperation syncToRun = syncOperation;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001556 for (SyncOperation op : pending) {
1557 if (op.isPeriodic) {
1558 continue;
1559 }
1560 if (op.key.equals(syncOperation.key)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001561 if (syncToRun.expectedRuntime > op.expectedRuntime) {
1562 syncToRun = op;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001563 }
1564 duplicatesCount++;
1565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001567 if (duplicatesCount > 1) {
1568 Slog.e(TAG, "FATAL ERROR! File a bug if you see this.");
1569 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001570
1571 if (syncOperation != syncToRun) {
1572 // If there's a duplicate with an earlier run time that's not exempted,
1573 // and if the current operation is exempted with no minDelay,
1574 // cancel the duplicate one and keep the current one.
1575 //
1576 // This means the duplicate one has a negative expected run time, but it hasn't
1577 // been executed possibly because of app-standby.
1578
Makoto Onuki75ad2492018-03-28 14:42:42 -07001579 if ((minDelay == 0)
1580 && (syncToRun.syncExemptionFlag < syncOperation.syncExemptionFlag)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001581 syncToRun = syncOperation;
Makoto Onuki75ad2492018-03-28 14:42:42 -07001582 inheritedSyncExemptionFlag =
1583 Math.max(inheritedSyncExemptionFlag, syncToRun.syncExemptionFlag);
Makoto Onuki61283ec2018-01-31 17:22:36 -08001584 }
1585 }
1586
1587 // Cancel all other duplicate syncs.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001588 for (SyncOperation op : pending) {
1589 if (op.isPeriodic) {
1590 continue;
1591 }
1592 if (op.key.equals(syncOperation.key)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001593 if (op != syncToRun) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001594 if (isLoggable) {
1595 Slog.v(TAG, "Cancelling duplicate sync " + op);
1596 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07001597 inheritedSyncExemptionFlag =
1598 Math.max(inheritedSyncExemptionFlag, op.syncExemptionFlag);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001599 cancelJob(op, "scheduleSyncOperationH-duplicate");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001600 }
1601 }
1602 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001603 if (syncToRun != syncOperation) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001604 // Don't schedule because a duplicate sync with earlier expected runtime exists.
1605 if (isLoggable) {
1606 Slog.v(TAG, "Not scheduling because a duplicate exists.");
1607 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001608
1609 // TODO Should we give the winning one SYNC_EXTRAS_APP_STANDBY_EXEMPTED
1610 // if the current one has it?
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001611 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001613
1614 // If any of the duplicates had exemption, we exempt the current one.
Makoto Onuki75ad2492018-03-28 14:42:42 -07001615 //
1616 if (inheritedSyncExemptionFlag > ContentResolver.SYNC_EXEMPTION_NONE) {
1617 syncOperation.syncExemptionFlag = inheritedSyncExemptionFlag;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001618 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001619 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001620
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001621 // Syncs that are re-scheduled shouldn't get a new job id.
1622 if (syncOperation.jobId == SyncOperation.NO_JOB_ID) {
1623 syncOperation.jobId = getUnusedJobIdH();
1624 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001625
1626 if (isLoggable) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001627 Slog.v(TAG, "scheduling sync operation " + syncOperation.toString());
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001628 }
1629
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001630 int priority = syncOperation.findPriority();
1631
1632 final int networkType = syncOperation.isNotAllowedOnMetered() ?
1633 JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
1634
Makoto Onuki61283ec2018-01-31 17:22:36 -08001635 // Note this logic means when an exempted sync fails,
1636 // the back-off one will inherit it too, and will be exempted from app-standby.
Makoto Onuki75ad2492018-03-28 14:42:42 -07001637 final int jobFlags = syncOperation.isAppStandbyExempted()
Makoto Onuki61283ec2018-01-31 17:22:36 -08001638 ? JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY : 0;
1639
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001640 JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001641 new ComponentName(mContext, SyncJobService.class))
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001642 .setExtras(syncOperation.toJobInfoExtras())
1643 .setRequiredNetworkType(networkType)
1644 .setPersisted(true)
Makoto Onuki61283ec2018-01-31 17:22:36 -08001645 .setPriority(priority)
1646 .setFlags(jobFlags);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001647
1648 if (syncOperation.isPeriodic) {
1649 b.setPeriodic(syncOperation.periodMillis, syncOperation.flexMillis);
1650 } else {
1651 if (minDelay > 0) {
1652 b.setMinimumLatency(minDelay);
1653 }
1654 getSyncStorageEngine().markPending(syncOperation.target, true);
1655 }
1656
1657 if (syncOperation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)) {
1658 b.setRequiresCharging(true);
1659 }
1660
Makoto Onuki75ad2492018-03-28 14:42:42 -07001661 if (syncOperation.syncExemptionFlag
Makoto Onukid5f25d22018-05-22 16:02:17 -07001662 == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001663 DeviceIdleController.LocalService dic =
1664 LocalServices.getService(DeviceIdleController.LocalService.class);
1665 if (dic != null) {
1666 dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID,
1667 syncOperation.owningPackage,
1668 mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
1669 UserHandle.getUserId(syncOperation.owningUid),
1670 /* sync=*/ false, "sync by top app");
1671 }
1672 }
1673
Makoto Onukid5f25d22018-05-22 16:02:17 -07001674 if (syncOperation.isAppStandbyExempted()) {
1675 final UsageStatsManagerInternal usmi = LocalServices.getService(
1676 UsageStatsManagerInternal.class);
1677 if (usmi != null) {
1678 usmi.reportExemptedSyncScheduled(syncOperation.owningPackage,
1679 UserHandle.getUserId(syncOperation.owningUid));
1680 }
1681 }
1682
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001683 getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
Shreyas Basargeeda34e42016-04-26 00:14:02 +01001684 syncOperation.target.userId, syncOperation.wakeLockName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 }
1686
1687 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07001688 * Remove scheduled sync operations.
Matthew Williams8ef22042013-07-26 12:56:39 -07001689 * @param info limit the removals to operations that match this target. The target can
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001690 * have null account/provider info to specify all accounts/providers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 */
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001692 public void clearScheduledSyncOperations(SyncStorageEngine.EndPoint info) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001693 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001694 for (SyncOperation op: ops) {
1695 if (!op.isPeriodic && op.target.matchesSpec(info)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001696 cancelJob(op, "clearScheduledSyncOperations");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001697 getSyncStorageEngine().markPending(op.target, false);
1698 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001700 mSyncStorageEngine.setBackoff(info,
Fred Quintana918339a2010-10-05 14:00:39 -07001701 SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 }
1703
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001704 /**
1705 * Remove a specified sync, if it exists.
1706 * @param info Authority for which the sync is to be removed.
1707 * @param extras extras bundle to uniquely identify sync.
1708 */
1709 public void cancelScheduledSyncOperation(SyncStorageEngine.EndPoint info, Bundle extras) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001710 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001711 for (SyncOperation op: ops) {
1712 if (!op.isPeriodic && op.target.matchesSpec(info)
1713 && syncExtrasEquals(extras, op.extras, false)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001714 cancelJob(op, "cancelScheduledSyncOperation");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001715 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001716 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001717 setAuthorityPendingState(info);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001718 // Reset the back-off if there are no more syncs pending.
1719 if (!mSyncStorageEngine.isSyncPending(info)) {
1720 mSyncStorageEngine.setBackoff(info,
1721 SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
1722 }
1723 }
1724
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001725 private void maybeRescheduleSync(SyncResult syncResult, SyncOperation operation) {
1726 final boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 if (isLoggable) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001728 Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 }
1730
Fred Quintana53bd2522010-02-05 15:28:12 -08001731 // The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
1732 // request. Retries of the request will always honor the backoff, so clear the
1733 // flag in case we retry this request.
1734 if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
1735 operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
1736 }
1737
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01001738 if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
1739 && !syncResult.syncAlreadyInProgress) {
1740 // syncAlreadyInProgress flag is set by AbstractThreadedSyncAdapter. The sync adapter
1741 // has no way of knowing that a sync error occured. So we DO retry if the error is
1742 // syncAlreadyInProgress.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001743 if (isLoggable) {
1744 Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
1745 + operation);
1746 }
Fred Quintana918339a2010-10-05 14:00:39 -07001747 } else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)
1748 && !syncResult.syncAlreadyInProgress) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001749 // If this was an upward sync then schedule a two-way sync immediately.
Fred Quintana53bd2522010-02-05 15:28:12 -08001750 operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001751 if (isLoggable) {
1752 Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
1753 + "encountered an error: " + operation);
1754 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001755 scheduleSyncOperationH(operation);
Fred Quintana307da1a2010-01-21 14:24:20 -08001756 } else if (syncResult.tooManyRetries) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001757 // If this sync aborted because the internal sync loop retried too many times then
1758 // don't reschedule. Otherwise we risk getting into a retry loop.
1759 if (isLoggable) {
1760 Log.d(TAG, "not retrying sync operation because it retried too many times: "
1761 + operation);
1762 }
Fred Quintanaaa7edda2009-12-03 14:18:58 -08001763 } else if (syncResult.madeSomeProgress()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001764 // If the operation succeeded to some extent then retry immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 if (isLoggable) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001766 Log.d(TAG, "retrying sync operation because even though it had an error "
1767 + "it achieved some success");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001769 scheduleSyncOperationH(operation);
Fred Quintana8570f742010-02-18 10:32:54 -08001770 } else if (syncResult.syncAlreadyInProgress) {
1771 if (isLoggable) {
1772 Log.d(TAG, "retrying sync operation that failed because there was already a "
1773 + "sync in progress: " + operation);
1774 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001775 scheduleSyncOperationH(operation, DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776 } else if (syncResult.hasSoftError()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001777 // If this was a two-way sync then retry soft errors with an exponential backoff.
Fred Quintana307da1a2010-01-21 14:24:20 -08001778 if (isLoggable) {
1779 Log.d(TAG, "retrying sync operation because it encountered a soft error: "
1780 + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001782 scheduleSyncOperationH(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 } else {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001784 // Otherwise do not reschedule.
Makoto Onuki5fc60022019-01-15 09:34:05 -08001785 Log.e(TAG, "not retrying sync operation because the error is a hard error: "
1786 + logSafe(operation));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 }
1788 }
1789
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07001790 private void onUserUnlocked(int userId) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001791 // Make sure that accounts we're about to use are valid.
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001792 AccountManagerService.getSingleton().validateAccounts(userId);
1793
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001794 mSyncAdapters.invalidateCache(userId);
1795
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001796 EndPoint target = new EndPoint(null, null, userId);
1797 updateRunningAccounts(target);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001798
Makoto Onuki61283ec2018-01-31 17:22:36 -08001799 // Schedule sync for any accounts under started user, but only the NOT_INITIALIZED adapters.
Svetoslavf3f02ac2015-09-08 14:36:35 -07001800 final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId,
1801 mContext.getOpPackageName());
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001802 for (Account account : accounts) {
Alon Albert57286f92012-10-09 14:21:38 -07001803 scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001804 AuthorityInfo.NOT_INITIALIZED, ContentResolver.SYNC_EXEMPTION_NONE);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001805 }
Alon Albert8e285552012-09-17 15:05:27 -07001806 }
Amith Yamasani13593602012-03-22 16:16:17 -07001807
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -07001808 private void onUserStopped(int userId) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001809 updateRunningAccounts(null /* Don't sync any target */);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001810
1811 cancelActiveSync(
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001812 new SyncStorageEngine.EndPoint(
1813 null /* any account */,
1814 null /* any authority */,
1815 userId),
Makoto Onukia9dca242017-06-21 17:06:49 -07001816 null /* any sync. */,
1817 "onUserStopped"
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001818 );
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001819 }
1820
1821 private void onUserRemoved(int userId) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001822 mLogger.log("onUserRemoved: u", userId);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001823 updateRunningAccounts(null /* Don't sync any target */);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001824
Amith Yamasani13593602012-03-22 16:16:17 -07001825 // Clean up the storage engine database
1826 mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001827 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001828 for (SyncOperation op: ops) {
1829 if (op.target.userId == userId) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001830 cancelJob(op, "user removed u" + userId);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001831 }
1832 }
1833 }
1834
Amith Yamasani96a0fd652015-04-10 16:16:30 -07001835 /**
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001836 * Construct intent used to bind to an adapter.
1837 *
1838 * @param context Context to create intent for
1839 * @param syncAdapterComponent The adapter description
1840 * @param userId The user the adapter belongs to
1841 *
1842 * @return The intent required to bind to the adapter
1843 */
1844 static @NonNull Intent getAdapterBindIntent(@NonNull Context context,
1845 @NonNull ComponentName syncAdapterComponent, @UserIdInt int userId) {
1846 final Intent intent = new Intent();
1847 intent.setAction("android.content.SyncAdapter");
1848 intent.setComponent(syncAdapterComponent);
1849 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1850 com.android.internal.R.string.sync_binding_label);
1851 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0,
1852 new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId)));
1853
1854 return intent;
1855 }
1856
1857 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001858 * @hide
1859 */
Alon Alberteca75112010-12-08 15:02:33 -08001860 class ActiveSyncContext extends ISyncContext.Stub
1861 implements ServiceConnection, IBinder.DeathRecipient {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 final SyncOperation mSyncOperation;
1863 final long mHistoryRowId;
Fred Quintana718d8a22009-04-29 17:53:20 -07001864 ISyncAdapter mSyncAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 final long mStartTime;
1866 long mTimeoutStartTime;
Fred Quintana3ec47302010-03-10 10:08:31 -08001867 boolean mBound;
Fred Quintana918339a2010-10-05 14:00:39 -07001868 final PowerManager.WakeLock mSyncWakeLock;
1869 final int mSyncAdapterUid;
1870 SyncInfo mSyncInfo;
Alon Alberteca75112010-12-08 15:02:33 -08001871 boolean mIsLinkedToDeath = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001872 String mEventName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873
Matthew Williams1967c8d2015-06-19 19:03:13 -07001874 /** Total bytes transferred, counted at {@link #mLastPolledTimeElapsed} */
1875 long mBytesTransferredAtLastPoll;
1876 /**
1877 * Last point in {@link SystemClock#elapsedRealtime()} at which we checked the # of bytes
1878 * transferred to/fro by this adapter.
1879 */
1880 long mLastPolledTimeElapsed;
1881
Fred Quintana918339a2010-10-05 14:00:39 -07001882 /**
1883 * Create an ActiveSyncContext for an impending sync and grab the wakelock for that
1884 * sync adapter. Since this grabs the wakelock you need to be sure to call
1885 * close() when you are done with this ActiveSyncContext, whether the sync succeeded
1886 * or not.
1887 * @param syncOperation the SyncOperation we are about to sync
1888 * @param historyRowId the row in which to record the history info for this sync
1889 * @param syncAdapterUid the UID of the application that contains the sync adapter
1890 * for this sync. This is used to attribute the wakelock hold to that application.
1891 */
1892 public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001893 int syncAdapterUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 super();
Fred Quintana918339a2010-10-05 14:00:39 -07001895 mSyncAdapterUid = syncAdapterUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 mSyncOperation = syncOperation;
1897 mHistoryRowId = historyRowId;
Fred Quintana718d8a22009-04-29 17:53:20 -07001898 mSyncAdapter = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 mStartTime = SystemClock.elapsedRealtime();
1900 mTimeoutStartTime = mStartTime;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001901 mSyncWakeLock = mSyncHandler.getSyncWakeLock(mSyncOperation);
Fred Quintana918339a2010-10-05 14:00:39 -07001902 mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
1903 mSyncWakeLock.acquire();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 }
1905
1906 public void sendHeartbeat() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001907 // Heartbeats are no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 }
1909
1910 public void onFinished(SyncResult result) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001911 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "onFinished: " + this);
1912 // Include "this" in the message so that the handler can ignore it if this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 // ActiveSyncContext is no longer the mActiveSyncContext at message handling
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001914 // time.
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001915 mLogger.log("onFinished result=", result, " endpoint=",
1916 (mSyncOperation == null ? "null" : mSyncOperation.target));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 sendSyncFinishedOrCanceledMessage(this, result);
1918 }
1919
Makoto Onuki5fc60022019-01-15 09:34:05 -08001920 public void toString(StringBuilder sb, boolean logSafe) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 sb.append("startTime ").append(mStartTime)
1922 .append(", mTimeoutStartTime ").append(mTimeoutStartTime)
1923 .append(", mHistoryRowId ").append(mHistoryRowId)
Makoto Onuki5fc60022019-01-15 09:34:05 -08001924 .append(", syncOperation ").append(
1925 logSafe ? logSafe(mSyncOperation) : mSyncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 }
1927
Fred Quintana718d8a22009-04-29 17:53:20 -07001928 public void onServiceConnected(ComponentName name, IBinder service) {
1929 Message msg = mSyncHandler.obtainMessage();
1930 msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001931 msg.obj = new ServiceConnectionData(this, service);
Fred Quintana718d8a22009-04-29 17:53:20 -07001932 mSyncHandler.sendMessage(msg);
1933 }
1934
1935 public void onServiceDisconnected(ComponentName name) {
1936 Message msg = mSyncHandler.obtainMessage();
1937 msg.what = SyncHandler.MESSAGE_SERVICE_DISCONNECTED;
1938 msg.obj = new ServiceConnectionData(this, null);
1939 mSyncHandler.sendMessage(msg);
1940 }
1941
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001942 boolean bindToSyncAdapter(ComponentName serviceComponent, int userId) {
Fred Quintana718d8a22009-04-29 17:53:20 -07001943 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001944 Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
Fred Quintana718d8a22009-04-29 17:53:20 -07001945 }
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001946 Intent intent = getAdapterBindIntent(mContext, serviceComponent, userId);
1947
Fred Quintana3ec47302010-03-10 10:08:31 -08001948 mBound = true;
Amith Yamasani27b89e62013-01-16 12:30:11 -08001949 final boolean bindResult = mContext.bindServiceAsUser(intent, this,
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001950 SYNC_ADAPTER_CONNECTION_FLAGS, new UserHandle(mSyncOperation.target.userId));
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001951 mLogger.log("bindService() returned=", mBound, " for ", this);
Fred Quintana3ec47302010-03-10 10:08:31 -08001952 if (!bindResult) {
1953 mBound = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001954 } else {
1955 try {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08001956 mEventName = mSyncOperation.wakeLockName();
Dianne Hackbornfdb19562014-07-11 16:03:36 -07001957 mBatteryStats.noteSyncStart(mEventName, mSyncAdapterUid);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001958 } catch (RemoteException e) {
1959 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001960 }
1961 return bindResult;
Fred Quintana718d8a22009-04-29 17:53:20 -07001962 }
1963
Fred Quintana918339a2010-10-05 14:00:39 -07001964 /**
1965 * Performs the required cleanup, which is the releasing of the wakelock and
1966 * unbinding from the sync adapter (if actually bound).
1967 */
Fred Quintana3ec47302010-03-10 10:08:31 -08001968 protected void close() {
Fred Quintana718d8a22009-04-29 17:53:20 -07001969 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1970 Log.d(TAG, "unBindFromSyncAdapter: connection " + this);
1971 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001972 if (mBound) {
1973 mBound = false;
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001974 mLogger.log("unbindService for ", this);
Fred Quintana3ec47302010-03-10 10:08:31 -08001975 mContext.unbindService(this);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001976 try {
Dianne Hackbornfdb19562014-07-11 16:03:36 -07001977 mBatteryStats.noteSyncFinish(mEventName, mSyncAdapterUid);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001978 } catch (RemoteException e) {
1979 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001980 }
Fred Quintana918339a2010-10-05 14:00:39 -07001981 mSyncWakeLock.release();
Dianne Hackbornc24ab862011-10-18 15:55:03 -07001982 mSyncWakeLock.setWorkSource(null);
Fred Quintana718d8a22009-04-29 17:53:20 -07001983 }
1984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 public String toString() {
1986 StringBuilder sb = new StringBuilder();
Makoto Onuki5fc60022019-01-15 09:34:05 -08001987 toString(sb, false);
1988 return sb.toString();
1989 }
1990
1991 public String toSafeString() {
1992 StringBuilder sb = new StringBuilder();
1993 toString(sb, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 return sb.toString();
1995 }
Alon Alberteca75112010-12-08 15:02:33 -08001996
1997 @Override
1998 public void binderDied() {
1999 sendSyncFinishedOrCanceledMessage(this, null);
2000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 }
2002
Makoto Onukia9dca242017-06-21 17:06:49 -07002003 protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002004 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
Makoto Onuki75ad2492018-03-28 14:42:42 -07002005
2006 final SyncAdapterStateFetcher buckets = new SyncAdapterStateFetcher();
2007
2008 dumpSyncState(ipw, buckets);
Makoto Onukiaad2b512018-02-07 09:31:46 -08002009 mConstants.dump(pw, "");
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002010 dumpSyncAdapters(ipw);
Makoto Onukia9dca242017-06-21 17:06:49 -07002011
2012 if (dumpAll) {
2013 ipw.println("Detailed Sync History");
2014 mLogger.dumpAll(pw);
2015 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 }
2017
Dianne Hackborn231cc602009-04-27 17:10:36 -07002018 static String formatTime(long time) {
Makoto Onukif74cf942018-04-16 17:04:58 -07002019 if (time == 0) {
2020 return "N/A";
2021 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07002022 Time tobj = new Time();
2023 tobj.set(time);
2024 return tobj.format("%Y-%m-%d %H:%M:%S");
2025 }
Doug Zongker44f57472009-09-20 15:52:43 -07002026
Makoto Onuki15e7a252017-06-08 17:12:05 -07002027 private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
2028 int res = Integer.compare(op1.target.userId, op2.target.userId);
2029 if (res != 0) return res;
2030
2031 final Comparator<String> stringComparator = String.CASE_INSENSITIVE_ORDER;
2032
2033 res = stringComparator.compare(op1.target.account.type, op2.target.account.type);
2034 if (res != 0) return res;
2035
2036 res = stringComparator.compare(op1.target.account.name, op2.target.account.name);
2037 if (res != 0) return res;
2038
2039 res = stringComparator.compare(op1.target.provider, op2.target.provider);
2040 if (res != 0) return res;
2041
2042 res = Integer.compare(op1.reason, op2.reason);
2043 if (res != 0) return res;
2044
2045 res = Long.compare(op1.periodMillis, op2.periodMillis);
2046 if (res != 0) return res;
2047
2048 res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
2049 if (res != 0) return res;
2050
2051 res = Long.compare(op1.jobId, op2.jobId);
2052 if (res != 0) return res;
2053
2054 return 0;
2055 };
2056
2057 private final static Comparator<SyncOperation> sOpRuntimeComparator = (op1, op2) -> {
2058 int res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
2059 if (res != 0) return res;
2060
2061 return sOpDumpComparator.compare(op1, op2);
2062 };
2063
2064 private static <T> int countIf(Collection<T> col, Predicate<T> p) {
2065 int ret = 0;
2066 for (T item : col) {
2067 if (p.test(item)) ret++;
2068 }
2069 return ret;
2070 }
2071
Makoto Onuki75ad2492018-03-28 14:42:42 -07002072 protected void dumpPendingSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00002073 List<SyncOperation> pendingSyncs = getAllPendingSyncs();
Makoto Onuki15e7a252017-06-08 17:12:05 -07002074
2075 pw.print("Pending Syncs: ");
2076 pw.println(countIf(pendingSyncs, op -> !op.isPeriodic));
2077
2078 Collections.sort(pendingSyncs, sOpRuntimeComparator);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002079 int count = 0;
2080 for (SyncOperation op: pendingSyncs) {
2081 if (!op.isPeriodic) {
Makoto Onuki5fc60022019-01-15 09:34:05 -08002082 pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002083 count++;
2084 }
2085 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002086 pw.println();
2087 }
2088
Makoto Onuki75ad2492018-03-28 14:42:42 -07002089 protected void dumpPeriodicSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00002090 List<SyncOperation> pendingSyncs = getAllPendingSyncs();
Makoto Onuki15e7a252017-06-08 17:12:05 -07002091
2092 pw.print("Periodic Syncs: ");
2093 pw.println(countIf(pendingSyncs, op -> op.isPeriodic));
2094
2095 Collections.sort(pendingSyncs, sOpDumpComparator);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002096 int count = 0;
2097 for (SyncOperation op: pendingSyncs) {
2098 if (op.isPeriodic) {
Makoto Onuki5fc60022019-01-15 09:34:05 -08002099 pw.println(op.dump(null, false, buckets, /*logSafe=*/ false));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002100 count++;
2101 }
2102 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002103 pw.println();
2104 }
2105
Makoto Onuki15e7a252017-06-08 17:12:05 -07002106 /**
2107 * Similar to {@link android.util.TimeUtils#formatDuration}, but it's more suitable and concise
2108 * for the sync manager dumpsys. (Don't add the leading + sign, don't show milliseconds.)
2109 */
2110 public static StringBuilder formatDurationHMS(StringBuilder sb, long duration) {
2111 duration /= 1000;
2112 if (duration < 0) {
2113 sb.append('-');
2114 duration = -duration;
2115 }
2116 final long seconds = duration % 60;
2117 duration /= 60;
2118
2119 final long minutes = duration % 60;
2120 duration /= 60;
2121
2122 final long hours = duration % 24;
2123 duration /= 24;
2124
2125 final long days = duration;
2126
2127 boolean print = false;
2128 if (days > 0) {
2129 sb.append(days);
2130 sb.append('d');
2131 print = true;
2132 }
2133 print = printTwoDigitNumber(sb, hours, 'h', print);
2134 print = printTwoDigitNumber(sb, minutes, 'm', print);
2135 print = printTwoDigitNumber(sb, seconds, 's', print);
2136 if (!print) {
2137 sb.append("0s");
2138 }
2139
2140 return sb;
2141 }
2142
2143 private static boolean printTwoDigitNumber(StringBuilder sb, long value, char unit,
2144 boolean always) {
2145 if (!always && (value == 0)) {
2146 return false;
2147 }
2148 if (always && (value < 10)) {
2149 sb.append('0');
2150 }
2151 sb.append(value);
2152 sb.append(unit);
2153 return true;
2154 }
2155
Makoto Onuki75ad2492018-03-28 14:42:42 -07002156 protected void dumpSyncState(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07002157 final StringBuilder sb = new StringBuilder();
2158
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002159 pw.print("Data connected: "); pw.println(mDataConnectionIsConnected);
2160 pw.print("Battery saver: ");
2161 pw.println((mPowerManager != null) && mPowerManager.isPowerSaveMode());
2162
2163 pw.print("Background network restriction: ");
2164 {
2165 final ConnectivityManager cm = getConnectivityManager();
2166 final int status = (cm == null) ? -1 : cm.getRestrictBackgroundStatus();
2167 switch (status) {
2168 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
2169 pw.println(" disabled");
2170 break;
2171 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
2172 pw.println(" whitelisted");
2173 break;
2174 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
2175 pw.println(" enabled");
2176 break;
2177 default:
2178 pw.print("Unknown(");
2179 pw.print(status);
2180 pw.println(")");
2181 break;
2182 }
2183 }
2184
2185 pw.print("Auto sync: ");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002186 List<UserInfo> users = getAllUsers();
2187 if (users != null) {
2188 for (UserInfo user : users) {
2189 pw.print("u" + user.id + "="
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002190 + mSyncStorageEngine.getMasterSyncAutomatically(user.id) + " ");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002191 }
2192 pw.println();
2193 }
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002194 pw.print("Memory low: "); pw.println(mStorageIsLow);
2195 pw.print("Device idle: "); pw.println(mDeviceIsIdle);
2196 pw.print("Reported active: "); pw.println(mReportedSyncActive);
Makoto Onuki94986212018-04-11 16:24:46 -07002197 pw.print("Clock valid: "); pw.println(mSyncStorageEngine.isClockValid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198
Jeff Sharkey6eb96202012-10-10 13:13:54 -07002199 final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002200
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002201 pw.print("Accounts: ");
Fred Quintana53bd2522010-02-05 15:28:12 -08002202 if (accounts != INITIAL_ACCOUNTS_ARRAY) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07002203 pw.println(accounts.length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 } else {
Fred Quintana53bd2522010-02-05 15:28:12 -08002205 pw.println("not known yet");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002207 final long now = SystemClock.elapsedRealtime();
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002208 pw.print("Now: "); pw.print(now);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002209 pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002210
2211 sb.setLength(0);
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002212 pw.print("Uptime: "); pw.print(formatDurationHMS(sb, now));
Makoto Onuki15e7a252017-06-08 17:12:05 -07002213 pw.println();
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002214 pw.print("Time spent syncing: ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002215
2216 sb.setLength(0);
2217 pw.print(formatDurationHMS(sb,
2218 mSyncHandler.mSyncTimeTracker.timeSpentSyncing()));
2219 pw.print(", sync ");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002220 pw.print(mSyncHandler.mSyncTimeTracker.mLastWasSyncing ? "" : "not ");
2221 pw.println("in progress");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222
Fred Quintana918339a2010-10-05 14:00:39 -07002223 pw.println();
2224 pw.println("Active Syncs: " + mActiveSyncContexts.size());
Alon Albert57286f92012-10-09 14:21:38 -07002225 final PackageManager pm = mContext.getPackageManager();
Fred Quintana918339a2010-10-05 14:00:39 -07002226 for (SyncManager.ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07002227 final long durationInSeconds = (now - activeSyncContext.mStartTime);
Fred Quintana918339a2010-10-05 14:00:39 -07002228 pw.print(" ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002229 sb.setLength(0);
2230 pw.print(formatDurationHMS(sb, durationInSeconds));
Fred Quintana918339a2010-10-05 14:00:39 -07002231 pw.print(" - ");
Makoto Onuki5fc60022019-01-15 09:34:05 -08002232 pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets, /*logSafe=*/ false));
Fred Quintana918339a2010-10-05 14:00:39 -07002233 pw.println();
2234 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002235 pw.println();
2236
Makoto Onuki75ad2492018-03-28 14:42:42 -07002237 dumpPendingSyncs(pw, buckets);
2238 dumpPeriodicSyncs(pw, buckets);
Fred Quintana918339a2010-10-05 14:00:39 -07002239
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002240 // Join the installed sync adapter with the accounts list and emit for everything.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002241 pw.println("Sync Status");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002242
2243 final ArrayList<Pair<EndPoint, SyncStatusInfo>> statuses = new ArrayList<>();
2244
Makoto Onuki94986212018-04-11 16:24:46 -07002245 mSyncStorageEngine.resetTodayStats(/* force=*/ false);
2246
Amith Yamasani04e0d262012-02-14 11:50:53 -08002247 for (AccountAndUser account : accounts) {
Alon Albert57286f92012-10-09 14:21:38 -07002248 pw.printf("Account %s u%d %s\n",
2249 account.account.name, account.userId, account.account.type);
2250
2251 pw.println("=======================================================================");
Makoto Onuki94986212018-04-11 16:24:46 -07002252 final PrintTable table = new PrintTable(16);
Alon Albert57286f92012-10-09 14:21:38 -07002253 table.set(0, 0,
2254 "Authority", // 0
2255 "Syncable", // 1
2256 "Enabled", // 2
Makoto Onuki94986212018-04-11 16:24:46 -07002257
2258 "Stats", // 3 "Total", "Today" or "Yesterday".
2259
2260 "Loc", // 4 # of syncs with local sources. (including failures/cancels. )
2261 "Poll", // 5 "poll" syncs.
2262 "Per", // 6 Periodic syncs.
2263 "Feed", // 7 Syncs with a "feed" extra. (subscribedfeeds?)
2264 "User", // 8 User-initiated
2265 "Othr", // 9 Other sources.
2266
2267 "Tot", // 10 Total syncs (including failures / cancels)
2268 "Fail", // 11 (Failure)
2269 "Can", // 12 (Cancel)
2270
2271 "Time", // 13 Total time
2272 "Last Sync", // 14
2273 "Backoff" // 15
Alon Albert57286f92012-10-09 14:21:38 -07002274 );
2275
2276 final List<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> sorted =
2277 Lists.newArrayList();
2278 sorted.addAll(mSyncAdapters.getAllServices(account.userId));
2279 Collections.sort(sorted,
2280 new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002281 @Override
2282 public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00002283 RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002284 return lhs.type.authority.compareTo(rhs.type.authority);
2285 }
2286 });
Alon Albert57286f92012-10-09 14:21:38 -07002287 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType : sorted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002288 if (!syncAdapterType.type.accountType.equals(account.account.type)) {
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002289 continue;
2290 }
Alon Albert57286f92012-10-09 14:21:38 -07002291 int row = table.getNumRows();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002292 Pair<AuthorityInfo, SyncStatusInfo> syncAuthoritySyncStatus =
Georgi Nikolovdbe846b2013-06-25 14:09:56 -07002293 mSyncStorageEngine.getCopyOfAuthorityWithSyncStatus(
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002294 new SyncStorageEngine.EndPoint(
2295 account.account,
2296 syncAdapterType.type.authority,
2297 account.userId));
Georgi Nikolovdbe846b2013-06-25 14:09:56 -07002298 SyncStorageEngine.AuthorityInfo settings = syncAuthoritySyncStatus.first;
2299 SyncStatusInfo status = syncAuthoritySyncStatus.second;
Makoto Onuki15e7a252017-06-08 17:12:05 -07002300 statuses.add(Pair.create(settings.target, status));
Matthew Williams8ef22042013-07-26 12:56:39 -07002301 String authority = settings.target.provider;
Alon Albert57286f92012-10-09 14:21:38 -07002302 if (authority.length() > 50) {
2303 authority = authority.substring(authority.length() - 50);
2304 }
2305 table.set(row, 0, authority, settings.syncable, settings.enabled);
Makoto Onuki15e7a252017-06-08 17:12:05 -07002306
Makoto Onuki94986212018-04-11 16:24:46 -07002307 QuadConsumer<String, Stats, Function<Integer, String>, Integer> c =
2308 (label, stats, filter, r) -> {
2309 sb.setLength(0);
2310 table.set(r, 3,
2311 label,
2312 filter.apply(stats.numSourceLocal),
2313 filter.apply(stats.numSourcePoll),
2314 filter.apply(stats.numSourcePeriodic),
2315 filter.apply(stats.numSourceFeed),
2316 filter.apply(stats.numSourceUser),
2317 filter.apply(stats.numSourceOther),
2318 filter.apply(stats.numSyncs),
2319 filter.apply(stats.numFailures),
2320 filter.apply(stats.numCancels),
2321 formatDurationHMS(sb, stats.totalElapsedTime));
2322 };
2323 c.accept("Total", status.totalStats, (i) -> Integer.toString(i), row);
2324 c.accept("Today", status.todayStats, this::zeroToEmpty, row + 1);
2325 c.accept("Yestr", status.yesterdayStats, this::zeroToEmpty, row + 2);
2326
2327 final int LAST_SYNC = 14;
2328 final int BACKOFF = LAST_SYNC + 1;
Alon Albert57286f92012-10-09 14:21:38 -07002329
Alon Albert57286f92012-10-09 14:21:38 -07002330 int row1 = row;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002331 if (settings.delayUntil > now) {
Makoto Onuki94986212018-04-11 16:24:46 -07002332 table.set(row1++, BACKOFF, "D: " + (settings.delayUntil - now) / 1000);
Alon Albert57286f92012-10-09 14:21:38 -07002333 if (settings.backoffTime > now) {
Makoto Onuki94986212018-04-11 16:24:46 -07002334 table.set(row1++, BACKOFF, "B: " + (settings.backoffTime - now) / 1000);
2335 table.set(row1++, BACKOFF, settings.backoffDelay / 1000);
Alon Albert57286f92012-10-09 14:21:38 -07002336 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002337 }
Alon Albert57286f92012-10-09 14:21:38 -07002338
Makoto Onuki010291d2017-06-06 16:32:47 -07002339 row1 = row;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002340 if (status.lastSuccessTime != 0) {
Makoto Onuki94986212018-04-11 16:24:46 -07002341 table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastSuccessSource]
Alon Albert57286f92012-10-09 14:21:38 -07002342 + " " + "SUCCESS");
Makoto Onuki94986212018-04-11 16:24:46 -07002343 table.set(row1++, LAST_SYNC, formatTime(status.lastSuccessTime));
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002344 }
2345 if (status.lastFailureTime != 0) {
Makoto Onuki94986212018-04-11 16:24:46 -07002346 table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastFailureSource]
Alon Albert57286f92012-10-09 14:21:38 -07002347 + " " + "FAILURE");
Makoto Onuki94986212018-04-11 16:24:46 -07002348 table.set(row1++, LAST_SYNC, formatTime(status.lastFailureTime));
Alon Albert57286f92012-10-09 14:21:38 -07002349 //noinspection UnusedAssignment
Makoto Onuki94986212018-04-11 16:24:46 -07002350 table.set(row1++, LAST_SYNC, status.lastFailureMesg);
Dianne Hackborn231cc602009-04-27 17:10:36 -07002351 }
2352 }
Alon Albert57286f92012-10-09 14:21:38 -07002353 table.writeTo(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002354 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002355
2356 dumpSyncHistory(pw);
2357
2358 pw.println();
2359 pw.println("Per Adapter History");
Makoto Onuki94986212018-04-11 16:24:46 -07002360 pw.println("(SERVER is now split up to FEED and OTHER)");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002361
2362 for (int i = 0; i < statuses.size(); i++) {
2363 final Pair<EndPoint, SyncStatusInfo> event = statuses.get(i);
2364
2365 pw.print(" ");
2366 pw.print(event.first.account.name);
2367 pw.print('/');
2368 pw.print(event.first.account.type);
2369 pw.print(" u");
2370 pw.print(event.first.userId);
2371 pw.print(" [");
2372 pw.print(event.first.provider);
2373 pw.print("]");
2374 pw.println();
2375
Makoto Onukif74cf942018-04-16 17:04:58 -07002376 pw.println(" Per source last syncs:");
2377 for (int j = 0; j < SyncStorageEngine.SOURCES.length; j++) {
2378 pw.print(" ");
2379 pw.print(String.format("%8s", SyncStorageEngine.SOURCES[j]));
2380 pw.print(" Success: ");
2381 pw.print(formatTime(event.second.perSourceLastSuccessTimes[j]));
2382
2383 pw.print(" Failure: ");
2384 pw.println(formatTime(event.second.perSourceLastFailureTimes[j]));
2385 }
2386
2387 pw.println(" Last syncs:");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002388 for (int j = 0; j < event.second.getEventCount(); j++) {
Makoto Onukif74cf942018-04-16 17:04:58 -07002389 pw.print(" ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002390 pw.print(formatTime(event.second.getEventTime(j)));
2391 pw.print(' ');
2392 pw.print(event.second.getEvent(j));
2393 pw.println();
2394 }
Makoto Onukif74cf942018-04-16 17:04:58 -07002395 if (event.second.getEventCount() == 0) {
2396 pw.println(" N/A");
2397 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002399 }
2400
Makoto Onuki94986212018-04-11 16:24:46 -07002401 private String zeroToEmpty(int value) {
2402 return (value != 0) ? Integer.toString(value) : "";
2403 }
2404
Dianne Hackborn231cc602009-04-27 17:10:36 -07002405 private void dumpTimeSec(PrintWriter pw, long time) {
2406 pw.print(time/1000); pw.print('.'); pw.print((time/100)%10);
2407 pw.print('s');
2408 }
Doug Zongker44f57472009-09-20 15:52:43 -07002409
Dianne Hackborn231cc602009-04-27 17:10:36 -07002410 private void dumpDayStatistic(PrintWriter pw, SyncStorageEngine.DayStats ds) {
2411 pw.print("Success ("); pw.print(ds.successCount);
2412 if (ds.successCount > 0) {
2413 pw.print(" for "); dumpTimeSec(pw, ds.successTime);
2414 pw.print(" avg="); dumpTimeSec(pw, ds.successTime/ds.successCount);
2415 }
2416 pw.print(") Failure ("); pw.print(ds.failureCount);
2417 if (ds.failureCount > 0) {
2418 pw.print(" for "); dumpTimeSec(pw, ds.failureTime);
2419 pw.print(" avg="); dumpTimeSec(pw, ds.failureTime/ds.failureCount);
2420 }
2421 pw.println(")");
2422 }
Doug Zongker44f57472009-09-20 15:52:43 -07002423
Alon Alberte0bde332011-09-22 14:26:16 -07002424 protected void dumpSyncHistory(PrintWriter pw) {
2425 dumpRecentHistory(pw);
2426 dumpDayStatistics(pw);
2427 }
2428
2429 private void dumpRecentHistory(PrintWriter pw) {
2430 final ArrayList<SyncStorageEngine.SyncHistoryItem> items
2431 = mSyncStorageEngine.getSyncHistory();
2432 if (items != null && items.size() > 0) {
2433 final Map<String, AuthoritySyncStats> authorityMap = Maps.newHashMap();
2434 long totalElapsedTime = 0;
2435 long totalTimes = 0;
2436 final int N = items.size();
2437
2438 int maxAuthority = 0;
2439 int maxAccount = 0;
2440 for (SyncStorageEngine.SyncHistoryItem item : items) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002441 SyncStorageEngine.AuthorityInfo authorityInfo
Alon Alberte0bde332011-09-22 14:26:16 -07002442 = mSyncStorageEngine.getAuthority(item.authorityId);
2443 final String authorityName;
2444 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002445 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002446 authorityName = authorityInfo.target.provider;
2447 accountKey = authorityInfo.target.account.name + "/"
2448 + authorityInfo.target.account.type
2449 + " u" + authorityInfo.target.userId;
Alon Alberte0bde332011-09-22 14:26:16 -07002450 } else {
2451 authorityName = "Unknown";
2452 accountKey = "Unknown";
2453 }
2454
2455 int length = authorityName.length();
2456 if (length > maxAuthority) {
2457 maxAuthority = length;
2458 }
2459 length = accountKey.length();
2460 if (length > maxAccount) {
2461 maxAccount = length;
2462 }
2463
2464 final long elapsedTime = item.elapsedTime;
2465 totalElapsedTime += elapsedTime;
2466 totalTimes++;
2467 AuthoritySyncStats authoritySyncStats = authorityMap.get(authorityName);
2468 if (authoritySyncStats == null) {
2469 authoritySyncStats = new AuthoritySyncStats(authorityName);
2470 authorityMap.put(authorityName, authoritySyncStats);
2471 }
2472 authoritySyncStats.elapsedTime += elapsedTime;
2473 authoritySyncStats.times++;
2474 final Map<String, AccountSyncStats> accountMap = authoritySyncStats.accountMap;
2475 AccountSyncStats accountSyncStats = accountMap.get(accountKey);
2476 if (accountSyncStats == null) {
2477 accountSyncStats = new AccountSyncStats(accountKey);
2478 accountMap.put(accountKey, accountSyncStats);
2479 }
2480 accountSyncStats.elapsedTime += elapsedTime;
2481 accountSyncStats.times++;
2482
2483 }
2484
Alon Albert27096822012-01-11 18:06:41 -08002485 if (totalElapsedTime > 0) {
2486 pw.println();
2487 pw.printf("Detailed Statistics (Recent history): "
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002488 + "%d (# of times) %ds (sync time)\n",
Alon Albert27096822012-01-11 18:06:41 -08002489 totalTimes, totalElapsedTime / 1000);
Alon Alberte0bde332011-09-22 14:26:16 -07002490
Alon Albert27096822012-01-11 18:06:41 -08002491 final List<AuthoritySyncStats> sortedAuthorities =
2492 new ArrayList<AuthoritySyncStats>(authorityMap.values());
2493 Collections.sort(sortedAuthorities, new Comparator<AuthoritySyncStats>() {
Alon Albertbf976ba2011-10-03 13:06:43 -07002494 @Override
Alon Albert27096822012-01-11 18:06:41 -08002495 public int compare(AuthoritySyncStats lhs, AuthoritySyncStats rhs) {
Alon Albertbf976ba2011-10-03 13:06:43 -07002496 // reverse order
2497 int compare = Integer.compare(rhs.times, lhs.times);
2498 if (compare == 0) {
2499 compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
Alon Alberte0bde332011-09-22 14:26:16 -07002500 }
Alon Albertbf976ba2011-10-03 13:06:43 -07002501 return compare;
Alon Alberte0bde332011-09-22 14:26:16 -07002502 }
Alon Albertbf976ba2011-10-03 13:06:43 -07002503 });
Alon Albert27096822012-01-11 18:06:41 -08002504
2505 final int maxLength = Math.max(maxAuthority, maxAccount + 3);
2506 final int padLength = 2 + 2 + maxLength + 2 + 10 + 11;
2507 final char chars[] = new char[padLength];
2508 Arrays.fill(chars, '-');
2509 final String separator = new String(chars);
2510
2511 final String authorityFormat =
2512 String.format(" %%-%ds: %%-9s %%-11s\n", maxLength + 2);
2513 final String accountFormat =
2514 String.format(" %%-%ds: %%-9s %%-11s\n", maxLength);
2515
2516 pw.println(separator);
2517 for (AuthoritySyncStats authoritySyncStats : sortedAuthorities) {
2518 String name = authoritySyncStats.name;
2519 long elapsedTime;
2520 int times;
2521 String timeStr;
2522 String timesStr;
2523
2524 elapsedTime = authoritySyncStats.elapsedTime;
2525 times = authoritySyncStats.times;
Alon Albertbf976ba2011-10-03 13:06:43 -07002526 timeStr = String.format("%ds/%d%%",
2527 elapsedTime / 1000,
2528 elapsedTime * 100 / totalElapsedTime);
2529 timesStr = String.format("%d/%d%%",
2530 times,
2531 times * 100 / totalTimes);
Alon Albert27096822012-01-11 18:06:41 -08002532 pw.printf(authorityFormat, name, timesStr, timeStr);
2533
2534 final List<AccountSyncStats> sortedAccounts =
2535 new ArrayList<AccountSyncStats>(
2536 authoritySyncStats.accountMap.values());
2537 Collections.sort(sortedAccounts, new Comparator<AccountSyncStats>() {
2538 @Override
2539 public int compare(AccountSyncStats lhs, AccountSyncStats rhs) {
2540 // reverse order
2541 int compare = Integer.compare(rhs.times, lhs.times);
2542 if (compare == 0) {
2543 compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
2544 }
2545 return compare;
2546 }
2547 });
2548 for (AccountSyncStats stats: sortedAccounts) {
2549 elapsedTime = stats.elapsedTime;
2550 times = stats.times;
2551 timeStr = String.format("%ds/%d%%",
2552 elapsedTime / 1000,
2553 elapsedTime * 100 / totalElapsedTime);
2554 timesStr = String.format("%d/%d%%",
2555 times,
2556 times * 100 / totalTimes);
2557 pw.printf(accountFormat, stats.name, timesStr, timeStr);
2558 }
2559 pw.println(separator);
Alon Alberte0bde332011-09-22 14:26:16 -07002560 }
Alon Alberte0bde332011-09-22 14:26:16 -07002561 }
2562
2563 pw.println();
2564 pw.println("Recent Sync History");
Makoto Onuki94986212018-04-11 16:24:46 -07002565 pw.println("(SERVER is now split up to FEED and OTHER)");
Alon Albert57286f92012-10-09 14:21:38 -07002566 final String format = " %-" + maxAccount + "s %-" + maxAuthority + "s %s\n";
Alon Albertbf976ba2011-10-03 13:06:43 -07002567 final Map<String, Long> lastTimeMap = Maps.newHashMap();
Alon Albert57286f92012-10-09 14:21:38 -07002568 final PackageManager pm = mContext.getPackageManager();
Alon Alberte0bde332011-09-22 14:26:16 -07002569 for (int i = 0; i < N; i++) {
2570 SyncStorageEngine.SyncHistoryItem item = items.get(i);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002571 SyncStorageEngine.AuthorityInfo authorityInfo
Alon Alberte0bde332011-09-22 14:26:16 -07002572 = mSyncStorageEngine.getAuthority(item.authorityId);
2573 final String authorityName;
2574 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002575 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002576 authorityName = authorityInfo.target.provider;
2577 accountKey = authorityInfo.target.account.name + "/"
2578 + authorityInfo.target.account.type
2579 + " u" + authorityInfo.target.userId;
Alon Alberte0bde332011-09-22 14:26:16 -07002580 } else {
2581 authorityName = "Unknown";
2582 accountKey = "Unknown";
2583 }
2584 final long elapsedTime = item.elapsedTime;
2585 final Time time = new Time();
2586 final long eventTime = item.eventTime;
2587 time.set(eventTime);
2588
Alon Albertbf976ba2011-10-03 13:06:43 -07002589 final String key = authorityName + "/" + accountKey;
2590 final Long lastEventTime = lastTimeMap.get(key);
2591 final String diffString;
2592 if (lastEventTime == null) {
2593 diffString = "";
2594 } else {
2595 final long diff = (lastEventTime - eventTime) / 1000;
2596 if (diff < 60) {
2597 diffString = String.valueOf(diff);
2598 } else if (diff < 3600) {
2599 diffString = String.format("%02d:%02d", diff / 60, diff % 60);
2600 } else {
2601 final long sec = diff % 3600;
2602 diffString = String.format("%02d:%02d:%02d",
2603 diff / 3600, sec / 60, sec % 60);
2604 }
2605 }
2606 lastTimeMap.put(key, eventTime);
2607
2608 pw.printf(" #%-3d: %s %8s %5.1fs %8s",
Alon Alberte0bde332011-09-22 14:26:16 -07002609 i + 1,
2610 formatTime(eventTime),
2611 SyncStorageEngine.SOURCES[item.source],
Alon Albertbf976ba2011-10-03 13:06:43 -07002612 ((float) elapsedTime) / 1000,
2613 diffString);
Alon Albert57286f92012-10-09 14:21:38 -07002614 pw.printf(format, accountKey, authorityName,
2615 SyncOperation.reasonToString(pm, item.reason));
Alon Alberte0bde332011-09-22 14:26:16 -07002616
2617 if (item.event != SyncStorageEngine.EVENT_STOP
2618 || item.upstreamActivity != 0
2619 || item.downstreamActivity != 0) {
2620 pw.printf(" event=%d upstreamActivity=%d downstreamActivity=%d\n",
2621 item.event,
2622 item.upstreamActivity,
2623 item.downstreamActivity);
2624 }
2625 if (item.mesg != null
2626 && !SyncStorageEngine.MESG_SUCCESS.equals(item.mesg)) {
2627 pw.printf(" mesg=%s\n", item.mesg);
2628 }
2629 }
Alon Albert57286f92012-10-09 14:21:38 -07002630 pw.println();
2631 pw.println("Recent Sync History Extras");
Makoto Onuki94986212018-04-11 16:24:46 -07002632 pw.println("(SERVER is now split up to FEED and OTHER)");
Alon Albert57286f92012-10-09 14:21:38 -07002633 for (int i = 0; i < N; i++) {
2634 final SyncStorageEngine.SyncHistoryItem item = items.get(i);
2635 final Bundle extras = item.extras;
2636 if (extras == null || extras.size() == 0) {
2637 continue;
2638 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002639 final SyncStorageEngine.AuthorityInfo authorityInfo
Alon Albert57286f92012-10-09 14:21:38 -07002640 = mSyncStorageEngine.getAuthority(item.authorityId);
2641 final String authorityName;
2642 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002643 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002644 authorityName = authorityInfo.target.provider;
2645 accountKey = authorityInfo.target.account.name + "/"
2646 + authorityInfo.target.account.type
2647 + " u" + authorityInfo.target.userId;
Alon Albert57286f92012-10-09 14:21:38 -07002648 } else {
2649 authorityName = "Unknown";
2650 accountKey = "Unknown";
2651 }
2652 final Time time = new Time();
2653 final long eventTime = item.eventTime;
2654 time.set(eventTime);
2655
2656 pw.printf(" #%-3d: %s %8s ",
2657 i + 1,
2658 formatTime(eventTime),
2659 SyncStorageEngine.SOURCES[item.source]);
2660
2661 pw.printf(format, accountKey, authorityName, extras);
2662 }
Alon Alberte0bde332011-09-22 14:26:16 -07002663 }
2664 }
2665
2666 private void dumpDayStatistics(PrintWriter pw) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07002667 SyncStorageEngine.DayStats dses[] = mSyncStorageEngine.getDayStatistics();
2668 if (dses != null && dses[0] != null) {
2669 pw.println();
2670 pw.println("Sync Statistics");
2671 pw.print(" Today: "); dumpDayStatistic(pw, dses[0]);
2672 int today = dses[0].day;
2673 int i;
2674 SyncStorageEngine.DayStats ds;
Doug Zongker44f57472009-09-20 15:52:43 -07002675
Dianne Hackborn231cc602009-04-27 17:10:36 -07002676 // Print each day in the current week.
2677 for (i=1; i<=6 && i < dses.length; i++) {
2678 ds = dses[i];
2679 if (ds == null) break;
2680 int delta = today-ds.day;
2681 if (delta > 6) break;
Doug Zongker44f57472009-09-20 15:52:43 -07002682
Dianne Hackborn231cc602009-04-27 17:10:36 -07002683 pw.print(" Day-"); pw.print(delta); pw.print(": ");
2684 dumpDayStatistic(pw, ds);
2685 }
Doug Zongker44f57472009-09-20 15:52:43 -07002686
Dianne Hackborn231cc602009-04-27 17:10:36 -07002687 // Aggregate all following days into weeks and print totals.
2688 int weekDay = today;
2689 while (i < dses.length) {
2690 SyncStorageEngine.DayStats aggr = null;
2691 weekDay -= 7;
2692 while (i < dses.length) {
2693 ds = dses[i];
2694 if (ds == null) {
2695 i = dses.length;
2696 break;
2697 }
2698 int delta = weekDay-ds.day;
2699 if (delta > 6) break;
2700 i++;
Doug Zongker44f57472009-09-20 15:52:43 -07002701
Dianne Hackborn231cc602009-04-27 17:10:36 -07002702 if (aggr == null) {
2703 aggr = new SyncStorageEngine.DayStats(weekDay);
2704 }
2705 aggr.successCount += ds.successCount;
2706 aggr.successTime += ds.successTime;
2707 aggr.failureCount += ds.failureCount;
2708 aggr.failureTime += ds.failureTime;
2709 }
2710 if (aggr != null) {
2711 pw.print(" Week-"); pw.print((today-weekDay)/7); pw.print(": ");
2712 dumpDayStatistic(pw, aggr);
2713 }
2714 }
2715 }
Alon Alberte0bde332011-09-22 14:26:16 -07002716 }
Doug Zongker44f57472009-09-20 15:52:43 -07002717
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002718 private void dumpSyncAdapters(IndentingPrintWriter pw) {
2719 pw.println();
2720 final List<UserInfo> users = getAllUsers();
2721 if (users != null) {
2722 for (UserInfo user : users) {
2723 pw.println("Sync adapters for " + user + ":");
2724 pw.increaseIndent();
2725 for (RegisteredServicesCache.ServiceInfo<?> info :
2726 mSyncAdapters.getAllServices(user.id)) {
2727 pw.println(info);
2728 }
2729 pw.decreaseIndent();
2730 pw.println();
2731 }
2732 }
2733 }
2734
Alon Alberte0bde332011-09-22 14:26:16 -07002735 private static class AuthoritySyncStats {
2736 String name;
2737 long elapsedTime;
2738 int times;
2739 Map<String, AccountSyncStats> accountMap = Maps.newHashMap();
2740
2741 private AuthoritySyncStats(String name) {
2742 this.name = name;
2743 }
2744 }
2745
2746 private static class AccountSyncStats {
2747 String name;
2748 long elapsedTime;
2749 int times;
2750
2751 private AccountSyncStats(String name) {
2752 this.name = name;
Dianne Hackborn231cc602009-04-27 17:10:36 -07002753 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002754 }
2755
Philip P. Moltmann486b2412018-01-03 11:29:01 -08002756 interface OnReadyCallback {
2757 void onReady();
2758 }
2759
2760 static void sendOnUnsyncableAccount(@NonNull Context context,
2761 @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
2762 @UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) {
2763 OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo,
2764 onReadyCallback);
2765
2766 boolean isBound = context.bindServiceAsUser(
2767 getAdapterBindIntent(context, syncAdapterInfo.componentName, userId),
2768 connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId));
2769
2770 if (isBound) {
2771 // Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection.
2772 (new Handler(Looper.getMainLooper())).postDelayed(
2773 () -> context.unbindService(connection),
2774 OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS);
2775 } else {
2776 /*
2777 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
2778 * there the service cannot be bound, assume the default behavior.
2779 */
2780 connection.onReady();
2781 }
2782 }
2783
2784
2785 /**
2786 * Helper class for calling ISyncAdapter.onUnsyncableAccountDone.
2787 *
2788 * If this returns {@code true} the onReadyCallback is called. Otherwise nothing happens.
2789 */
2790 private static class OnUnsyncableAccountCheck implements ServiceConnection {
2791 static final long SERVICE_BOUND_TIME_MILLIS = 5000;
2792
2793 private final @NonNull OnReadyCallback mOnReadyCallback;
2794 private final @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType>
2795 mSyncAdapterInfo;
2796
2797 OnUnsyncableAccountCheck(
2798 @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
2799 @NonNull OnReadyCallback onReadyCallback) {
2800 mSyncAdapterInfo = syncAdapterInfo;
2801 mOnReadyCallback = onReadyCallback;
2802 }
2803
2804 private void onReady() {
2805 long identity = Binder.clearCallingIdentity();
2806 try {
2807 mOnReadyCallback.onReady();
2808 } finally {
2809 Binder.restoreCallingIdentity(identity);
2810 }
2811 }
2812
2813 @Override
2814 public void onServiceConnected(ComponentName name, IBinder service) {
2815 final ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
2816
2817 try {
2818 adapter.onUnsyncableAccount(new ISyncAdapterUnsyncableAccountCallback.Stub() {
2819 @Override
2820 public void onUnsyncableAccountDone(boolean isReady) {
2821 if (isReady) {
2822 onReady();
2823 }
2824 }
2825 });
2826 } catch (RemoteException e) {
2827 Slog.e(TAG, "Could not call onUnsyncableAccountDone " + mSyncAdapterInfo, e);
2828 /*
2829 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
2830 * there is a crash in the implementation, assume the default behavior.
2831 */
2832 onReady();
2833 }
2834 }
2835
2836 @Override
2837 public void onServiceDisconnected(ComponentName name) {
2838 // Wait until the service connects again
2839 }
2840 }
2841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002842 /**
2843 * A helper object to keep track of the time we have spent syncing since the last boot
2844 */
2845 private class SyncTimeTracker {
2846 /** True if a sync was in progress on the most recent call to update() */
2847 boolean mLastWasSyncing = false;
2848 /** Used to track when lastWasSyncing was last set */
2849 long mWhenSyncStarted = 0;
2850 /** The cumulative time we have spent syncing */
2851 private long mTimeSpentSyncing;
2852
2853 /** Call to let the tracker know that the sync state may have changed */
2854 public synchronized void update() {
Fred Quintana918339a2010-10-05 14:00:39 -07002855 final boolean isSyncInProgress = !mActiveSyncContexts.isEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002856 if (isSyncInProgress == mLastWasSyncing) return;
2857 final long now = SystemClock.elapsedRealtime();
2858 if (isSyncInProgress) {
2859 mWhenSyncStarted = now;
2860 } else {
2861 mTimeSpentSyncing += now - mWhenSyncStarted;
2862 }
2863 mLastWasSyncing = isSyncInProgress;
2864 }
2865
2866 /** Get how long we have been syncing, in ms */
2867 public synchronized long timeSpentSyncing() {
2868 if (!mLastWasSyncing) return mTimeSpentSyncing;
2869
2870 final long now = SystemClock.elapsedRealtime();
2871 return mTimeSpentSyncing + (now - mWhenSyncStarted);
2872 }
2873 }
2874
Fred Quintana718d8a22009-04-29 17:53:20 -07002875 class ServiceConnectionData {
2876 public final ActiveSyncContext activeSyncContext;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002877 public final IBinder adapter;
2878
2879 ServiceConnectionData(ActiveSyncContext activeSyncContext, IBinder adapter) {
Fred Quintana718d8a22009-04-29 17:53:20 -07002880 this.activeSyncContext = activeSyncContext;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002881 this.adapter = adapter;
Fred Quintana718d8a22009-04-29 17:53:20 -07002882 }
2883 }
2884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002885 /**
Makoto Onuki056a9752018-05-08 15:21:56 -07002886 * @return whether the device is ready to run sync jobs.
2887 */
2888 public static boolean readyToSync() {
2889 synchronized (SyncManager.class) {
2890 return sInstance != null && sInstance.mProvisioned && sInstance.mBootCompleted
2891 && sInstance.mJobServiceReady;
2892 }
2893 }
2894
2895 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002896 * Handles SyncOperation Messages that are posted to the associated
2897 * HandlerThread.
2898 */
2899 class SyncHandler extends Handler {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002900 // Messages that can be sent on mHandler.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002901 private static final int MESSAGE_SYNC_FINISHED = 1;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002902 private static final int MESSAGE_RELEASE_MESSAGES_FROM_QUEUE = 2;
Fred Quintana718d8a22009-04-29 17:53:20 -07002903 private static final int MESSAGE_SERVICE_CONNECTED = 4;
2904 private static final int MESSAGE_SERVICE_DISCONNECTED = 5;
Fred Quintana918339a2010-10-05 14:00:39 -07002905 private static final int MESSAGE_CANCEL = 6;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002906 static final int MESSAGE_JOBSERVICE_OBJECT = 7;
2907 static final int MESSAGE_START_SYNC = 10;
2908 static final int MESSAGE_STOP_SYNC = 11;
2909 static final int MESSAGE_SCHEDULE_SYNC = 12;
2910 static final int MESSAGE_UPDATE_PERIODIC_SYNC = 13;
2911 static final int MESSAGE_REMOVE_PERIODIC_SYNC = 14;
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002912
Matthew Williams1967c8d2015-06-19 19:03:13 -07002913 /**
2914 * Posted periodically to monitor network process for long-running syncs.
2915 * obj: {@link com.android.server.content.SyncManager.ActiveSyncContext}
2916 */
2917 private static final int MESSAGE_MONITOR_SYNC = 8;
振淦王60a74312015-12-01 16:37:31 +08002918 private static final int MESSAGE_ACCOUNTS_UPDATED = 9;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002921 private final HashMap<String, PowerManager.WakeLock> mWakeLocks = Maps.newHashMap();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002922
Matthew Williams8b76d202015-05-03 18:16:25 -07002923 private List<Message> mUnreadyQueue = new ArrayList<Message>();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002924
Matthew Williams8b76d202015-05-03 18:16:25 -07002925 void onBootCompleted() {
Matthew Williams8704fc32013-09-27 11:32:35 -07002926 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002927 Slog.v(TAG, "Boot completed.");
Matthew Williams8704fc32013-09-27 11:32:35 -07002928 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002929 checkIfDeviceReady();
Matthew Williams8b76d202015-05-03 18:16:25 -07002930 }
2931
2932 void onDeviceProvisioned() {
2933 if (Log.isLoggable(TAG, Log.DEBUG)) {
2934 Log.d(TAG, "mProvisioned=" + mProvisioned);
2935 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002936 checkIfDeviceReady();
2937 }
2938
2939 void checkIfDeviceReady() {
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002940 if (mProvisioned && mBootCompleted && mJobServiceReady) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002941 synchronized(this) {
Shreyas Basarge3147bbc2016-02-19 23:51:40 +00002942 mSyncStorageEngine.restoreAllPeriodicSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002943 // Dispatch any stashed messages.
2944 obtainMessage(MESSAGE_RELEASE_MESSAGES_FROM_QUEUE).sendToTarget();
2945 }
Matthew Williams8b76d202015-05-03 18:16:25 -07002946 }
2947 }
2948
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002949 /**
2950 * Stash any messages that come to the handler before boot is complete or before the device
2951 * is properly provisioned (i.e. out of set-up wizard).
2952 * {@link #onBootCompleted()} and {@link SyncHandler#onDeviceProvisioned} both
2953 * need to come in before we start syncing.
2954 * @param msg Message to dispatch at a later point.
2955 * @return true if a message was enqueued, false otherwise. This is to avoid losing the
2956 * message if we manage to acquire the lock but by the time we do boot has completed.
2957 */
2958 private boolean tryEnqueueMessageUntilReadyToRun(Message msg) {
2959 synchronized (this) {
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002960 if (!mBootCompleted || !mProvisioned || !mJobServiceReady) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002961 // Need to copy the message bc looper will recycle it.
2962 Message m = Message.obtain(msg);
2963 mUnreadyQueue.add(m);
2964 return true;
2965 } else {
2966 return false;
Matthew Williams8704fc32013-09-27 11:32:35 -07002967 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002968 }
2969 }
2970
2971 public SyncHandler(Looper looper) {
2972 super(looper);
2973 }
2974
2975 public void handleMessage(Message msg) {
2976 try {
2977 mSyncManagerWakeLock.acquire();
2978 // We only want to enqueue sync related messages until device is ready.
2979 // Other messages are handled without enqueuing.
2980 if (msg.what == MESSAGE_JOBSERVICE_OBJECT) {
2981 Slog.i(TAG, "Got SyncJobService instance.");
2982 mSyncJobService = (SyncJobService) msg.obj;
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002983 mJobServiceReady = true;
2984 checkIfDeviceReady();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002985 } else if (msg.what == SyncHandler.MESSAGE_ACCOUNTS_UPDATED) {
2986 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2987 Slog.v(TAG, "handleSyncHandlerMessage: MESSAGE_ACCOUNTS_UPDATED");
2988 }
2989 EndPoint targets = (EndPoint) msg.obj;
2990 updateRunningAccountsH(targets);
2991 } else if (msg.what == MESSAGE_RELEASE_MESSAGES_FROM_QUEUE) {
2992 if (mUnreadyQueue != null) {
2993 for (Message m : mUnreadyQueue) {
2994 handleSyncMessage(m);
2995 }
2996 mUnreadyQueue = null;
2997 }
2998 } else if (tryEnqueueMessageUntilReadyToRun(msg)) {
2999 // No work to be done.
3000 } else {
3001 handleSyncMessage(msg);
3002 }
3003 } finally {
3004 mSyncManagerWakeLock.release();
3005 }
3006 }
3007
3008 private void handleSyncMessage(Message msg) {
3009 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3010
3011 try {
3012 mDataConnectionIsConnected = readDataConnectionState();
3013 switch (msg.what) {
3014 case MESSAGE_SCHEDULE_SYNC:
Shreyas Basargeba1f7902016-10-01 00:19:44 +01003015 ScheduleSyncMessagePayload syncPayload =
3016 (ScheduleSyncMessagePayload) msg.obj;
3017 SyncOperation op = syncPayload.syncOperation;
3018 scheduleSyncOperationH(op, syncPayload.minDelayMillis);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003019 break;
3020
3021 case MESSAGE_START_SYNC:
3022 op = (SyncOperation) msg.obj;
3023 startSyncH(op);
3024 break;
3025
3026 case MESSAGE_STOP_SYNC:
3027 op = (SyncOperation) msg.obj;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003028 if (isLoggable) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003029 Slog.v(TAG, "Stop sync received.");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003030 }
3031 ActiveSyncContext asc = findActiveSyncContextH(op.jobId);
3032 if (asc != null) {
3033 runSyncFinishedOrCanceledH(null /* no result */, asc);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003034 boolean reschedule = msg.arg1 != 0;
3035 boolean applyBackoff = msg.arg2 != 0;
3036 if (isLoggable) {
3037 Slog.v(TAG, "Stopping sync. Reschedule: " + reschedule
3038 + "Backoff: " + applyBackoff);
3039 }
3040 if (applyBackoff) {
3041 increaseBackoffSetting(op.target);
3042 }
3043 if (reschedule) {
3044 deferStoppedSyncH(op, 0);
3045 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003046 }
3047 break;
3048
3049 case MESSAGE_UPDATE_PERIODIC_SYNC:
3050 UpdatePeriodicSyncMessagePayload data =
3051 (UpdatePeriodicSyncMessagePayload) msg.obj;
3052 updateOrAddPeriodicSyncH(data.target, data.pollFrequency,
3053 data.flex, data.extras);
3054 break;
3055 case MESSAGE_REMOVE_PERIODIC_SYNC:
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003056 Pair<EndPoint, String> args = (Pair<EndPoint, String>) (msg.obj);
3057 removePeriodicSyncH(args.first, msg.getData(), args.second);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003058 break;
3059
3060 case SyncHandler.MESSAGE_CANCEL:
3061 SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
3062 Bundle extras = msg.peekData();
Makoto Onuki5fc60022019-01-15 09:34:05 -08003063 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003064 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_CANCEL: "
3065 + endpoint + " bundle: " + extras);
3066 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003067 cancelActiveSyncH(endpoint, extras, "MESSAGE_CANCEL");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003068 break;
3069
3070 case SyncHandler.MESSAGE_SYNC_FINISHED:
3071 SyncFinishedOrCancelledMessagePayload payload =
3072 (SyncFinishedOrCancelledMessagePayload) msg.obj;
3073 if (!isSyncStillActiveH(payload.activeSyncContext)) {
Makoto Onuki5fc60022019-01-15 09:34:05 -08003074 if (isLoggable) {
3075 Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
3076 + "sync is no longer active: "
3077 + payload.activeSyncContext);
3078 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003079 break;
3080 }
3081 if (isLoggable) {
3082 Slog.v(TAG, "syncFinished" + payload.activeSyncContext.mSyncOperation);
3083 }
3084 mSyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003085 payload.activeSyncContext.mSyncOperation.jobId, false,
3086 "sync finished");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003087 runSyncFinishedOrCanceledH(payload.syncResult,
3088 payload.activeSyncContext);
3089 break;
3090
3091 case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
3092 ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
Makoto Onuki5fc60022019-01-15 09:34:05 -08003093 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003094 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
3095 + msgData.activeSyncContext);
3096 }
3097 // Check that this isn't an old message.
3098 if (isSyncStillActiveH(msgData.activeSyncContext)) {
3099 runBoundToAdapterH(
3100 msgData.activeSyncContext,
3101 msgData.adapter);
3102 }
3103 break;
3104 }
3105
3106 case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
3107 final ActiveSyncContext currentSyncContext =
3108 ((ServiceConnectionData) msg.obj).activeSyncContext;
Makoto Onuki5fc60022019-01-15 09:34:05 -08003109 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003110 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
3111 + currentSyncContext);
3112 }
3113 // Check that this isn't an old message.
3114 if (isSyncStillActiveH(currentSyncContext)) {
3115 // cancel the sync if we have a syncadapter, which means one is
3116 // outstanding
3117 try {
3118 if (currentSyncContext.mSyncAdapter != null) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003119 mLogger.log("Calling cancelSync for SERVICE_DISCONNECTED ",
3120 currentSyncContext,
3121 " adapter=", currentSyncContext.mSyncAdapter);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003122 currentSyncContext.mSyncAdapter.cancelSync(currentSyncContext);
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003123 mLogger.log("Canceled");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003124 }
3125 } catch (RemoteException e) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003126 mLogger.log("RemoteException ", Log.getStackTraceString(e));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003127 // We don't need to retry this in this case.
3128 }
3129
3130 // Pretend that the sync failed with an IOException,
3131 // which is a soft error.
3132 SyncResult syncResult = new SyncResult();
3133 syncResult.stats.numIoExceptions++;
3134 mSyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003135 currentSyncContext.mSyncOperation.jobId, false,
3136 "service disconnected");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003137 runSyncFinishedOrCanceledH(syncResult, currentSyncContext);
3138 }
3139 break;
3140 }
3141
3142 case SyncHandler.MESSAGE_MONITOR_SYNC:
3143 ActiveSyncContext monitoredSyncContext = (ActiveSyncContext) msg.obj;
Makoto Onuki5fc60022019-01-15 09:34:05 -08003144 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003145 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_MONITOR_SYNC: " +
3146 monitoredSyncContext.mSyncOperation.target);
3147 }
3148
3149 if (isSyncNotUsingNetworkH(monitoredSyncContext)) {
3150 Log.w(TAG, String.format(
3151 "Detected sync making no progress for %s. cancelling.",
Makoto Onuki5fc60022019-01-15 09:34:05 -08003152 logSafe(monitoredSyncContext)));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003153 mSyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003154 monitoredSyncContext.mSyncOperation.jobId, false,
3155 "no network activity");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003156 runSyncFinishedOrCanceledH(
3157 null /* cancel => no result */, monitoredSyncContext);
3158 } else {
3159 // Repost message to check again.
3160 postMonitorSyncProgressMessage(monitoredSyncContext);
3161 }
3162 break;
3163
3164 }
3165 } finally {
3166 mSyncTimeTracker.update();
Fred Quintanae91ebe22009-09-29 20:44:30 -07003167 }
3168 }
3169
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003170 private PowerManager.WakeLock getSyncWakeLock(SyncOperation operation) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08003171 final String wakeLockKey = operation.wakeLockName();
Fred Quintanab3029c32010-04-06 13:27:12 -07003172 PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
3173 if (wakeLock == null) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08003174 final String name = SYNC_WAKE_LOCK_PREFIX + wakeLockKey;
Fred Quintanab3029c32010-04-06 13:27:12 -07003175 wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
3176 wakeLock.setReferenceCounted(false);
3177 mWakeLocks.put(wakeLockKey, wakeLock);
3178 }
3179 return wakeLock;
3180 }
3181
Matthew Williams8704fc32013-09-27 11:32:35 -07003182 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003183 * Defer the specified SyncOperation by rescheduling it on the JobScheduler with some
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003184 * delay. This is equivalent to a failure. If this is a periodic sync, a delayed one-off
3185 * sync will be scheduled.
Matthew Williams8704fc32013-09-27 11:32:35 -07003186 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003187 private void deferSyncH(SyncOperation op, long delay, String why) {
3188 mLogger.log("deferSyncH() ", (op.isPeriodic ? "periodic " : ""),
3189 "sync. op=", op, " delay=", delay, " why=", why);
3190 mSyncJobService.callJobFinished(op.jobId, false, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003191 if (op.isPeriodic) {
3192 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
3193 } else {
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003194 // mSyncJobService.callJobFinished is async, so cancel the job to ensure we don't
3195 // find the this job in the pending jobs list while looking for duplicates
3196 // before scheduling it at a later time.
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003197 cancelJob(op, "deferSyncH()");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003198 scheduleSyncOperationH(op, delay);
Fred Quintanae91ebe22009-09-29 20:44:30 -07003199 }
3200 }
Matthew Williams8704fc32013-09-27 11:32:35 -07003201
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003202 /* Same as deferSyncH, but assumes that job is no longer running on JobScheduler. */
3203 private void deferStoppedSyncH(SyncOperation op, long delay) {
3204 if (op.isPeriodic) {
3205 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
3206 } else {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003207 scheduleSyncOperationH(op, delay);
3208 }
3209 }
3210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003212 * Cancel an active sync and reschedule it on the JobScheduler with some delay.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003213 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003214 private void deferActiveSyncH(ActiveSyncContext asc, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003215 SyncOperation op = asc.mSyncOperation;
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003216 runSyncFinishedOrCanceledH(null, asc);
Makoto Onukia9dca242017-06-21 17:06:49 -07003217 deferSyncH(op, SYNC_DELAY_ON_CONFLICT, why);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003218 }
3219
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003220 private void startSyncH(SyncOperation op) {
3221 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3222 if (isLoggable) Slog.v(TAG, op.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223
Makoto Onuki94986212018-04-11 16:24:46 -07003224 // At this point, we know the device has been connected to the server, so
3225 // assume the clock is correct.
3226 mSyncStorageEngine.setClockValid();
3227
Makoto Onuki5397be12017-12-20 16:22:34 +09003228 mSyncJobService.markSyncStarted(op.jobId);
3229
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003230 if (mStorageIsLow) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003231 deferSyncH(op, SYNC_DELAY_ON_LOW_STORAGE, "storage low");
Matthew Williams8704fc32013-09-27 11:32:35 -07003232 return;
3233 }
3234
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003235 if (op.isPeriodic) {
3236 // Don't allow this periodic to run if a previous instance failed and is currently
3237 // scheduled according to some backoff criteria.
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003238 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003239 for (SyncOperation syncOperation: ops) {
3240 if (syncOperation.sourcePeriodicId == op.jobId) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003241 mSyncJobService.callJobFinished(op.jobId, false,
3242 "periodic sync, pending");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003243 return;
Fred Quintana718d8a22009-04-29 17:53:20 -07003244 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003245 }
3246 // Don't allow this periodic to run if a previous instance failed and is currently
3247 // executing according to some backoff criteria.
3248 for (ActiveSyncContext asc: mActiveSyncContexts) {
3249 if (asc.mSyncOperation.sourcePeriodicId == op.jobId) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003250 mSyncJobService.callJobFinished(op.jobId, false,
3251 "periodic sync, already running");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003252 return;
Fred Quintana718d8a22009-04-29 17:53:20 -07003253 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003254 }
3255 // Check for adapter delays.
3256 if (isAdapterDelayed(op.target)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003257 deferSyncH(op, 0 /* No minimum delay */, "backing off");
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003258 return;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003259 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003260 }
Fred Quintana718d8a22009-04-29 17:53:20 -07003261
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003262 // Check for conflicting syncs.
3263 for (ActiveSyncContext asc: mActiveSyncContexts) {
3264 if (asc.mSyncOperation.isConflict(op)) {
3265 // If the provided SyncOperation conflicts with a running one, the lower
3266 // priority sync is pre-empted.
3267 if (asc.mSyncOperation.findPriority() >= op.findPriority()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003268 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003269 Slog.v(TAG, "Rescheduling sync due to conflict " + op.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003271 deferSyncH(op, SYNC_DELAY_ON_CONFLICT, "delay on conflict");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003272 return;
Matthew Williamsfa774182013-06-18 15:44:11 -07003273 } else {
Matthew Williamsfa774182013-06-18 15:44:11 -07003274 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003275 Slog.v(TAG, "Pushing back running sync due to a higher priority sync");
Fred Quintana918339a2010-10-05 14:00:39 -07003276 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003277 deferActiveSyncH(asc, "preempted");
Shreyas Basarge7680dd92016-02-11 14:52:47 +00003278 break;
Alon Albert8e285552012-09-17 15:05:27 -07003279 }
3280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003281 }
3282
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003283 final int syncOpState = computeSyncOpState(op);
3284 switch (syncOpState) {
3285 case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
3286 case SYNC_OP_STATE_INVALID: {
Makoto Onukia9dca242017-06-21 17:06:49 -07003287 mSyncJobService.callJobFinished(op.jobId, false,
3288 "invalid op state: " + syncOpState);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003289 } return;
3290 }
3291
3292 if (!dispatchSyncOperation(op)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003293 mSyncJobService.callJobFinished(op.jobId, false, "dispatchSyncOperation() failed");
Fred Quintana918339a2010-10-05 14:00:39 -07003294 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003295
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003296 setAuthorityPendingState(op.target);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003297 }
3298
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003299 private ActiveSyncContext findActiveSyncContextH(int jobId) {
3300 for (ActiveSyncContext asc: mActiveSyncContexts) {
3301 SyncOperation op = asc.mSyncOperation;
3302 if (op != null && op.jobId == jobId) {
3303 return asc;
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003304 }
3305 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003306 return null;
Matthew Williamsa4745542015-12-10 20:29:02 +00003307 }
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003308
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003309 private void updateRunningAccountsH(EndPoint syncTargets) {
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003310 AccountAndUser[] oldAccounts = mRunningAccounts;
振淦王60a74312015-12-01 16:37:31 +08003311 mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003312 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3313 Slog.v(TAG, "Accounts list: ");
3314 for (AccountAndUser acc : mRunningAccounts) {
3315 Slog.v(TAG, acc.toString());
3316 }
3317 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003318 if (mLogger.enabled()) {
3319 mLogger.log("updateRunningAccountsH: ", Arrays.toString(mRunningAccounts));
3320 }
振淦王60a74312015-12-01 16:37:31 +08003321 if (mBootCompleted) {
3322 doDatabaseCleanup();
3323 }
3324
3325 AccountAndUser[] accounts = mRunningAccounts;
3326 for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
3327 if (!containsAccountAndUser(accounts,
3328 currentSyncContext.mSyncOperation.target.account,
3329 currentSyncContext.mSyncOperation.target.userId)) {
3330 Log.d(TAG, "canceling sync since the account is no longer running");
3331 sendSyncFinishedOrCanceledMessage(currentSyncContext,
3332 null /* no result since this is a cancel */);
3333 }
3334 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003335
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003336 // On account add, check if there are any settings to be restored.
3337 for (AccountAndUser aau : mRunningAccounts) {
3338 if (!containsAccountAndUser(oldAccounts, aau.account, aau.userId)) {
3339 if (Log.isLoggable(TAG, Log.DEBUG)) {
3340 Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
3341 }
3342 AccountSyncSettingsBackupHelper.accountAdded(mContext);
3343 break;
3344 }
3345 }
3346
Rubin Xu2c548e02016-04-01 17:47:28 +01003347 // Cancel all jobs from non-existent accounts.
3348 AccountAndUser[] allAccounts = AccountManagerService.getSingleton().getAllAccounts();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003349 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003350 for (SyncOperation op: ops) {
Rubin Xu2c548e02016-04-01 17:47:28 +01003351 if (!containsAccountAndUser(allAccounts, op.target.account, op.target.userId)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003352 mLogger.log("canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003353 cancelJob(op, "updateRunningAccountsH()");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003354 }
3355 }
3356
3357 if (syncTargets != null) {
3358 scheduleSync(syncTargets.account, syncTargets.userId,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003359 SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
Makoto Onuki61283ec2018-01-31 17:22:36 -08003360 null, AuthorityInfo.NOT_INITIALIZED,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003361 ContentResolver.SYNC_EXEMPTION_NONE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003362 }
3363 }
3364
3365 /**
3366 * The given SyncOperation will be removed and a new one scheduled in its place if
3367 * an updated period or flex is specified.
3368 * @param syncOperation SyncOperation whose period and flex is to be updated.
3369 * @param pollFrequencyMillis new period in milliseconds.
3370 * @param flexMillis new flex time in milliseconds.
3371 */
3372 private void maybeUpdateSyncPeriodH(SyncOperation syncOperation, long pollFrequencyMillis,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003373 long flexMillis) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003374 if (!(pollFrequencyMillis == syncOperation.periodMillis
3375 && flexMillis == syncOperation.flexMillis)) {
3376 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3377 Slog.v(TAG, "updating period " + syncOperation + " to " + pollFrequencyMillis
3378 + " and flex to " + flexMillis);
3379 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003380 SyncOperation newOp = new SyncOperation(syncOperation, pollFrequencyMillis,
3381 flexMillis);
3382 newOp.jobId = syncOperation.jobId;
3383 scheduleSyncOperationH(newOp);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003384 }
3385 }
3386
3387 private void updateOrAddPeriodicSyncH(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003388 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003389 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3390 verifyJobScheduler(); // Will fill in mScheduledSyncs cache if it is not already filled.
3391 final long pollFrequencyMillis = pollFrequency * 1000L;
3392 final long flexMillis = flex * 1000L;
3393 if (isLoggable) {
3394 Slog.v(TAG, "Addition to periodic syncs requested: " + target
3395 + " period: " + pollFrequency
3396 + " flexMillis: " + flex
3397 + " extras: " + extras.toString());
3398 }
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003399 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003400 for (SyncOperation op: ops) {
3401 if (op.isPeriodic && op.target.matchesSpec(target)
3402 && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
3403 maybeUpdateSyncPeriodH(op, pollFrequencyMillis, flexMillis);
3404 return;
3405 }
3406 }
3407
3408 if (isLoggable) {
3409 Slog.v(TAG, "Adding new periodic sync: " + target
3410 + " period: " + pollFrequency
3411 + " flexMillis: " + flex
3412 + " extras: " + extras.toString());
3413 }
3414
3415 final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
3416 syncAdapterInfo = mSyncAdapters.getServiceInfo(
3417 SyncAdapterType.newKey(
3418 target.provider, target.account.type),
3419 target.userId);
3420 if (syncAdapterInfo == null) {
3421 return;
3422 }
3423
3424 SyncOperation op = new SyncOperation(target, syncAdapterInfo.uid,
3425 syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC,
3426 SyncStorageEngine.SOURCE_PERIODIC, extras,
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003427 syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003428 pollFrequencyMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003429
3430 final int syncOpState = computeSyncOpState(op);
3431 switch (syncOpState) {
3432 case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
Svet Ganov973edd192016-09-08 20:15:55 -07003433 String packageName = op.owningPackage;
3434 final int userId = UserHandle.getUserId(op.owningUid);
3435 // If the app did not run and has no account access, done
3436 if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
3437 return;
3438 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003439 mAccountManagerInternal.requestAccountAccess(op.target.account,
Svet Ganov973edd192016-09-08 20:15:55 -07003440 packageName, userId, new RemoteCallback((Bundle result) -> {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003441 if (result != null
3442 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
3443 updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
3444 }
3445 }
3446 ));
3447 } return;
3448
3449 case SYNC_OP_STATE_INVALID: {
3450 return;
3451 }
3452 }
3453
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003454 scheduleSyncOperationH(op);
3455 mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
3456 }
3457
3458 /**
3459 * Remove this periodic sync operation and all one-off operations initiated by it.
3460 */
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003461 private void removePeriodicSyncInternalH(SyncOperation syncOperation, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003462 // Remove this periodic sync and all one-off syncs initiated by it.
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003463 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003464 for (SyncOperation op: ops) {
3465 if (op.sourcePeriodicId == syncOperation.jobId || op.jobId == syncOperation.jobId) {
3466 ActiveSyncContext asc = findActiveSyncContextH(syncOperation.jobId);
3467 if (asc != null) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003468 mSyncJobService.callJobFinished(syncOperation.jobId, false,
3469 "removePeriodicSyncInternalH");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003470 runSyncFinishedOrCanceledH(null, asc);
3471 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003472 mLogger.log("removePeriodicSyncInternalH-canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003473 cancelJob(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003474 }
3475 }
3476 }
3477
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003478 private void removePeriodicSyncH(EndPoint target, Bundle extras, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003479 verifyJobScheduler();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003480 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003481 for (SyncOperation op: ops) {
3482 if (op.isPeriodic && op.target.matchesSpec(target)
3483 && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003484 removePeriodicSyncInternalH(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003485 }
3486 }
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003487 }
3488
Matthew Williams1967c8d2015-06-19 19:03:13 -07003489 private boolean isSyncNotUsingNetworkH(ActiveSyncContext activeSyncContext) {
3490 final long bytesTransferredCurrent =
3491 getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
3492 final long deltaBytesTransferred =
3493 bytesTransferredCurrent - activeSyncContext.mBytesTransferredAtLastPoll;
3494
3495 if (Log.isLoggable(TAG, Log.DEBUG)) {
3496 // Bytes transferred
3497 long remainder = deltaBytesTransferred;
3498 long mb = remainder / (1024 * 1024);
3499 remainder %= 1024 * 1024;
3500 long kb = remainder / 1024;
3501 remainder %= 1024;
3502 long b = remainder;
3503 Log.d(TAG, String.format(
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003504 "Time since last update: %ds. Delta transferred: %dMBs,%dKBs,%dBs",
3505 (SystemClock.elapsedRealtime()
3506 - activeSyncContext.mLastPolledTimeElapsed)/1000,
3507 mb, kb, b)
Matthew Williams1967c8d2015-06-19 19:03:13 -07003508 );
3509 }
3510 return (deltaBytesTransferred <= SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES);
3511 }
3512
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003513 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003514 * Determine if a sync is no longer valid and should be dropped.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003515 */
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003516 private int computeSyncOpState(SyncOperation op) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003517 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003518 int state;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003519 final EndPoint target = op.target;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003520
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003521 // Drop the sync if the account of this operation no longer exists.
3522 AccountAndUser[] accounts = mRunningAccounts;
3523 if (!containsAccountAndUser(accounts, target.account, target.userId)) {
3524 if (isLoggable) {
3525 Slog.v(TAG, " Dropping sync operation: account doesn't exist.");
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003526 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003527 return SYNC_OP_STATE_INVALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003528 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003529 // Drop this sync request if it isn't syncable.
Philip P. Moltmann486b2412018-01-03 11:29:01 -08003530 state = computeSyncable(target.account, target.userId, target.provider, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003531 if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003532 if (isLoggable) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003533 Slog.v(TAG, " Dropping sync operation: "
3534 + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003535 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003536 return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003537 }
Svet Ganovdfed1c72016-08-25 15:40:52 -07003538 if (state == AuthorityInfo.NOT_SYNCABLE) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003539 if (isLoggable) {
Svet Ganovdfed1c72016-08-25 15:40:52 -07003540 Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003541 }
3542 return SYNC_OP_STATE_INVALID;
3543 }
3544
3545 final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
3546 && mSyncStorageEngine.getSyncAutomatically(target.account,
3547 target.userId, target.provider);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003548
3549 // We ignore system settings that specify the sync is invalid if:
3550 // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
3551 // or
3552 // 2) it's an initialisation sync - we just need to connect to it.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003553 final boolean ignoreSystemConfiguration = op.isIgnoreSettings() || (state < 0);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003554
3555 // Sync not enabled.
3556 if (!syncEnabled && !ignoreSystemConfiguration) {
3557 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003558 Slog.v(TAG, " Dropping sync operation: disallowed by settings/network.");
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003559 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003560 return SYNC_OP_STATE_INVALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003561 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003562 return SYNC_OP_STATE_VALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003563 }
Fred Quintana918339a2010-10-05 14:00:39 -07003564
Fred Quintana87b14662011-09-12 10:32:55 -07003565 private boolean dispatchSyncOperation(SyncOperation op) {
Fred Quintana918339a2010-10-05 14:00:39 -07003566 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003567 Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
3568 Slog.v(TAG, "num active syncs: " + mActiveSyncContexts.size());
Fred Quintana918339a2010-10-05 14:00:39 -07003569 for (ActiveSyncContext syncContext : mActiveSyncContexts) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003570 Slog.v(TAG, syncContext.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003571 }
3572 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07003573 if (op.isAppStandbyExempted()) {
3574 final UsageStatsManagerInternal usmi = LocalServices.getService(
3575 UsageStatsManagerInternal.class);
3576 if (usmi != null) {
3577 usmi.reportExemptedSyncStart(op.owningPackage,
3578 UserHandle.getUserId(op.owningUid));
3579 }
3580 }
3581
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003582 // Connect to the sync adapter.
3583 int targetUid;
3584 ComponentName targetComponent;
3585 final SyncStorageEngine.EndPoint info = op.target;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003586 SyncAdapterType syncAdapterType =
3587 SyncAdapterType.newKey(info.provider, info.account.type);
3588 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
3589 syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId);
3590 if (syncAdapterInfo == null) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003591 mLogger.log("dispatchSyncOperation() failed: no sync adapter info for ",
3592 syncAdapterType);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003593 Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
3594 + ", removing settings for it");
3595 mSyncStorageEngine.removeAuthority(info);
3596 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003598 targetUid = syncAdapterInfo.uid;
3599 targetComponent = syncAdapterInfo.componentName;
Fred Quintana718d8a22009-04-29 17:53:20 -07003600 ActiveSyncContext activeSyncContext =
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003601 new ActiveSyncContext(op, insertStartSyncEvent(op), targetUid);
Fred Quintana718d8a22009-04-29 17:53:20 -07003602 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003603 Slog.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);
Fred Quintana718d8a22009-04-29 17:53:20 -07003604 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07003605
3606 activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);
3607 mActiveSyncContexts.add(activeSyncContext);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003608
3609 // Post message to begin monitoring this sync's progress.
3610 postMonitorSyncProgressMessage(activeSyncContext);
3611
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003612 if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003613 mLogger.log("dispatchSyncOperation() failed: bind failed. target: ",
3614 targetComponent);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003615 Slog.e(TAG, "Bind attempt failed - target: " + targetComponent);
Fred Quintana918339a2010-10-05 14:00:39 -07003616 closeActiveSyncContext(activeSyncContext);
Fred Quintana87b14662011-09-12 10:32:55 -07003617 return false;
Fred Quintana718d8a22009-04-29 17:53:20 -07003618 }
3619
Fred Quintana87b14662011-09-12 10:32:55 -07003620 return true;
Fred Quintana718d8a22009-04-29 17:53:20 -07003621 }
3622
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003623 private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003624 IBinder syncAdapter) {
Fred Quintana918339a2010-10-05 14:00:39 -07003625 final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
Fred Quintana718d8a22009-04-29 17:53:20 -07003626 try {
Alon Alberteca75112010-12-08 15:02:33 -08003627 activeSyncContext.mIsLinkedToDeath = true;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003628 syncAdapter.linkToDeath(activeSyncContext, 0);
Alon Alberteca75112010-12-08 15:02:33 -08003629
Makoto Onukia9dca242017-06-21 17:06:49 -07003630 mLogger.log("Sync start: account=" + syncOperation.target.account,
3631 " authority=", syncOperation.target.provider,
3632 " reason=", SyncOperation.reasonToString(null, syncOperation.reason),
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003633 " extras=", SyncOperation.extrasToString(syncOperation.extras),
3634 " adapter=", activeSyncContext.mSyncAdapter);
Makoto Onukia9dca242017-06-21 17:06:49 -07003635
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003636 activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter);
3637 activeSyncContext.mSyncAdapter
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003638 .startSync(activeSyncContext, syncOperation.target.provider,
3639 syncOperation.target.account, syncOperation.extras);
Makoto Onukia9dca242017-06-21 17:06:49 -07003640
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003641 mLogger.log("Sync is running now...");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003642 } catch (RemoteException remoteExc) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003643 mLogger.log("Sync failed with RemoteException: ", remoteExc.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003644 Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);
3645 closeActiveSyncContext(activeSyncContext);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003646 increaseBackoffSetting(syncOperation.target);
3647 scheduleSyncOperationH(syncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 } catch (RuntimeException exc) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003649 mLogger.log("Sync failed with RuntimeException: ", exc.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003650 closeActiveSyncContext(activeSyncContext);
Makoto Onuki5fc60022019-01-15 09:34:05 -08003651 Slog.e(TAG, "Caught RuntimeException while starting the sync "
3652 + logSafe(syncOperation), exc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003654 }
3655
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003656 /**
Matthew Williams8ef22042013-07-26 12:56:39 -07003657 * Cancel the sync for the provided target that matches the given bundle.
Matthew Williams1967c8d2015-06-19 19:03:13 -07003658 * @param info Can have null fields to indicate all the active syncs for that field.
3659 * @param extras Can be null to indicate <strong>all</strong> syncs for the given endpoint.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003660 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003661 private void cancelActiveSyncH(SyncStorageEngine.EndPoint info, Bundle extras,
3662 String why) {
Fred Quintana918339a2010-10-05 14:00:39 -07003663 ArrayList<ActiveSyncContext> activeSyncs =
3664 new ArrayList<ActiveSyncContext>(mActiveSyncContexts);
3665 for (ActiveSyncContext activeSyncContext : activeSyncs) {
3666 if (activeSyncContext != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003667 final SyncStorageEngine.EndPoint opInfo =
3668 activeSyncContext.mSyncOperation.target;
Matthew Williams8ef22042013-07-26 12:56:39 -07003669 if (!opInfo.matchesSpec(info)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003670 continue;
Fred Quintana918339a2010-10-05 14:00:39 -07003671 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003672 if (extras != null &&
3673 !syncExtrasEquals(activeSyncContext.mSyncOperation.extras,
3674 extras,
3675 false /* no config settings */)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003676 continue;
3677 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003678 mSyncJobService.callJobFinished(activeSyncContext.mSyncOperation.jobId, false,
3679 why);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003680 runSyncFinishedOrCanceledH(null /* cancel => no result */, activeSyncContext);
Fred Quintana918339a2010-10-05 14:00:39 -07003681 }
3682 }
3683 }
3684
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003685 /**
3686 * Should be called when a one-off instance of a periodic sync completes successfully.
3687 */
3688 private void reschedulePeriodicSyncH(SyncOperation syncOperation) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003689 // Ensure that the periodic sync wasn't removed.
3690 SyncOperation periodicSync = null;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003691 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003692 for (SyncOperation op: ops) {
3693 if (op.isPeriodic && syncOperation.matchesPeriodicOperation(op)) {
3694 periodicSync = op;
3695 break;
3696 }
3697 }
3698 if (periodicSync == null) {
3699 return;
3700 }
3701 scheduleSyncOperationH(periodicSync);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003702 }
3703
Matthew Williams8b76d202015-05-03 18:16:25 -07003704 private void runSyncFinishedOrCanceledH(SyncResult syncResult,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003705 ActiveSyncContext activeSyncContext) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003706 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Alon Alberteca75112010-12-08 15:02:33 -08003707
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003708 final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
3709 final SyncStorageEngine.EndPoint info = syncOperation.target;
3710
Alon Alberteca75112010-12-08 15:02:33 -08003711 if (activeSyncContext.mIsLinkedToDeath) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003712 activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
Alon Alberteca75112010-12-08 15:02:33 -08003713 activeSyncContext.mIsLinkedToDeath = false;
3714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715 final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003716 String historyMessage;
3717 int downstreamActivity;
3718 int upstreamActivity;
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003719
Makoto Onukia9dca242017-06-21 17:06:49 -07003720 mLogger.log("runSyncFinishedOrCanceledH() op=", syncOperation, " result=", syncResult);
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 if (syncResult != null) {
3723 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003724 Slog.v(TAG, "runSyncFinishedOrCanceled [finished]: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003725 + syncOperation + ", result " + syncResult);
3726 }
3727
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003728 // In the non-canceled case, close the active sync context before doing the rest
3729 // of the stuff.
3730 closeActiveSyncContext(activeSyncContext);
3731
3732 // Note this part is probably okay to do before closeActiveSyncContext()...
3733 // But moved here to restore OC-dev's behavior. See b/64597061.
3734 if (!syncOperation.isPeriodic) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003735 cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-finished");
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003736 }
3737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003738 if (!syncResult.hasError()) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07003739 historyMessage = SyncStorageEngine.MESG_SUCCESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003740 // TODO: set these correctly when the SyncResult is extended to include it
3741 downstreamActivity = 0;
3742 upstreamActivity = 0;
Makoto Onukia9dca242017-06-21 17:06:49 -07003743 clearBackoffSetting(syncOperation.target, "sync success");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003744
3745 // If the operation completes successfully and it was scheduled due to
3746 // a periodic operation failing, we reschedule the periodic operation to
3747 // start from now.
3748 if (syncOperation.isDerivedFromFailedPeriodicSync()) {
3749 reschedulePeriodicSyncH(syncOperation);
3750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 } else {
Makoto Onuki5fc60022019-01-15 09:34:05 -08003752 Log.w(TAG, "failed sync operation "
3753 + logSafe(syncOperation) + ", " + syncResult);
Makoto Onukiaad2b512018-02-07 09:31:46 -08003754
3755 syncOperation.retries++;
3756 if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07003757 syncOperation.syncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onukiaad2b512018-02-07 09:31:46 -08003758 }
3759
Fred Quintana307da1a2010-01-21 14:24:20 -08003760 // the operation failed so increase the backoff time
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003761 increaseBackoffSetting(syncOperation.target);
3762 if (!syncOperation.isPeriodic) {
3763 // reschedule the sync if so indicated by the syncResult
3764 maybeRescheduleSync(syncResult, syncOperation);
3765 } else {
3766 // create a normal sync instance that will respect adapter backoffs
Shreyas Basargeba1f7902016-10-01 00:19:44 +01003767 postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation(),
3768 0 /* min delay */);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003769 }
Alon Albert57286f92012-10-09 14:21:38 -07003770 historyMessage = ContentResolver.syncErrorToString(
3771 syncResultToErrorNumber(syncResult));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003772 // TODO: set these correctly when the SyncResult is extended to include it
3773 downstreamActivity = 0;
3774 upstreamActivity = 0;
3775 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003776 setDelayUntilTime(syncOperation.target, syncResult.delayUntil);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003777 } else {
3778 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003779 Slog.v(TAG, "runSyncFinishedOrCanceled [canceled]: " + syncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 }
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003781
3782 if (!syncOperation.isPeriodic) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003783 cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-canceled");
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003784 }
3785
Fred Quintana718d8a22009-04-29 17:53:20 -07003786 if (activeSyncContext.mSyncAdapter != null) {
3787 try {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003788 mLogger.log("Calling cancelSync for runSyncFinishedOrCanceled ",
3789 activeSyncContext, " adapter=", activeSyncContext.mSyncAdapter);
Fred Quintana21bb0de2009-06-16 10:24:58 -07003790 activeSyncContext.mSyncAdapter.cancelSync(activeSyncContext);
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003791 mLogger.log("Canceled");
Fred Quintana718d8a22009-04-29 17:53:20 -07003792 } catch (RemoteException e) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003793 mLogger.log("RemoteException ", Log.getStackTraceString(e));
Fred Quintana718d8a22009-04-29 17:53:20 -07003794 // we don't need to retry this in this case
3795 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07003797 historyMessage = SyncStorageEngine.MESG_CANCELED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 downstreamActivity = 0;
3799 upstreamActivity = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003800
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003801 // In the cancel sync case, close it after calling cancelSync().
3802 closeActiveSyncContext(activeSyncContext);
3803 }
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003805 stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
3806 upstreamActivity, downstreamActivity, elapsedTime);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003807 // Check for full-resync and schedule it after closing off the last sync.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003808 if (syncResult != null && syncResult.tooManyDeletions) {
3809 installHandleTooManyDeletesNotification(info.account,
3810 info.provider, syncResult.stats.numDeletes,
3811 info.userId);
3812 } else {
Chris Wren282cfef2017-03-27 15:01:44 -04003813 mNotificationMgr.cancelAsUser(
3814 Integer.toString(info.account.hashCode() ^ info.provider.hashCode()),
3815 SystemMessage.NOTE_SYNC_ERROR,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003816 new UserHandle(info.userId));
3817 }
3818 if (syncResult != null && syncResult.fullSyncRequested) {
3819 scheduleSyncOperationH(
3820 new SyncOperation(info.account, info.userId,
3821 syncOperation.owningUid, syncOperation.owningPackage,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003822 syncOperation.reason,
3823 syncOperation.syncSource, info.provider, new Bundle(),
Makoto Onuki61283ec2018-01-31 17:22:36 -08003824 syncOperation.allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003825 syncOperation.syncExemptionFlag));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003826 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 }
3828
Fred Quintana918339a2010-10-05 14:00:39 -07003829 private void closeActiveSyncContext(ActiveSyncContext activeSyncContext) {
3830 activeSyncContext.close();
3831 mActiveSyncContexts.remove(activeSyncContext);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003832 mSyncStorageEngine.removeActiveSync(activeSyncContext.mSyncInfo,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003833 activeSyncContext.mSyncOperation.target.userId);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003834
3835 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003836 Slog.v(TAG, "removing all MESSAGE_MONITOR_SYNC & MESSAGE_SYNC_EXPIRED for "
Matthew Williams1967c8d2015-06-19 19:03:13 -07003837 + activeSyncContext.toString());
3838 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07003839 mSyncHandler.removeMessages(SyncHandler.MESSAGE_MONITOR_SYNC, activeSyncContext);
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003840
3841 mLogger.log("closeActiveSyncContext: ", activeSyncContext);
Fred Quintana918339a2010-10-05 14:00:39 -07003842 }
3843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003844 /**
3845 * Convert the error-containing SyncResult into the Sync.History error number. Since
3846 * the SyncResult may indicate multiple errors at once, this method just returns the
3847 * most "serious" error.
3848 * @param syncResult the SyncResult from which to read
3849 * @return the most "serious" error set in the SyncResult
3850 * @throws IllegalStateException if the SyncResult does not indicate any errors.
3851 * If SyncResult.error() is true then it is safe to call this.
3852 */
3853 private int syncResultToErrorNumber(SyncResult syncResult) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07003854 if (syncResult.syncAlreadyInProgress)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003855 return ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003856 if (syncResult.stats.numAuthExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003857 return ContentResolver.SYNC_ERROR_AUTHENTICATION;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003858 if (syncResult.stats.numIoExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003859 return ContentResolver.SYNC_ERROR_IO;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003860 if (syncResult.stats.numParseExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003861 return ContentResolver.SYNC_ERROR_PARSE;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003862 if (syncResult.stats.numConflictDetectedExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003863 return ContentResolver.SYNC_ERROR_CONFLICT;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003864 if (syncResult.tooManyDeletions)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003865 return ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003866 if (syncResult.tooManyRetries)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003867 return ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003868 if (syncResult.databaseError)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003869 return ContentResolver.SYNC_ERROR_INTERNAL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003870 throw new IllegalStateException("we are not in an error state, " + syncResult);
3871 }
3872
Fred Quintanad9d2f112009-04-23 13:36:27 -07003873 private void installHandleTooManyDeletesNotification(Account account, String authority,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003874 long numDeletes, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003875 if (mNotificationMgr == null) return;
Fred Quintanac848b702009-08-25 20:18:46 -07003876
3877 final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
3878 authority, 0 /* flags */);
3879 if (providerInfo == null) {
3880 return;
3881 }
3882 CharSequence authorityName = providerInfo.loadLabel(mContext.getPackageManager());
3883
Fred Quintanab19e62a2010-12-16 13:54:43 -08003884 Intent clickIntent = new Intent(mContext, SyncActivityTooManyDeletes.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885 clickIntent.putExtra("account", account);
Tadashi G. Takaoka86135d32009-09-24 19:31:44 -07003886 clickIntent.putExtra("authority", authority);
Fred Quintanac848b702009-08-25 20:18:46 -07003887 clickIntent.putExtra("provider", authorityName.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003888 clickIntent.putExtra("numDeletes", numDeletes);
3889
3890 if (!isActivityAvailable(clickIntent)) {
3891 Log.w(TAG, "No activity found to handle too many deletes.");
3892 return;
3893 }
3894
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003895 UserHandle user = new UserHandle(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003896 final PendingIntent pendingIntent = PendingIntent
Dianne Hackborn41203752012-08-31 14:05:51 -07003897 .getActivityAsUser(mContext, 0, clickIntent,
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003898 PendingIntent.FLAG_CANCEL_CURRENT, null, user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899
3900 CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
3901 R.string.contentServiceTooManyDeletesNotificationDesc);
3902
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003903 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003904 Notification notification =
3905 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04003906 .setSmallIcon(R.drawable.stat_notify_sync_error)
3907 .setTicker(mContext.getString(R.string.contentServiceSync))
3908 .setWhen(System.currentTimeMillis())
3909 .setColor(contextForUser.getColor(
3910 com.android.internal.R.color.system_notification_accent_color))
3911 .setContentTitle(contextForUser.getString(
3912 R.string.contentServiceSyncNotificationTitle))
3913 .setContentText(
3914 String.format(tooManyDeletesDescFormat.toString(), authorityName))
3915 .setContentIntent(pendingIntent)
3916 .build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003917 notification.flags |= Notification.FLAG_ONGOING_EVENT;
Chris Wren282cfef2017-03-27 15:01:44 -04003918 mNotificationMgr.notifyAsUser(
3919 Integer.toString(account.hashCode() ^ authority.hashCode()),
3920 SystemMessage.NOTE_SYNC_ERROR,
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003921 notification, user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003922 }
3923
3924 /**
3925 * Checks whether an activity exists on the system image for the given intent.
3926 *
3927 * @param intent The intent for an activity.
3928 * @return Whether or not an activity exists.
3929 */
3930 private boolean isActivityAvailable(Intent intent) {
3931 PackageManager pm = mContext.getPackageManager();
3932 List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
3933 int listSize = list.size();
3934 for (int i = 0; i < listSize; i++) {
3935 ResolveInfo resolveInfo = list.get(i);
3936 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
3937 != 0) {
3938 return true;
3939 }
3940 }
3941
3942 return false;
3943 }
3944
3945 public long insertStartSyncEvent(SyncOperation syncOperation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003946 final long now = System.currentTimeMillis();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003947 EventLog.writeEvent(2720,
3948 syncOperation.toEventLog(SyncStorageEngine.EVENT_START));
3949 return mSyncStorageEngine.insertStartSyncEvent(syncOperation, now);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003950 }
3951
3952 public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003953 int upstreamActivity, int downstreamActivity, long elapsedTime) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003954 EventLog.writeEvent(2720,
3955 syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
Fred Quintana77c560f2010-03-29 22:20:26 -07003956 mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08003957 resultMessage, downstreamActivity, upstreamActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003958 }
3959 }
Fred Quintana918339a2010-10-05 14:00:39 -07003960
Matthew Williams8b76d202015-05-03 18:16:25 -07003961 private boolean isSyncStillActiveH(ActiveSyncContext activeSyncContext) {
Fred Quintana918339a2010-10-05 14:00:39 -07003962 for (ActiveSyncContext sync : mActiveSyncContexts) {
3963 if (sync == activeSyncContext) {
3964 return true;
3965 }
3966 }
3967 return false;
3968 }
Alon Albert57286f92012-10-09 14:21:38 -07003969
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003970 /**
3971 * Sync extra comparison function.
3972 * @param b1 bundle to compare
3973 * @param b2 other bundle to compare
3974 * @param includeSyncSettings if false, ignore system settings in bundle.
3975 */
3976 public static boolean syncExtrasEquals(Bundle b1, Bundle b2, boolean includeSyncSettings) {
3977 if (b1 == b2) {
3978 return true;
3979 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003980 // Exit early if we can.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003981 if (includeSyncSettings && b1.size() != b2.size()) {
3982 return false;
3983 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003984 Bundle bigger = b1.size() > b2.size() ? b1 : b2;
3985 Bundle smaller = b1.size() > b2.size() ? b2 : b1;
3986 for (String key : bigger.keySet()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003987 if (!includeSyncSettings && isSyncSetting(key)) {
3988 continue;
3989 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003990 if (!smaller.containsKey(key)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003991 return false;
3992 }
Matthew Williams9ad2c842015-10-16 12:01:31 -07003993 if (!Objects.equals(bigger.get(key), smaller.get(key))) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003994 return false;
3995 }
3996 }
3997 return true;
3998 }
3999
4000 /**
4001 * @return true if the provided key is used by the SyncManager in scheduling the sync.
4002 */
4003 private static boolean isSyncSetting(String key) {
4004 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
4005 return true;
4006 }
4007 if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
4008 return true;
4009 }
4010 if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF)) {
4011 return true;
4012 }
4013 if (key.equals(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY)) {
4014 return true;
4015 }
4016 if (key.equals(ContentResolver.SYNC_EXTRAS_MANUAL)) {
4017 return true;
4018 }
4019 if (key.equals(ContentResolver.SYNC_EXTRAS_UPLOAD)) {
4020 return true;
4021 }
4022 if (key.equals(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS)) {
4023 return true;
4024 }
4025 if (key.equals(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS)) {
4026 return true;
4027 }
4028 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD)) {
4029 return true;
4030 }
4031 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD)) {
4032 return true;
4033 }
4034 if (key.equals(ContentResolver.SYNC_EXTRAS_PRIORITY)) {
4035 return true;
4036 }
4037 if (key.equals(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED)) {
4038 return true;
4039 }
4040 if (key.equals(ContentResolver.SYNC_EXTRAS_INITIALIZE)) {
4041 return true;
4042 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08004043// if (key.equals(ContentResolver.SYNC_EXTRAS_APP_STANDBY_EXEMPTED)) {
4044// return true;
4045// }
4046 // No need to check virtual flags such as SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07004047 return false;
4048 }
4049
Alon Albert57286f92012-10-09 14:21:38 -07004050 static class PrintTable {
Makoto Onuki15e7a252017-06-08 17:12:05 -07004051 private ArrayList<String[]> mTable = Lists.newArrayList();
Alon Albert57286f92012-10-09 14:21:38 -07004052 private final int mCols;
4053
4054 PrintTable(int cols) {
4055 mCols = cols;
4056 }
4057
4058 void set(int row, int col, Object... values) {
4059 if (col + values.length > mCols) {
4060 throw new IndexOutOfBoundsException("Table only has " + mCols +
4061 " columns. can't set " + values.length + " at column " + col);
4062 }
4063 for (int i = mTable.size(); i <= row; i++) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07004064 final String[] list = new String[mCols];
Alon Albert57286f92012-10-09 14:21:38 -07004065 mTable.add(list);
4066 for (int j = 0; j < mCols; j++) {
4067 list[j] = "";
4068 }
4069 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07004070 final String[] rowArray = mTable.get(row);
4071 for (int i = 0; i < values.length; i++) {
4072 final Object value = values[i];
4073 rowArray[col + i] = (value == null) ? "" : value.toString();
4074 }
Alon Albert57286f92012-10-09 14:21:38 -07004075 }
4076
4077 void writeTo(PrintWriter out) {
4078 final String[] formats = new String[mCols];
4079 int totalLength = 0;
4080 for (int col = 0; col < mCols; ++col) {
4081 int maxLength = 0;
4082 for (Object[] row : mTable) {
4083 final int length = row[col].toString().length();
4084 if (length > maxLength) {
4085 maxLength = length;
4086 }
4087 }
4088 totalLength += maxLength;
4089 formats[col] = String.format("%%-%ds", maxLength);
4090 }
Patrick Tjin31068162014-01-30 13:28:46 -08004091 formats[mCols - 1] = "%s";
Alon Albert57286f92012-10-09 14:21:38 -07004092 printRow(out, formats, mTable.get(0));
4093 totalLength += (mCols - 1) * 2;
4094 for (int i = 0; i < totalLength; ++i) {
4095 out.print("-");
4096 }
4097 out.println();
4098 for (int i = 1, mTableSize = mTable.size(); i < mTableSize; i++) {
4099 Object[] row = mTable.get(i);
4100 printRow(out, formats, row);
4101 }
4102 }
4103
4104 private void printRow(PrintWriter out, String[] formats, Object[] row) {
4105 for (int j = 0, rowLength = row.length; j < rowLength; j++) {
4106 out.printf(String.format(formats[j], row[j].toString()));
4107 out.print(" ");
4108 }
4109 out.println();
4110 }
4111
4112 public int getNumRows() {
4113 return mTable.size();
4114 }
4115 }
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004116
4117 private Context getContextForUser(UserHandle user) {
4118 try {
4119 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
4120 } catch (NameNotFoundException e) {
4121 // Default to mContext, not finding the package system is running as is unlikely.
4122 return mContext;
4123 }
4124 }
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004125
4126 private void cancelJob(SyncOperation op, String why) {
4127 if (op == null) {
4128 Slog.wtf(TAG, "Null sync operation detected.");
4129 return;
4130 }
4131 if (op.isPeriodic) {
4132 mLogger.log("Removing periodic sync ", op, " for ", why);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004133 }
4134 getJobScheduler().cancel(op.jobId);
4135 }
4136
Makoto Onuki94986212018-04-11 16:24:46 -07004137 public void resetTodayStats() {
4138 mSyncStorageEngine.resetTodayStats(/*force=*/ true);
4139 }
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004140}