blob: 0a640b8a76c64b67d9462dfa346387abd57d1926 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.content;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Alon Alberte0bde332011-09-22 14:26:16 -070019import android.accounts.Account;
Amith Yamasanif29f2362012-04-05 18:29:52 -070020import android.accounts.AccountAndUser;
Alon Alberte0bde332011-09-22 14:26:16 -070021import android.accounts.AccountManager;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070022import android.accounts.AccountManagerInternal;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080023import android.annotation.NonNull;
24import android.annotation.UserIdInt;
Fred Quintana33e44692011-12-05 15:04:16 -080025import android.app.ActivityManager;
Amith Yamasani9422bdc2013-04-10 16:58:19 -070026import android.app.AppGlobals;
Alon Alberte0bde332011-09-22 14:26:16 -070027import android.app.Notification;
28import android.app.NotificationManager;
29import android.app.PendingIntent;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000030import android.app.job.JobInfo;
31import android.app.job.JobScheduler;
Makoto Onuki75ad2492018-03-28 14:42:42 -070032import android.app.usage.UsageStatsManagerInternal;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080033import android.content.BroadcastReceiver;
34import android.content.ComponentName;
35import android.content.ContentResolver;
Makoto Onuki75ad2492018-03-28 14:42:42 -070036import android.content.ContentResolver.SyncExemption;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080037import android.content.Context;
38import android.content.ISyncAdapter;
Philip P. Moltmann486b2412018-01-03 11:29:01 -080039import android.content.ISyncAdapterUnsyncableAccountCallback;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080040import android.content.ISyncContext;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080041import android.content.Intent;
42import android.content.IntentFilter;
Matthew Williamsfa774182013-06-18 15:44:11 -070043import android.content.PeriodicSync;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080044import android.content.ServiceConnection;
45import android.content.SyncActivityTooManyDeletes;
46import android.content.SyncAdapterType;
47import android.content.SyncAdaptersCache;
48import android.content.SyncInfo;
49import android.content.SyncResult;
50import android.content.SyncStatusInfo;
Makoto Onuki94986212018-04-11 16:24:46 -070051import android.content.SyncStatusInfo.Stats;
Alon Alberte0bde332011-09-22 14:26:16 -070052import android.content.pm.ApplicationInfo;
Amith Yamasani9422bdc2013-04-10 16:58:19 -070053import android.content.pm.PackageInfo;
Alon Alberte0bde332011-09-22 14:26:16 -070054import android.content.pm.PackageManager;
Todd Kennedy0eb97382017-10-03 16:57:22 -070055import android.content.pm.PackageManager.NameNotFoundException;
Makoto Onukid4764302018-03-30 17:32:57 -070056import android.content.pm.PackageManagerInternal;
Alon Alberte0bde332011-09-22 14:26:16 -070057import android.content.pm.ProviderInfo;
58import android.content.pm.RegisteredServicesCache;
59import android.content.pm.RegisteredServicesCacheListener;
60import android.content.pm.ResolveInfo;
Amith Yamasani04e0d262012-02-14 11:50:53 -080061import android.content.pm.UserInfo;
Matthew Williams8b76d202015-05-03 18:16:25 -070062import android.database.ContentObserver;
Alon Alberte0bde332011-09-22 14:26:16 -070063import android.net.ConnectivityManager;
64import android.net.NetworkInfo;
Matthew Williams1967c8d2015-06-19 19:03:13 -070065import android.net.TrafficStats;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080066import android.os.BatteryStats;
Makoto Onukibbf6d8c2017-08-11 12:11:39 -070067import android.os.Binder;
Makoto Onukidd4b14f2017-08-17 14:03:48 -070068import android.os.Build;
Fred Quintana918339a2010-10-05 14:00:39 -070069import android.os.Bundle;
70import android.os.Handler;
Makoto Onukie08a5c22018-04-27 13:28:46 -070071import android.os.HandlerThread;
Fred Quintana918339a2010-10-05 14:00:39 -070072import android.os.IBinder;
73import android.os.Looper;
74import android.os.Message;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000075import android.os.Messenger;
Fred Quintana918339a2010-10-05 14:00:39 -070076import android.os.PowerManager;
Makoto Onuki75ad2492018-03-28 14:42:42 -070077import android.os.Process;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -070078import android.os.RemoteCallback;
Fred Quintana918339a2010-10-05 14:00:39 -070079import android.os.RemoteException;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080080import android.os.ServiceManager;
Fred Quintana918339a2010-10-05 14:00:39 -070081import android.os.SystemClock;
82import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070083import android.os.UserHandle;
Amith Yamasani258848d2012-08-10 17:06:33 -070084import android.os.UserManager;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070085import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.text.format.Time;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.util.EventLog;
89import android.util.Log;
Fred Quintana307da1a2010-01-21 14:24:20 -080090import android.util.Pair;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000091import android.util.Slog;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +000092
Alon Albert8e285552012-09-17 15:05:27 -070093import com.android.internal.R;
Makoto Onuki056a9752018-05-08 15:21:56 -070094import com.android.internal.annotations.GuardedBy;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -080095import com.android.internal.app.IBatteryStats;
Makoto Onukid4764302018-03-30 17:32:57 -070096import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
97import com.android.internal.notification.SystemNotificationChannels;
Dianne Hackborn8d044e82013-04-30 17:24:15 -070098import com.android.internal.os.BackgroundThread;
Makoto Onukid4764302018-03-30 17:32:57 -070099import com.android.internal.util.ArrayUtils;
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700100import com.android.internal.util.IndentingPrintWriter;
Makoto Onuki94986212018-04-11 16:24:46 -0700101import com.android.internal.util.function.QuadConsumer;
Makoto Onukid4764302018-03-30 17:32:57 -0700102import com.android.server.DeviceIdleController;
103import com.android.server.LocalServices;
104import com.android.server.SystemService;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800105import com.android.server.accounts.AccountManagerService;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000106import com.android.server.backup.AccountSyncSettingsBackupHelper;
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700107import com.android.server.content.SyncStorageEngine.AuthorityInfo;
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700108import com.android.server.content.SyncStorageEngine.EndPoint;
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800109import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
Makoto Onukid4764302018-03-30 17:32:57 -0700110import com.android.server.job.JobSchedulerInternal;
111
112import com.google.android.collect.Lists;
113import com.google.android.collect.Maps;
Alon Albert8e285552012-09-17 15:05:27 -0700114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116import java.io.PrintWriter;
117import java.util.ArrayList;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000118import java.util.Arrays;
Fred Quintana918339a2010-10-05 14:00:39 -0700119import java.util.Collection;
120import java.util.Collections;
Alon Alberte0bde332011-09-22 14:26:16 -0700121import java.util.Comparator;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000122import java.util.HashMap;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000123import java.util.HashSet;
124import java.util.List;
125import java.util.Map;
Matthew Williams9ad2c842015-10-16 12:01:31 -0700126import java.util.Objects;
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000127import java.util.Random;
128import java.util.Set;
Makoto Onuki94986212018-04-11 16:24:46 -0700129import java.util.function.Function;
Makoto Onuki15e7a252017-06-08 17:12:05 -0700130import java.util.function.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131
132/**
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000133 * Implementation details:
134 * All scheduled syncs will be passed on to JobScheduler as jobs
135 * (See {@link #scheduleSyncOperationH(SyncOperation, long)}. This function schedules a job
136 * with JobScheduler with appropriate delay and constraints (according to backoffs and extras).
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000137 * The scheduleSyncOperationH function also assigns a unique jobId to each
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000138 * SyncOperation.
139 *
140 * Periodic Syncs:
141 * Each periodic sync is scheduled as a periodic job. If a periodic sync fails, we create a new
142 * one off SyncOperation and set its {@link SyncOperation#sourcePeriodicId} field to the jobId of the
143 * periodic sync. We don't allow the periodic job to run while any job initiated by it is pending.
144 *
145 * Backoffs:
146 * Each {@link EndPoint} has a backoff associated with it. When a SyncOperation fails, we increase
147 * the backoff on the authority. Then we reschedule all syncs associated with that authority to
148 * run at a later time. Similarly, when a sync succeeds, backoff is cleared and all associated syncs
149 * are rescheduled. A rescheduled sync will get a new jobId.
150 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 * @hide
152 */
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700153public class SyncManager {
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700154 static final String TAG = "SyncManager";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700156 private static final boolean DEBUG_ACCOUNT_ACCESS = false;
157
Makoto Onukib47e8942017-09-18 14:03:03 -0700158 // Only do the check on a debuggable build.
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700159 private static final boolean ENABLE_SUSPICIOUS_CHECK = Build.IS_DEBUGGABLE;
160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 /** Delay a sync due to local changes this long. In milliseconds */
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700162 private static final long LOCAL_SYNC_DELAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700164 static {
Fred Quintana918339a2010-10-05 14:00:39 -0700165 LOCAL_SYNC_DELAY =
166 SystemProperties.getLong("sync.local_sync_delay", 30 * 1000 /* 30 seconds */);
Debajit Ghosh44ee0f02009-09-14 14:58:31 -0700167 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 /**
Fred Quintana8570f742010-02-18 10:32:54 -0800170 * How long to wait before retrying a sync that failed due to one already being in progress.
171 */
172 private static final int DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS = 10;
173
Matthew Williams92a1c092014-08-25 19:18:32 -0700174 /**
Matthew Williams1967c8d2015-06-19 19:03:13 -0700175 * How often to periodically poll network traffic for an adapter performing a sync to determine
176 * whether progress is being made.
177 */
178 private static final long SYNC_MONITOR_WINDOW_LENGTH_MILLIS = 60 * 1000; // 60 seconds
179
180 /**
181 * How many bytes must be transferred (Tx + Rx) over the period of time defined by
182 * {@link #SYNC_MONITOR_WINDOW_LENGTH_MILLIS} for the sync to be considered to be making
183 * progress.
184 */
185 private static final int SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES = 10; // 10 bytes
186
187 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000188 * If a previously scheduled sync becomes ready and we are low on storage, it gets
189 * pushed back for this amount of time.
190 */
191 private static final long SYNC_DELAY_ON_LOW_STORAGE = 60*60*1000; // 1 hour
192
193 /**
194 * If a sync becomes ready and it conflicts with an already running sync, it gets
195 * pushed back for this amount of time.
196 */
197 private static final long SYNC_DELAY_ON_CONFLICT = 10*1000; // 10 seconds
Fred Quintana3ec47302010-03-10 10:08:31 -0800198
Shreyas Basargefa272532016-03-09 16:52:48 +0000199 /**
200 * Generate job ids in the range [MIN_SYNC_JOB_ID, MAX_SYNC_JOB_ID) to avoid conflicts with
201 * other jobs scheduled by the system process.
202 */
203 private static final int MIN_SYNC_JOB_ID = 100000;
204 private static final int MAX_SYNC_JOB_ID = 110000;
205
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800206 private static final String SYNC_WAKE_LOCK_PREFIX = "*sync*/";
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700207 private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm";
Fred Quintana918339a2010-10-05 14:00:39 -0700208 private static final String SYNC_LOOP_WAKE_LOCK = "SyncLoopWakeLock";
209
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700210
211 private static final int SYNC_OP_STATE_VALID = 0;
212 private static final int SYNC_OP_STATE_INVALID = 1;
213 private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
214
Philip P. Moltmann486b2412018-01-03 11:29:01 -0800215 /** Flags used when connecting to a sync adapter service */
216 private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
217 | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
218
Makoto Onuki056a9752018-05-08 15:21:56 -0700219 /** Singleton instance. */
220 @GuardedBy("SyncManager.class")
221 private static SyncManager sInstance;
222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 private Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224
Amith Yamasani04e0d262012-02-14 11:50:53 -0800225 private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
226
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700227 // TODO: add better locking around mRunningAccounts
228 private volatile AccountAndUser[] mRunningAccounts = INITIAL_ACCOUNTS_ARRAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 volatile private PowerManager.WakeLock mHandleAlarmWakeLock;
Fred Quintana918339a2010-10-05 14:00:39 -0700231 volatile private PowerManager.WakeLock mSyncManagerWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 volatile private boolean mDataConnectionIsConnected = false;
233 volatile private boolean mStorageIsLow = false;
Dianne Hackborn4870e9d2015-04-08 16:55:47 -0700234 volatile private boolean mDeviceIsIdle = false;
Dianne Hackborn627dfa12015-11-11 18:10:30 -0800235 volatile private boolean mReportedSyncActive = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
237 private final NotificationManager mNotificationMgr;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800238 private final IBatteryStats mBatteryStats;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000239 private JobScheduler mJobScheduler;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000240 private JobSchedulerInternal mJobSchedulerInternal;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000241 private SyncJobService mSyncJobService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700243 private SyncStorageEngine mSyncStorageEngine;
Jeff Sharkeya706e2f2012-10-16 12:02:42 -0700244
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700245 protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246
Fred Quintanaf892fb32009-08-27 21:32:08 -0700247 // Synchronized on "this". Instead of using this directly one should instead call
248 // its accessor, getConnManager().
249 private ConnectivityManager mConnManagerDoNotUseDirectly;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250
Matthew Williams8b76d202015-05-03 18:16:25 -0700251 /** Track whether the device has already been provisioned. */
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000252 private volatile boolean mProvisioned;
Matthew Williams8b76d202015-05-03 18:16:25 -0700253
Makoto Onuki94986212018-04-11 16:24:46 -0700254 protected final SyncAdaptersCache mSyncAdapters;
Fred Quintana718d8a22009-04-29 17:53:20 -0700255
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000256 private final Random mRand;
257
Makoto Onukia9dca242017-06-21 17:06:49 -0700258 private final SyncLogger mLogger;
259
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000260 private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
261 for (JobInfo job: pendingJobs) {
262 if (job.getId() == jobId) {
263 return true;
264 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000265 }
266 for (ActiveSyncContext asc: mActiveSyncContexts) {
267 if (asc.mSyncOperation.jobId == jobId) {
268 return true;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000269 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000270 }
271 return false;
272 }
273
274 private int getUnusedJobIdH() {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000275 int newJobId;
276 do {
277 newJobId = MIN_SYNC_JOB_ID + mRand.nextInt(MAX_SYNC_JOB_ID - MIN_SYNC_JOB_ID);
278 } while (isJobIdInUseLockedH(newJobId,
279 mJobSchedulerInternal.getSystemScheduledPendingJobs()));
280 return newJobId;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000281 }
282
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000283 private List<SyncOperation> getAllPendingSyncs() {
284 verifyJobScheduler();
285 List<JobInfo> pendingJobs = mJobSchedulerInternal.getSystemScheduledPendingJobs();
286 List<SyncOperation> pendingSyncs = new ArrayList<SyncOperation>(pendingJobs.size());
287 for (JobInfo job: pendingJobs) {
288 SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
289 if (op != null) {
290 pendingSyncs.add(op);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000291 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000292 }
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000293 return pendingSyncs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000294 }
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700295
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700296 private final BroadcastReceiver mStorageIntentReceiver =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700298 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 public void onReceive(Context context, Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 String action = intent.getAction();
301 if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
302 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000303 Slog.v(TAG, "Internal storage is low.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 }
305 mStorageIsLow = true;
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700306 cancelActiveSync(
307 SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
Makoto Onukia9dca242017-06-21 17:06:49 -0700308 null /* any sync */,
309 "storage low");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
311 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000312 Slog.v(TAG, "Internal storage is ok.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 }
314 mStorageIsLow = false;
Makoto Onukia9dca242017-06-21 17:06:49 -0700315 rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
316 "storage ok");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 }
318 }
319 };
320
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700321 private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700322 @Override
Fred Quintana60307342009-03-24 22:48:12 -0700323 public void onReceive(Context context, Intent intent) {
Matthew Williams8b76d202015-05-03 18:16:25 -0700324 mBootCompleted = true;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000325 // Called because it gets all pending jobs and stores them in mScheduledSyncs cache.
326 verifyJobScheduler();
Fred Quintanae91ebe22009-09-29 20:44:30 -0700327 mSyncHandler.onBootCompleted();
Fred Quintana60307342009-03-24 22:48:12 -0700328 }
329 };
330
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700331 private final BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700332 @Override
Amith Yamasanid648a602012-09-26 15:06:10 -0700333 public void onReceive(Context context, Intent intent) {
Makoto Onukifb636cc2017-12-07 15:46:26 -0800334 EndPoint target = new EndPoint(null, null, getSendingUserId());
Shreyas Basargedcb88c82016-02-03 00:09:18 +0000335 updateRunningAccounts(target /* sync targets for user */);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700336 }
337 };
338
Fred Quintanab3029c32010-04-06 13:27:12 -0700339 private final PowerManager mPowerManager;
Ashish Sharma69d95de2012-04-11 17:27:24 -0700340
Amith Yamasani9535c912012-10-10 21:48:33 -0700341 private final UserManager mUserManager;
Amith Yamasani258848d2012-08-10 17:06:33 -0700342
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700343 private final AccountManager mAccountManager;
344
345 private final AccountManagerInternal mAccountManagerInternal;
346
Svet Ganov973edd192016-09-08 20:15:55 -0700347 private final PackageManagerInternal mPackageManagerInternal;
348
Amith Yamasani258848d2012-08-10 17:06:33 -0700349 private List<UserInfo> getAllUsers() {
Amith Yamasani9535c912012-10-10 21:48:33 -0700350 return mUserManager.getUsers();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800351 }
352
353 private boolean containsAccountAndUser(AccountAndUser[] accounts, Account account, int userId) {
354 boolean found = false;
355 for (int i = 0; i < accounts.length; i++) {
356 if (accounts[i].userId == userId
357 && accounts[i].account.equals(account)) {
358 found = true;
359 break;
360 }
361 }
362 return found;
363 }
364
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000365 /** target indicates endpoints that should be synced after account info is updated. */
366 private void updateRunningAccounts(EndPoint target) {
367 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_ACCOUNTS_UPDATED");
振淦王60a74312015-12-01 16:37:31 +0800368 // Update accounts in handler thread.
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000369 Message m = mSyncHandler.obtainMessage(SyncHandler.MESSAGE_ACCOUNTS_UPDATED);
370 m.obj = target;
371 m.sendToTarget();
Fred Quintanad9d2f112009-04-23 13:36:27 -0700372 }
373
Jeff Sharkey8f55d112012-10-11 11:00:21 -0700374 private void doDatabaseCleanup() {
Amith Yamasanidb6a14c2012-10-17 21:16:52 -0700375 for (UserInfo user : mUserManager.getUsers(true)) {
376 // Skip any partially created/removed users
377 if (user.partial) continue;
Svetoslavf3f02ac2015-09-08 14:36:35 -0700378 Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(
379 user.id, mContext.getOpPackageName());
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000380
Jeff Sharkey8f55d112012-10-11 11:00:21 -0700381 mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
382 }
383 }
384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 private BroadcastReceiver mConnectivityIntentReceiver =
386 new BroadcastReceiver() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000387 @Override
388 public void onReceive(Context context, Intent intent) {
389 final boolean wasConnected = mDataConnectionIsConnected;
Alon Alberted1d2532011-02-15 14:02:14 -0800390
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000391 // Don't use the intent to figure out if network is connected, just check
392 // ConnectivityManager directly.
393 mDataConnectionIsConnected = readDataConnectionState();
394 if (mDataConnectionIsConnected) {
395 if (!wasConnected) {
396 if (Log.isLoggable(TAG, Log.VERBOSE)) {
397 Slog.v(TAG, "Reconnection detected: clearing all backoffs");
398 }
Makoto Onukia9dca242017-06-21 17:06:49 -0700399 // Note the location of this code was wrong from nyc to oc; fixed in DR.
400 clearAllBackoffs("network reconnect");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000401 }
Matthew Williams119aac92014-09-28 20:42:23 -0700402 }
Alon Alberted1d2532011-02-15 14:02:14 -0800403 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000404 };
405
Makoto Onukia9dca242017-06-21 17:06:49 -0700406 private void clearAllBackoffs(String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000407 mSyncStorageEngine.clearAllBackoffsLocked();
Makoto Onukia9dca242017-06-21 17:06:49 -0700408 rescheduleSyncs(EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410
Alon Albert1bad83a2011-02-16 10:29:56 -0800411 private boolean readDataConnectionState() {
Alon Alberted1d2532011-02-15 14:02:14 -0800412 NetworkInfo networkInfo = getConnectivityManager().getActiveNetworkInfo();
413 return (networkInfo != null) && networkInfo.isConnected();
414 }
415
Makoto Onukie7b02982017-08-24 14:23:36 -0700416 private String getJobStats() {
417 JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
418 return "JobStats: "
419 + ((js == null) ? "(JobSchedulerInternal==null)"
420 : js.getPersistStats().toString());
421 }
422
Dianne Hackborn55280a92009-05-07 15:53:46 -0700423 private BroadcastReceiver mShutdownIntentReceiver =
424 new BroadcastReceiver() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000425 @Override
426 public void onReceive(Context context, Intent intent) {
427 Log.w(TAG, "Writing sync state before shutdown...");
428 getSyncStorageEngine().writeAllState();
Makoto Onukie7b02982017-08-24 14:23:36 -0700429
430 mLogger.log(getJobStats());
Makoto Onukife224e02017-06-29 14:11:14 -0700431 mLogger.log("Shutting down.");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000432 }
433 };
Dianne Hackborn55280a92009-05-07 15:53:46 -0700434
Makoto Onuki94986212018-04-11 16:24:46 -0700435 private final BroadcastReceiver mOtherIntentsReceiver =
436 new BroadcastReceiver() {
437 @Override
438 public void onReceive(Context context, Intent intent) {
439 if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
440 mSyncStorageEngine.setClockValid();
441 return;
442 }
443 }
444 };
445
Amith Yamasani13593602012-03-22 16:16:17 -0700446 private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
447 @Override
448 public void onReceive(Context context, Intent intent) {
Alon Albert8e285552012-09-17 15:05:27 -0700449 String action = intent.getAction();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700450 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
451 if (userId == UserHandle.USER_NULL) return;
452
Alon Albert8e285552012-09-17 15:05:27 -0700453 if (Intent.ACTION_USER_REMOVED.equals(action)) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700454 onUserRemoved(userId);
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700455 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
456 onUserUnlocked(userId);
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -0700457 } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
458 onUserStopped(userId);
Alon Albert8e285552012-09-17 15:05:27 -0700459 }
Amith Yamasani13593602012-03-22 16:16:17 -0700460 }
461 };
462
Makoto Onukie08a5c22018-04-27 13:28:46 -0700463 private final HandlerThread mThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 private final SyncHandler mSyncHandler;
Makoto Onukiaad2b512018-02-07 09:31:46 -0800465 private final SyncManagerConstants mConstants;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466
Fred Quintana4f9cfc52009-09-02 15:20:23 -0700467 private volatile boolean mBootCompleted = false;
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +0100468 private volatile boolean mJobServiceReady = false;
Fred Quintana4f9cfc52009-09-02 15:20:23 -0700469
Fred Quintanaf892fb32009-08-27 21:32:08 -0700470 private ConnectivityManager getConnectivityManager() {
471 synchronized (this) {
472 if (mConnManagerDoNotUseDirectly == null) {
473 mConnManagerDoNotUseDirectly = (ConnectivityManager)mContext.getSystemService(
474 Context.CONNECTIVITY_SERVICE);
475 }
476 return mConnManagerDoNotUseDirectly;
477 }
478 }
479
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000480 /**
481 * Cancel all unnecessary jobs. This function will be run once after every boot.
482 */
483 private void cleanupJobs() {
484 // O(n^2) in number of jobs, so we run this on the background thread.
485 mSyncHandler.postAtFrontOfQueue(new Runnable() {
486 @Override
487 public void run() {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000488 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000489 Set<String> cleanedKeys = new HashSet<String>();
490 for (SyncOperation opx: ops) {
491 if (cleanedKeys.contains(opx.key)) {
492 continue;
493 }
494 cleanedKeys.add(opx.key);
495 for (SyncOperation opy: ops) {
496 if (opx == opy) {
497 continue;
498 }
499 if (opx.key.equals(opy.key)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700500 mLogger.log("Removing duplicate sync: ", opy);
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700501 cancelJob(opy, "cleanupJobs() x=" + opx + " y=" + opy);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000502 }
503 }
504 }
505 }
506 });
507 }
508
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000509 private synchronized void verifyJobScheduler() {
510 if (mJobScheduler != null) {
511 return;
512 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700513 final long token = Binder.clearCallingIdentity();
514 try {
515 if (Log.isLoggable(TAG, Log.VERBOSE)) {
516 Log.d(TAG, "initializing JobScheduler object.");
517 }
518 mJobScheduler = (JobScheduler) mContext.getSystemService(
519 Context.JOB_SCHEDULER_SERVICE);
520 mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
521 // Get all persisted syncs from JobScheduler
522 List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
523
524 int numPersistedPeriodicSyncs = 0;
525 int numPersistedOneshotSyncs = 0;
526 for (JobInfo job : pendingJobs) {
527 SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
528 if (op != null) {
529 if (op.isPeriodic) {
530 numPersistedPeriodicSyncs++;
531 } else {
532 numPersistedOneshotSyncs++;
533 // Set the pending status of this EndPoint to true. Pending icon is
534 // shown on the settings activity.
535 mSyncStorageEngine.markPending(op.target, true);
536 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000537 }
538 }
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700539 final String summary = "Loaded persisted syncs: "
540 + numPersistedPeriodicSyncs + " periodic syncs, "
541 + numPersistedOneshotSyncs + " oneshot syncs, "
542 + (pendingJobs.size()) + " total system server jobs, "
Makoto Onukie7b02982017-08-24 14:23:36 -0700543 + getJobStats();
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700544 Slog.i(TAG, summary);
545 mLogger.log(summary);
546
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700547 cleanupJobs();
548
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700549 if (ENABLE_SUSPICIOUS_CHECK &&
550 (numPersistedPeriodicSyncs == 0) && likelyHasPeriodicSyncs()) {
551 Slog.wtf(TAG, "Device booted with no persisted periodic syncs: " + summary);
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700552 }
553 } finally {
554 Binder.restoreCallingIdentity(token);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000555 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700556 }
557
558 /**
559 * @return whether the device most likely has some periodic syncs.
560 */
561 private boolean likelyHasPeriodicSyncs() {
562 try {
Makoto Onukib47e8942017-09-18 14:03:03 -0700563 // Each sync adapter has a daily periodic sync by default, but sync adapters can remove
564 // them by themselves. So here, we use an arbitrary threshold. If there are more than
565 // this many sync endpoints, surely one of them should have a periodic sync...
566 return mSyncStorageEngine.getAuthorityCount() >= 6;
Makoto Onukibbf6d8c2017-08-11 12:11:39 -0700567 } catch (Throwable th) {
568 // Just in case.
569 }
570 return false;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000571 }
572
573 private JobScheduler getJobScheduler() {
574 verifyJobScheduler();
575 return mJobScheduler;
576 }
577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 public SyncManager(Context context, boolean factoryTest) {
Makoto Onuki056a9752018-05-08 15:21:56 -0700579 synchronized (SyncManager.class) {
580 if (sInstance == null) {
581 sInstance = this;
582 } else {
583 Slog.wtf(TAG, "SyncManager instantiated multiple times");
584 }
585 }
586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 // Initialize the SyncStorageEngine first, before registering observers
588 // and creating threads and so on; it may fail if the disk is full.
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700589 mContext = context;
Amith Yamasani9535c912012-10-10 21:48:33 -0700590
Makoto Onukia9dca242017-06-21 17:06:49 -0700591 mLogger = SyncLogger.getInstance();
592
Makoto Onuki6963bea72017-12-12 10:42:39 -0800593 SyncStorageEngine.init(context, BackgroundThread.get().getLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 mSyncStorageEngine = SyncStorageEngine.getSingleton();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800595 mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
Matthew Williamsfa774182013-06-18 15:44:11 -0700596 @Override
Makoto Onuki61283ec2018-01-31 17:22:36 -0800597 public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700598 @SyncExemption int syncExemptionFlag) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000599 scheduleSync(info.account, info.userId, reason, info.provider, extras,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700600 AuthorityInfo.UNDEFINED, syncExemptionFlag);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000601 }
602 });
603
604 mSyncStorageEngine.setPeriodicSyncAddedListener(
605 new SyncStorageEngine.PeriodicSyncAddedListener() {
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +0000606 @Override
607 public void onPeriodicSyncAdded(EndPoint target, Bundle extras, long pollFrequency,
608 long flex) {
609 updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
610 }
611 });
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000612
613 mSyncStorageEngine.setOnAuthorityRemovedListener(new SyncStorageEngine.OnAuthorityRemovedListener() {
614 @Override
615 public void onAuthorityRemoved(EndPoint removedAuthority) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700616 removeSyncsForAuthority(removedAuthority, "onAuthorityRemoved");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800617 }
618 });
619
Fred Quintana0c4d04a2010-11-03 17:02:55 -0700620 mSyncAdapters = new SyncAdaptersCache(mContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621
Makoto Onukie08a5c22018-04-27 13:28:46 -0700622 mThread = new HandlerThread("SyncManager", android.os.Process.THREAD_PRIORITY_BACKGROUND);
623 mThread.start();
624 mSyncHandler = new SyncHandler(mThread.getLooper());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625
Fred Quintana44037e62010-01-21 13:14:49 -0800626 mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700627 @Override
628 public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
Fred Quintana44037e62010-01-21 13:14:49 -0800629 if (!removed) {
Alon Albert57286f92012-10-09 14:21:38 -0700630 scheduleSync(null, UserHandle.USER_ALL,
631 SyncOperation.REASON_SERVICE_CHANGED,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800632 type.authority, null, AuthorityInfo.UNDEFINED,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700633 ContentResolver.SYNC_EXEMPTION_NONE);
Fred Quintana44037e62010-01-21 13:14:49 -0800634 }
635 }
636 }, mSyncHandler);
Fred Quintana718d8a22009-04-29 17:53:20 -0700637
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000638 mRand = new Random(System.currentTimeMillis());
Makoto Onukiaad2b512018-02-07 09:31:46 -0800639 mConstants = new SyncManagerConstants(context);
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
642 context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
643
Fred Quintanae91ebe22009-09-29 20:44:30 -0700644 if (!factoryTest) {
645 intentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Dianne Hackbornd83a0962014-05-02 16:28:33 -0700646 intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Fred Quintanae91ebe22009-09-29 20:44:30 -0700647 context.registerReceiver(mBootCompletedReceiver, intentFilter);
648 }
Fred Quintana60307342009-03-24 22:48:12 -0700649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
651 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
652 context.registerReceiver(mStorageIntentReceiver, intentFilter);
653
Dianne Hackborn55280a92009-05-07 15:53:46 -0700654 intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
655 intentFilter.setPriority(100);
656 context.registerReceiver(mShutdownIntentReceiver, intentFilter);
657
Amith Yamasani13593602012-03-22 16:16:17 -0700658 intentFilter = new IntentFilter();
659 intentFilter.addAction(Intent.ACTION_USER_REMOVED);
Jeff Sharkey9d8a1042015-12-03 17:56:20 -0700660 intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -0700661 intentFilter.addAction(Intent.ACTION_USER_STOPPED);
Alon Albert8e285552012-09-17 15:05:27 -0700662 mContext.registerReceiverAsUser(
663 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
Amith Yamasani13593602012-03-22 16:16:17 -0700664
Makoto Onuki94986212018-04-11 16:24:46 -0700665 intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
666 context.registerReceiver(mOtherIntentsReceiver, intentFilter);
667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 if (!factoryTest) {
669 mNotificationMgr = (NotificationManager)
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000670 context.getSystemService(Context.NOTIFICATION_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 } else {
672 mNotificationMgr = null;
673 }
Fred Quintanab3029c32010-04-06 13:27:12 -0700674 mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
Amith Yamasani9535c912012-10-10 21:48:33 -0700675 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700676 mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
677 mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
Svet Ganov973edd192016-09-08 20:15:55 -0700678 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700679
Svet Ganovf6d424f12016-09-20 20:18:53 -0700680 mAccountManagerInternal.addOnAppPermissionChangeListener((Account account, int uid) -> {
681 // If the UID gained access to the account kick-off syncs lacking account access
682 if (mAccountManagerInternal.hasAccountAccess(account, uid)) {
683 scheduleSync(account, UserHandle.getUserId(uid),
684 SyncOperation.REASON_ACCOUNTS_UPDATED,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800685 null, null, AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700686 ContentResolver.SYNC_EXEMPTION_NONE);
Svet Ganovf6d424f12016-09-20 20:18:53 -0700687 }
688 });
689
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800690 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
691 BatteryStats.SERVICE_NAME));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692
693 // This WakeLock is used to ensure that we stay awake between the time that we receive
694 // a sync alarm notification and when we finish processing it. We need to do this
695 // because we don't do the work in the alarm handler, rather we do it in a message
696 // handler.
Fred Quintanab3029c32010-04-06 13:27:12 -0700697 mHandleAlarmWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 HANDLE_SYNC_ALARM_WAKE_LOCK);
699 mHandleAlarmWakeLock.setReferenceCounted(false);
700
Fred Quintana918339a2010-10-05 14:00:39 -0700701 // This WakeLock is used to ensure that we stay awake while running the sync loop
702 // message handler. Normally we will hold a sync adapter wake lock while it is being
703 // synced but during the execution of the sync loop it might finish a sync for
704 // one sync adapter before starting the sync for the other sync adapter and we
705 // don't want the device to go to sleep during that window.
706 mSyncManagerWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
707 SYNC_LOOP_WAKE_LOCK);
708 mSyncManagerWakeLock.setReferenceCounted(false);
709
Matthew Williams8b76d202015-05-03 18:16:25 -0700710 mProvisioned = isDeviceProvisioned();
711 if (!mProvisioned) {
712 final ContentResolver resolver = context.getContentResolver();
713 ContentObserver provisionedObserver =
714 new ContentObserver(null /* current thread */) {
715 public void onChange(boolean selfChange) {
716 mProvisioned |= isDeviceProvisioned();
717 if (mProvisioned) {
718 mSyncHandler.onDeviceProvisioned();
719 resolver.unregisterContentObserver(this);
720 }
721 }
722 };
723
724 synchronized (mSyncHandler) {
725 resolver.registerContentObserver(
726 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
727 false /* notifyForDescendents */,
728 provisionedObserver);
729
730 // The device *may* have been provisioned while we were registering above observer.
731 // Check again to make sure.
732 mProvisioned |= isDeviceProvisioned();
733 if (mProvisioned) {
734 resolver.unregisterContentObserver(provisionedObserver);
735 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700736 }
Matthew Williams8b76d202015-05-03 18:16:25 -0700737 }
Fred Quintanae91ebe22009-09-29 20:44:30 -0700738
739 if (!factoryTest) {
Amith Yamasanid648a602012-09-26 15:06:10 -0700740 // Register for account list updates for all users
741 mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
742 UserHandle.ALL,
743 new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
Matthew Williams5c6756f2014-10-02 04:12:28 +0000744 null, null);
Fred Quintanae91ebe22009-09-29 20:44:30 -0700745 }
Ashish Sharma69d95de2012-04-11 17:27:24 -0700746
Christopher Tate734c91d2016-02-02 12:46:18 -0800747 // Set up the communication channel between the scheduled job and the sync manager.
748 // This is posted to the *main* looper intentionally, to defer calling startService()
749 // until after the lengthy primary boot sequence completes on that thread, to avoid
750 // spurious ANR triggering.
751 final Intent startServiceIntent = new Intent(mContext, SyncJobService.class);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000752 startServiceIntent.putExtra(SyncJobService.EXTRA_MESSENGER, new Messenger(mSyncHandler));
Christopher Tate734c91d2016-02-02 12:46:18 -0800753 new Handler(mContext.getMainLooper()).post(new Runnable() {
754 @Override
755 public void run() {
756 mContext.startService(startServiceIntent);
757 }
758 });
Svet Ganov65712b02016-09-01 10:24:11 -0700759
760 // Sync adapters were able to access the synced account without the accounts
761 // permission which circumvents our permission model. Therefore, we require
762 // sync adapters that don't have access to the account to get user consent.
763 // This can be noisy, therefore we will white-list sync adapters installed
764 // before we started checking for account access because they already know
765 // the account (they run before) which is the genie is out of the bottle.
766 whiteListExistingSyncAdaptersIfNeeded();
Makoto Onukife224e02017-06-29 14:11:14 -0700767
Makoto Onukie7b02982017-08-24 14:23:36 -0700768 mLogger.log("Sync manager initialized: " + Build.FINGERPRINT);
Svet Ganov65712b02016-09-01 10:24:11 -0700769 }
770
Makoto Onukife224e02017-06-29 14:11:14 -0700771 public void onStartUser(int userHandle) {
Makoto Onukif15a9422017-12-11 15:50:58 -0800772 mSyncHandler.post(() -> mLogger.log("onStartUser: user=", userHandle));
Makoto Onukife224e02017-06-29 14:11:14 -0700773 }
774
775 public void onUnlockUser(int userHandle) {
Makoto Onukif15a9422017-12-11 15:50:58 -0800776 mSyncHandler.post(() -> mLogger.log("onUnlockUser: user=", userHandle));
Makoto Onukife224e02017-06-29 14:11:14 -0700777 }
778
779 public void onStopUser(int userHandle) {
Makoto Onukif15a9422017-12-11 15:50:58 -0800780 mSyncHandler.post(() -> mLogger.log("onStopUser: user=", userHandle));
Makoto Onukife224e02017-06-29 14:11:14 -0700781 }
782
Makoto Onukiaad2b512018-02-07 09:31:46 -0800783 public void onBootPhase(int phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800784 // Note SyncManager only receives PHASE_ACTIVITY_MANAGER_READY and after.
Makoto Onukiaad2b512018-02-07 09:31:46 -0800785 switch (phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800786 case SystemService.PHASE_ACTIVITY_MANAGER_READY:
Makoto Onukiaad2b512018-02-07 09:31:46 -0800787 mConstants.start();
788 break;
789 }
790 }
Makoto Onukife224e02017-06-29 14:11:14 -0700791
Svet Ganov65712b02016-09-01 10:24:11 -0700792 private void whiteListExistingSyncAdaptersIfNeeded() {
793 if (!mSyncStorageEngine.shouldGrantSyncAdaptersAccountAccess()) {
794 return;
795 }
796 List<UserInfo> users = mUserManager.getUsers(true);
797 final int userCount = users.size();
798 for (int i = 0; i < userCount; i++) {
799 UserHandle userHandle = users.get(i).getUserHandle();
800 final int userId = userHandle.getIdentifier();
801 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> service
802 : mSyncAdapters.getAllServices(userId)) {
803 String packageName = service.componentName.getPackageName();
804 for (Account account : mAccountManager.getAccountsByTypeAsUser(
805 service.type.accountType, userHandle)) {
806 if (!canAccessAccount(account, packageName, userId)) {
807 mAccountManager.updateAppPermission(account,
Svet Ganovf6d424f12016-09-20 20:18:53 -0700808 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, service.uid, true);
Svet Ganov65712b02016-09-01 10:24:11 -0700809 }
810 }
811 }
812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 }
814
Matthew Williams8b76d202015-05-03 18:16:25 -0700815 private boolean isDeviceProvisioned() {
816 final ContentResolver resolver = mContext.getContentResolver();
817 return (Settings.Global.getInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0) != 0);
818 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 /**
820 * Return a random value v that satisfies minValue <= v < maxValue. The difference between
821 * maxValue and minValue must be less than Integer.MAX_VALUE.
822 */
823 private long jitterize(long minValue, long maxValue) {
824 Random random = new Random(SystemClock.elapsedRealtime());
825 long spread = maxValue - minValue;
826 if (spread > Integer.MAX_VALUE) {
827 throw new IllegalArgumentException("the difference between the maxValue and the "
828 + "minValue must be less than " + Integer.MAX_VALUE);
829 }
830 return minValue + random.nextInt((int)spread);
831 }
832
Dianne Hackborn231cc602009-04-27 17:10:36 -0700833 public SyncStorageEngine getSyncStorageEngine() {
834 return mSyncStorageEngine;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 }
Doug Zongker44f57472009-09-20 15:52:43 -0700836
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700837 private int getIsSyncable(Account account, int userId, String providerName) {
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700838 int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
839 UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
840
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000841 // If it's not a restricted user, return isSyncable.
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700842 if (userInfo == null || !userInfo.isRestricted()) return isSyncable;
843
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000844 // Else check if the sync adapter has opted-in or not.
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700845 RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
846 mSyncAdapters.getServiceInfo(
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000847 SyncAdapterType.newKey(providerName, account.type), userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700848 if (syncAdapterInfo == null) return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700849
850 PackageInfo pInfo = null;
851 try {
852 pInfo = AppGlobals.getPackageManager().getPackageInfo(
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000853 syncAdapterInfo.componentName.getPackageName(), 0, userId);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700854 if (pInfo == null) return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700855 } catch (RemoteException re) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000856 // Shouldn't happen.
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700857 return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700858 }
859 if (pInfo.restrictedAccountType != null
860 && pInfo.restrictedAccountType.equals(account.type)) {
861 return isSyncable;
862 } else {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700863 return AuthorityInfo.NOT_SYNCABLE;
Amith Yamasani9422bdc2013-04-10 16:58:19 -0700864 }
865 }
866
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000867 private void setAuthorityPendingState(EndPoint info) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +0000868 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000869 for (SyncOperation op: ops) {
870 if (!op.isPeriodic && op.target.matchesSpec(info)) {
871 getSyncStorageEngine().markPending(info, true);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700872 return;
873 }
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700874 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000875 getSyncStorageEngine().markPending(info, false);
Matthew Williamsfa774182013-06-18 15:44:11 -0700876 }
877
878 /**
879 * Initiate a sync. This can start a sync for all providers
880 * (pass null to url, set onlyTicklable to false), only those
881 * providers that are marked as ticklable (pass null to url,
882 * set onlyTicklable to true), or a specific provider (set url
883 * to the content url of the provider).
884 *
885 * <p>If the ContentResolver.SYNC_EXTRAS_UPLOAD boolean in extras is
886 * true then initiate a sync that just checks for local changes to send
887 * to the server, otherwise initiate a sync that first gets any
888 * changes from the server before sending local changes back to
889 * the server.
890 *
891 * <p>If a specific provider is being synced (the url is non-null)
892 * then the extras can contain SyncAdapter-specific information
893 * to control what gets synced (e.g. which specific feed to sync).
894 *
895 * <p>You'll start getting callbacks after this.
896 *
897 * @param requestedAccount the account to sync, may be null to signify all accounts
898 * @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
899 * then all users' accounts are considered.
900 * @param reason for sync request. If this is a positive integer, it is the Linux uid
901 * assigned to the process that requested the sync. If it's negative, the sync was requested by
902 * the SyncManager itself and could be one of the following:
903 * {@link SyncOperation#REASON_BACKGROUND_DATA_SETTINGS_CHANGED}
904 * {@link SyncOperation#REASON_ACCOUNTS_UPDATED}
905 * {@link SyncOperation#REASON_SERVICE_CHANGED}
906 * {@link SyncOperation#REASON_PERIODIC}
907 * {@link SyncOperation#REASON_IS_SYNCABLE}
908 * {@link SyncOperation#REASON_SYNC_AUTO}
909 * {@link SyncOperation#REASON_MASTER_SYNC_AUTO}
910 * {@link SyncOperation#REASON_USER_START}
911 * @param requestedAuthority the authority to sync, may be null to indicate all authorities
912 * @param extras a Map of SyncAdapter-specific information to control
913 * syncs of a specific provider. Can be null. Is ignored
914 * if the url is null.
Svet Ganovf6d424f12016-09-20 20:18:53 -0700915 * @param targetSyncState Only sync authorities that have the specified sync state.
916 * Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
Matthew Williamsfa774182013-06-18 15:44:11 -0700917 */
918 public void scheduleSync(Account requestedAccount, int userId, int reason,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800919 String requestedAuthority, Bundle extras, int targetSyncState,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700920 @SyncExemption int syncExemptionFlag) {
Shreyas Basargeba1f7902016-10-01 00:19:44 +0100921 scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700922 0 /* min delay */, true /* checkIfAccountReady */, syncExemptionFlag);
Shreyas Basargeba1f7902016-10-01 00:19:44 +0100923 }
924
925 /**
926 * @param minDelayMillis The sync can't land before this delay expires.
927 */
928 private void scheduleSync(Account requestedAccount, int userId, int reason,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800929 String requestedAuthority, Bundle extras, int targetSyncState,
930 final long minDelayMillis, boolean checkIfAccountReady,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700931 @SyncExemption int syncExemptionFlag) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000932 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Matthew Williamsfa774182013-06-18 15:44:11 -0700933 if (extras == null) {
934 extras = new Bundle();
935 }
936 if (isLoggable) {
937 Log.d(TAG, "one-time sync for: " + requestedAccount + " " + extras.toString() + " "
Makoto Onukiaad2b512018-02-07 09:31:46 -0800938 + requestedAuthority
939 + " reason=" + reason
940 + " checkIfAccountReady=" + checkIfAccountReady
Makoto Onuki75ad2492018-03-28 14:42:42 -0700941 + " syncExemptionFlag=" + syncExemptionFlag);
Matthew Williamsfa774182013-06-18 15:44:11 -0700942 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700943
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700944 AccountAndUser[] accounts = null;
945 if (requestedAccount != null) {
946 if (userId != UserHandle.USER_ALL) {
947 accounts = new AccountAndUser[]{new AccountAndUser(requestedAccount, userId)};
948 } else {
949 for (AccountAndUser runningAccount : mRunningAccounts) {
950 if (requestedAccount.equals(runningAccount.account)) {
951 accounts = ArrayUtils.appendElement(AccountAndUser.class,
952 accounts, runningAccount);
953 }
954 }
955 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700956 } else {
Matthew Williamsfa774182013-06-18 15:44:11 -0700957 accounts = mRunningAccounts;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700958 }
959
960 if (ArrayUtils.isEmpty(accounts)) {
961 if (isLoggable) {
962 Slog.v(TAG, "scheduleSync: no accounts configured, dropping");
Matthew Williamsfa774182013-06-18 15:44:11 -0700963 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700964 return;
Matthew Williamsfa774182013-06-18 15:44:11 -0700965 }
966
967 final boolean uploadOnly = extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
968 final boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
969 if (manualSync) {
970 extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true);
971 extras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true);
972 }
973 final boolean ignoreSettings =
974 extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
975
976 int source;
977 if (uploadOnly) {
978 source = SyncStorageEngine.SOURCE_LOCAL;
979 } else if (manualSync) {
980 source = SyncStorageEngine.SOURCE_USER;
981 } else if (requestedAuthority == null) {
982 source = SyncStorageEngine.SOURCE_POLL;
983 } else {
Makoto Onuki94986212018-04-11 16:24:46 -0700984 if (extras.containsKey("feed")) {
985 source = SyncStorageEngine.SOURCE_FEED;
986 } else{
987 // This isn't strictly server, since arbitrary callers can (and do) request
988 // a non-forced two-way sync on a specific url.
989 source = SyncStorageEngine.SOURCE_OTHER;
990 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700991 }
992
993 for (AccountAndUser account : accounts) {
Fyodor Kupolov6fde2982015-01-06 17:46:37 -0800994 // If userId is specified, do not sync accounts of other users
Xiaohui Chen98404fd2015-08-17 16:09:02 -0700995 if (userId >= UserHandle.USER_SYSTEM && account.userId >= UserHandle.USER_SYSTEM
Fyodor Kupolov6fde2982015-01-06 17:46:37 -0800996 && userId != account.userId) {
997 continue;
998 }
Matthew Williamsfa774182013-06-18 15:44:11 -0700999 // Compile a list of authorities that have sync adapters.
1000 // For each authority sync each account that matches a sync adapter.
1001 final HashSet<String> syncableAuthorities = new HashSet<String>();
1002 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapter :
1003 mSyncAdapters.getAllServices(account.userId)) {
1004 syncableAuthorities.add(syncAdapter.type.authority);
1005 }
1006
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001007 // If the url was specified then replace the list of authorities
Matthew Williamsfa774182013-06-18 15:44:11 -07001008 // with just this authority or clear it if this authority isn't
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001009 // syncable.
Matthew Williamsfa774182013-06-18 15:44:11 -07001010 if (requestedAuthority != null) {
1011 final boolean hasSyncAdapter = syncableAuthorities.contains(requestedAuthority);
1012 syncableAuthorities.clear();
1013 if (hasSyncAdapter) syncableAuthorities.add(requestedAuthority);
1014 }
1015
1016 for (String authority : syncableAuthorities) {
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001017 int isSyncable = computeSyncable(account.account, account.userId, authority,
1018 !checkIfAccountReady);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001019
Matthew Williams53abfdb2015-06-10 20:06:37 -07001020 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001021 continue;
1022 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001023
1024 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
1025 mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority,
1026 account.account.type), account.userId);
Matthew Williamsfa774182013-06-18 15:44:11 -07001027 if (syncAdapterInfo == null) {
1028 continue;
1029 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001030
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001031 final int owningUid = syncAdapterInfo.uid;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001032
1033 if (isSyncable == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
1034 if (isLoggable) {
1035 Slog.v(TAG, " Not scheduling sync operation: "
1036 + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001037 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001038 Bundle finalExtras = new Bundle(extras);
Svet Ganov973edd192016-09-08 20:15:55 -07001039 String packageName = syncAdapterInfo.componentName.getPackageName();
1040 // If the app did not run and has no account access, done
Amith Yamasani2cbfa1e2017-03-28 10:34:01 -07001041 try {
1042 if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
1043 continue;
1044 }
1045 } catch (IllegalArgumentException e) {
1046 // Package not found, race with an uninstall
Svet Ganov973edd192016-09-08 20:15:55 -07001047 continue;
1048 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001049 mAccountManagerInternal.requestAccountAccess(account.account,
Svet Ganov973edd192016-09-08 20:15:55 -07001050 packageName, userId,
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001051 new RemoteCallback((Bundle result) -> {
1052 if (result != null
1053 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
1054 scheduleSync(account.account, userId, reason, authority,
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001055 finalExtras, targetSyncState, minDelayMillis,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001056 true /* checkIfAccountReady */,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001057 syncExemptionFlag);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001058 }
1059 }
1060 ));
1061 continue;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001062 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001063
Matthew Williamsfa774182013-06-18 15:44:11 -07001064 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
1065 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001066 if (!checkIfAccountReady && isSyncable < 0 && isAlwaysSyncable) {
Matthew Williams53abfdb2015-06-10 20:06:37 -07001067 mSyncStorageEngine.setIsSyncable(
Makoto Onukid4764302018-03-30 17:32:57 -07001068 account.account, account.userId, authority, AuthorityInfo.SYNCABLE,
1069 SyncLogger.CALLING_UID_SELF);
Matthew Williams53abfdb2015-06-10 20:06:37 -07001070 isSyncable = AuthorityInfo.SYNCABLE;
Matthew Williamsfa774182013-06-18 15:44:11 -07001071 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001072
Svet Ganovf6d424f12016-09-20 20:18:53 -07001073 if (targetSyncState != AuthorityInfo.UNDEFINED && targetSyncState != isSyncable) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001074 continue;
1075 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07001076
Matthew Williamsfa774182013-06-18 15:44:11 -07001077 if (!syncAdapterInfo.type.supportsUploading() && uploadOnly) {
1078 continue;
1079 }
1080
Matthew Williamsfa774182013-06-18 15:44:11 -07001081 boolean syncAllowed =
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001082 (isSyncable < 0) // Always allow if the isSyncable state is unknown.
1083 || ignoreSettings
1084 || (mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
Matthew Williamsfa774182013-06-18 15:44:11 -07001085 && mSyncStorageEngine.getSyncAutomatically(account.account,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001086 account.userId, authority));
Matthew Williamsfa774182013-06-18 15:44:11 -07001087 if (!syncAllowed) {
1088 if (isLoggable) {
1089 Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
1090 + " is not allowed, dropping request");
1091 }
1092 continue;
1093 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001094 SyncStorageEngine.EndPoint info =
1095 new SyncStorageEngine.EndPoint(
1096 account.account, authority, account.userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001097 long delayUntil =
1098 mSyncStorageEngine.getDelayUntilTime(info);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001099
1100 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
1101
Svet Ganovf6d424f12016-09-20 20:18:53 -07001102 if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001103 if (checkIfAccountReady) {
1104 Bundle finalExtras = new Bundle(extras);
1105
1106 sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId,
1107 () -> scheduleSync(account.account, account.userId, reason,
1108 authority, finalExtras, targetSyncState, minDelayMillis,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001109 false, syncExemptionFlag));
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001110 } else {
1111 // Initialisation sync.
1112 Bundle newExtras = new Bundle();
1113 newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
1114 if (isLoggable) {
1115 Slog.v(TAG, "schedule initialisation Sync:"
1116 + ", delay until " + delayUntil
1117 + ", run by " + 0
1118 + ", flexMillis " + 0
1119 + ", source " + source
1120 + ", account " + account
1121 + ", authority " + authority
1122 + ", extras " + newExtras);
1123 }
1124 postScheduleSyncMessage(
1125 new SyncOperation(account.account, account.userId,
1126 owningUid, owningPackage, reason, source,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001127 authority, newExtras, allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001128 syncExemptionFlag),
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001129 minDelayMillis
1130 );
Matthew Williamsfa774182013-06-18 15:44:11 -07001131 }
Svet Ganovf6d424f12016-09-20 20:18:53 -07001132 } else if (targetSyncState == AuthorityInfo.UNDEFINED
1133 || targetSyncState == isSyncable) {
Matthew Williamsfa774182013-06-18 15:44:11 -07001134 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001135 Slog.v(TAG, "scheduleSync:"
Matthew Williamsfa774182013-06-18 15:44:11 -07001136 + " delay until " + delayUntil
Matthew Williamsfa774182013-06-18 15:44:11 -07001137 + ", source " + source
1138 + ", account " + account
1139 + ", authority " + authority
1140 + ", extras " + extras);
1141 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001142 postScheduleSyncMessage(
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001143 new SyncOperation(account.account, account.userId,
1144 owningUid, owningPackage, reason, source,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001145 authority, extras, allowParallelSyncs, syncExemptionFlag),
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001146 minDelayMillis
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001147 );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 }
1149 }
1150 }
1151 }
1152
Svet Ganov96b9c752016-10-17 19:29:58 -07001153 public int computeSyncable(Account account, int userId, String authority,
1154 boolean checkAccountAccess) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001155 final int status = getIsSyncable(account, userId, authority);
1156 if (status == AuthorityInfo.NOT_SYNCABLE) {
1157 return AuthorityInfo.NOT_SYNCABLE;
1158 }
1159 final SyncAdapterType type = SyncAdapterType.newKey(authority, account.type);
1160 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo =
1161 mSyncAdapters.getServiceInfo(type, userId);
1162 if (syncAdapterInfo == null) {
1163 return AuthorityInfo.NOT_SYNCABLE;
1164 }
1165 final int owningUid = syncAdapterInfo.uid;
1166 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
1167 try {
Dianne Hackbornc3af19a2017-01-20 17:00:44 -08001168 if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001169 Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
1170 + syncAdapterInfo.componentName
1171 + " -- package not allowed to start");
1172 return AuthorityInfo.NOT_SYNCABLE;
1173 }
1174 } catch (RemoteException e) {
1175 /* ignore - local call */
1176 }
Svet Ganov96b9c752016-10-17 19:29:58 -07001177 if (checkAccountAccess && !canAccessAccount(account, owningPackage, owningUid)) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07001178 Log.w(TAG, "Access to " + account + " denied for package "
1179 + owningPackage + " in UID " + syncAdapterInfo.uid);
1180 return AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS;
1181 }
1182
1183 return status;
1184 }
1185
1186 private boolean canAccessAccount(Account account, String packageName, int uid) {
1187 if (mAccountManager.hasAccountAccess(account, packageName,
1188 UserHandle.getUserHandleForUid(uid))) {
1189 return true;
1190 }
1191 // We relax the account access rule to also include the system apps as
1192 // they are trusted and we want to minimize the cases where the user
1193 // involvement is required to grant access to the synced account.
1194 try {
1195 mContext.getPackageManager().getApplicationInfoAsUser(packageName,
1196 PackageManager.MATCH_SYSTEM_ONLY, UserHandle.getUserId(uid));
1197 return true;
1198 } catch (NameNotFoundException e) {
1199 return false;
1200 }
1201 }
1202
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001203 private void removeSyncsForAuthority(EndPoint info, String why) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001204 mLogger.log("removeSyncsForAuthority: ", info);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001205 verifyJobScheduler();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001206 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001207 for (SyncOperation op: ops) {
1208 if (op.target.matchesSpec(info)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001209 mLogger.log("canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001210 cancelJob(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001211 }
1212 }
1213 }
1214
1215 /**
1216 * Remove a specific periodic sync identified by its target and extras.
1217 */
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001218 public void removePeriodicSync(EndPoint target, Bundle extras, String why) {
1219 Message m = mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_REMOVE_PERIODIC_SYNC,
1220 Pair.create(target, why));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001221 m.setData(extras);
1222 m.sendToTarget();
1223 }
1224
1225 /**
1226 * Add a periodic sync. If a sync with same target and extras exists, its period and
1227 * flexMillis will be updated.
1228 */
1229 public void updateOrAddPeriodicSync(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001230 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001231 UpdatePeriodicSyncMessagePayload payload = new UpdatePeriodicSyncMessagePayload(target,
1232 pollFrequency, flex, extras);
1233 mSyncHandler.obtainMessage(SyncHandler.MESSAGE_UPDATE_PERIODIC_SYNC, payload)
1234 .sendToTarget();
1235 }
1236
1237 /**
1238 * Get a list of periodic syncs corresponding to the given target.
1239 */
1240 public List<PeriodicSync> getPeriodicSyncs(EndPoint target) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001241 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001242 List<PeriodicSync> periodicSyncs = new ArrayList<PeriodicSync>();
1243
1244 for (SyncOperation op: ops) {
1245 if (op.isPeriodic && op.target.matchesSpec(target)) {
1246 periodicSyncs.add(new PeriodicSync(op.target.account, op.target.provider,
1247 op.extras, op.periodMillis / 1000, op.flexMillis / 1000));
1248 }
1249 }
1250
1251 return periodicSyncs;
1252 }
1253
Matthew Williamsfa774182013-06-18 15:44:11 -07001254 /**
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001255 * Schedule sync based on local changes to a provider. We wait for at least LOCAL_SYNC_DELAY
1256 * ms to batch syncs.
Matthew Williamsfa774182013-06-18 15:44:11 -07001257 */
Makoto Onuki61283ec2018-01-31 17:22:36 -08001258 public void scheduleLocalSync(Account account, int userId, int reason, String authority,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001259 @SyncExemption int syncExemptionFlag) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 final Bundle extras = new Bundle();
1261 extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
Matthew Williamsfa774182013-06-18 15:44:11 -07001262 scheduleSync(account, userId, reason, authority, extras,
Makoto Onuki61283ec2018-01-31 17:22:36 -08001263 AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001264 syncExemptionFlag);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 }
1266
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001267 public SyncAdapterType[] getSyncAdapterTypes(int userId) {
1268 final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
1269 serviceInfos = mSyncAdapters.getAllServices(userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -07001270 SyncAdapterType[] types = new SyncAdapterType[serviceInfos.size()];
1271 int i = 0;
1272 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
1273 types[i] = serviceInfo.type;
1274 ++i;
1275 }
1276 return types;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 }
1278
Amith Yamasani37a40c22015-06-17 13:25:42 -07001279 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
1280 return mSyncAdapters.getSyncAdapterPackagesForAuthority(authority, userId);
1281 }
1282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001284 SyncResult syncResult) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001285 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 Message msg = mSyncHandler.obtainMessage();
1287 msg.what = SyncHandler.MESSAGE_SYNC_FINISHED;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001288 msg.obj = new SyncFinishedOrCancelledMessagePayload(syncContext, syncResult);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 mSyncHandler.sendMessage(msg);
1290 }
1291
Makoto Onukia9dca242017-06-21 17:06:49 -07001292 private void sendCancelSyncsMessage(final SyncStorageEngine.EndPoint info, Bundle extras,
1293 String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001294 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_CANCEL");
Makoto Onukia9dca242017-06-21 17:06:49 -07001295
1296 mLogger.log("sendCancelSyncsMessage() ep=", info, " why=", why);
1297
Fred Quintana918339a2010-10-05 14:00:39 -07001298 Message msg = mSyncHandler.obtainMessage();
1299 msg.what = SyncHandler.MESSAGE_CANCEL;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001300 msg.setData(extras);
1301 msg.obj = info;
Fred Quintana918339a2010-10-05 14:00:39 -07001302 mSyncHandler.sendMessage(msg);
1303 }
1304
Matthew Williams92a1c092014-08-25 19:18:32 -07001305 /**
Matthew Williams1967c8d2015-06-19 19:03:13 -07001306 * Post a delayed message that will monitor the given sync context by periodically checking how
1307 * much network has been used by the uid.
Matthew Williams92a1c092014-08-25 19:18:32 -07001308 */
Matthew Williams1967c8d2015-06-19 19:03:13 -07001309 private void postMonitorSyncProgressMessage(ActiveSyncContext activeSyncContext) {
Matthew Williams92a1c092014-08-25 19:18:32 -07001310 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001311 Slog.v(TAG, "posting MESSAGE_SYNC_MONITOR in " +
Matthew Williams1967c8d2015-06-19 19:03:13 -07001312 (SYNC_MONITOR_WINDOW_LENGTH_MILLIS/1000) + "s");
Matthew Williams92a1c092014-08-25 19:18:32 -07001313 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07001314
1315 activeSyncContext.mBytesTransferredAtLastPoll =
1316 getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
1317 activeSyncContext.mLastPolledTimeElapsed = SystemClock.elapsedRealtime();
1318 Message monitorMessage =
1319 mSyncHandler.obtainMessage(
1320 SyncHandler.MESSAGE_MONITOR_SYNC,
1321 activeSyncContext);
1322 mSyncHandler.sendMessageDelayed(monitorMessage, SYNC_MONITOR_WINDOW_LENGTH_MILLIS);
Matthew Williams92a1c092014-08-25 19:18:32 -07001323 }
1324
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001325 private void postScheduleSyncMessage(SyncOperation syncOperation, long minDelayMillis) {
1326 ScheduleSyncMessagePayload payload =
1327 new ScheduleSyncMessagePayload(syncOperation, minDelayMillis);
1328 mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, payload).sendToTarget();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001329 }
1330
Matthew Williams1967c8d2015-06-19 19:03:13 -07001331 /**
1332 * Monitor sync progress by calculating how many bytes it is managing to send to and fro.
1333 */
1334 private long getTotalBytesTransferredByUid(int uid) {
1335 return (TrafficStats.getUidRxBytes(uid) + TrafficStats.getUidTxBytes(uid));
1336 }
1337
1338 /**
1339 * Convenience class for passing parameters for a finished or cancelled sync to the handler
1340 * to be processed.
1341 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001342 private class SyncFinishedOrCancelledMessagePayload {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 public final ActiveSyncContext activeSyncContext;
1344 public final SyncResult syncResult;
1345
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001346 SyncFinishedOrCancelledMessagePayload(ActiveSyncContext syncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001347 SyncResult syncResult) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 this.activeSyncContext = syncContext;
1349 this.syncResult = syncResult;
1350 }
1351 }
1352
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001353 private class UpdatePeriodicSyncMessagePayload {
1354 public final EndPoint target;
1355 public final long pollFrequency;
1356 public final long flex;
1357 public final Bundle extras;
1358
1359 UpdatePeriodicSyncMessagePayload(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001360 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001361 this.target = target;
1362 this.pollFrequency = pollFrequency;
1363 this.flex = flex;
1364 this.extras = extras;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365 }
1366 }
1367
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001368 private static class ScheduleSyncMessagePayload {
1369 final SyncOperation syncOperation;
1370 final long minDelayMillis;
1371
1372 ScheduleSyncMessagePayload(SyncOperation syncOperation, long minDelayMillis) {
1373 this.syncOperation = syncOperation;
1374 this.minDelayMillis = minDelayMillis;
1375 }
1376 }
1377
Makoto Onukia9dca242017-06-21 17:06:49 -07001378 private void clearBackoffSetting(EndPoint target, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001379 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
1380 if (backoff != null && backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE &&
1381 backoff.second == SyncStorageEngine.NOT_IN_BACKOFF_MODE) {
1382 return;
1383 }
1384 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1385 Slog.v(TAG, "Clearing backoffs for " + target);
1386 }
1387 mSyncStorageEngine.setBackoff(target,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001388 SyncStorageEngine.NOT_IN_BACKOFF_MODE,
1389 SyncStorageEngine.NOT_IN_BACKOFF_MODE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001390
Makoto Onukia9dca242017-06-21 17:06:49 -07001391 rescheduleSyncs(target, why);
Alon Albert6e079a32010-11-12 12:41:09 -08001392 }
1393
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001394 private void increaseBackoffSetting(EndPoint target) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001395 final long now = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396
Fred Quintana307da1a2010-01-21 14:24:20 -08001397 final Pair<Long, Long> previousSettings =
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001398 mSyncStorageEngine.getBackoff(target);
Alon Albertaeeb6202010-12-09 16:14:02 -08001399 long newDelayInMs = -1;
1400 if (previousSettings != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001401 // Don't increase backoff before current backoff is expired. This will happen for op's
Alon Albertaeeb6202010-12-09 16:14:02 -08001402 // with ignoreBackoff set.
1403 if (now < previousSettings.first) {
1404 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001405 Slog.v(TAG, "Still in backoff, do not increase it. "
1406 + "Remaining: " + ((previousSettings.first - now) / 1000) + " seconds.");
Alon Albertaeeb6202010-12-09 16:14:02 -08001407 }
1408 return;
1409 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001410 // Subsequent delays are the double of the previous delay.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001411 newDelayInMs =
1412 (long) (previousSettings.second * mConstants.getRetryTimeIncreaseFactor());
Alon Albertaeeb6202010-12-09 16:14:02 -08001413 }
1414 if (newDelayInMs <= 0) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001415 // The initial delay is the jitterized INITIAL_SYNC_RETRY_TIME_IN_MS.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001416 final long initialRetryMs = mConstants.getInitialSyncRetryTimeInSeconds() * 1000;
1417 newDelayInMs = jitterize(initialRetryMs, (long)(initialRetryMs * 1.1));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 }
1419
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001420 // Cap the delay.
Makoto Onukiaad2b512018-02-07 09:31:46 -08001421 final long maxSyncRetryTimeInSeconds = mConstants.getMaxSyncRetryTimeInSeconds();
1422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 if (newDelayInMs > maxSyncRetryTimeInSeconds * 1000) {
1424 newDelayInMs = maxSyncRetryTimeInSeconds * 1000;
1425 }
1426
Alon Albertc1ac7762010-10-28 13:35:55 -07001427 final long backoff = now + newDelayInMs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001428 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1429 Slog.v(TAG, "Backoff until: " + backoff + ", delayTime: " + newDelayInMs);
1430 }
1431 mSyncStorageEngine.setBackoff(target, backoff, newDelayInMs);
Makoto Onukia9dca242017-06-21 17:06:49 -07001432 rescheduleSyncs(target, "increaseBackoffSetting");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001433 }
Alon Albertc1ac7762010-10-28 13:35:55 -07001434
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001435 /**
1436 * Reschedule all scheduled syncs for this EndPoint. The syncs will be scheduled according
1437 * to current backoff and delayUntil values of this EndPoint.
1438 */
Makoto Onukia9dca242017-06-21 17:06:49 -07001439 private void rescheduleSyncs(EndPoint target, String why) {
1440 mLogger.log("rescheduleSyncs() ep=", target, " why=", why);
1441
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001442 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001443 int count = 0;
1444 for (SyncOperation op: ops) {
1445 if (!op.isPeriodic && op.target.matchesSpec(target)) {
1446 count++;
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001447 cancelJob(op, why);
Shreyas Basargeba1f7902016-10-01 00:19:44 +01001448 postScheduleSyncMessage(op, 0 /* min delay */);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001449 }
1450 }
1451 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1452 Slog.v(TAG, "Rescheduled " + count + " syncs for " + target);
Fred Quintana918339a2010-10-05 14:00:39 -07001453 }
Fred Quintana307da1a2010-01-21 14:24:20 -08001454 }
1455
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001456 private void setDelayUntilTime(EndPoint target, long delayUntilSeconds) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001457 final long delayUntil = delayUntilSeconds * 1000;
1458 final long absoluteNow = System.currentTimeMillis();
1459 long newDelayUntilTime;
1460 if (delayUntil > absoluteNow) {
1461 newDelayUntilTime = SystemClock.elapsedRealtime() + (delayUntil - absoluteNow);
1462 } else {
1463 newDelayUntilTime = 0;
1464 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001465 mSyncStorageEngine.setDelayUntilTime(target, newDelayUntilTime);
1466 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1467 Slog.v(TAG, "Delay Until time set to " + newDelayUntilTime + " for " + target);
Fred Quintana918339a2010-10-05 14:00:39 -07001468 }
Makoto Onukia9dca242017-06-21 17:06:49 -07001469 rescheduleSyncs(target, "delayUntil newDelayUntilTime: " + newDelayUntilTime);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001470 }
1471
1472 private boolean isAdapterDelayed(EndPoint target) {
1473 long now = SystemClock.elapsedRealtime();
1474 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
1475 if (backoff != null && backoff.first != SyncStorageEngine.NOT_IN_BACKOFF_MODE
1476 && backoff.first > now) {
1477 return true;
1478 }
1479 if (mSyncStorageEngine.getDelayUntilTime(target) > now) {
1480 return true;
1481 }
1482 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 }
1484
1485 /**
Matthew Williams8ef22042013-07-26 12:56:39 -07001486 * Cancel the active sync if it matches the target.
1487 * @param info object containing info about which syncs to cancel. The target can
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001488 * have null account/provider info to specify all accounts/providers.
1489 * @param extras if non-null, specifies the exact sync to remove.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 */
Makoto Onukia9dca242017-06-21 17:06:49 -07001491 public void cancelActiveSync(SyncStorageEngine.EndPoint info, Bundle extras, String why) {
1492 sendCancelSyncsMessage(info, extras, why);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 }
1494
1495 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001496 * Schedule a sync operation with JobScheduler.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001498 private void scheduleSyncOperationH(SyncOperation syncOperation) {
1499 scheduleSyncOperationH(syncOperation, 0L);
1500 }
1501
1502 private void scheduleSyncOperationH(SyncOperation syncOperation, long minDelay) {
1503 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
1504 if (syncOperation == null) {
1505 Slog.e(TAG, "Can't schedule null sync operation.");
1506 return;
1507 }
1508 if (!syncOperation.ignoreBackoff()) {
1509 Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target);
1510 if (backoff == null) {
1511 Slog.e(TAG, "Couldn't find backoff values for " + syncOperation.target);
1512 backoff = new Pair<Long, Long>(SyncStorageEngine.NOT_IN_BACKOFF_MODE,
1513 SyncStorageEngine.NOT_IN_BACKOFF_MODE);
1514 }
1515 long now = SystemClock.elapsedRealtime();
1516 long backoffDelay = backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE ? 0
1517 : backoff.first - now;
1518 long delayUntil = mSyncStorageEngine.getDelayUntilTime(syncOperation.target);
1519 long delayUntilDelay = delayUntil > now ? delayUntil - now : 0;
1520 if (isLoggable) {
1521 Slog.v(TAG, "backoff delay:" + backoffDelay
1522 + " delayUntil delay:" + delayUntilDelay);
1523 }
1524 minDelay = Math.max(minDelay, Math.max(backoffDelay, delayUntilDelay));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 }
1526
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001527 if (minDelay < 0) {
1528 minDelay = 0;
1529 }
1530
1531 // Check if duplicate syncs are pending. If found, keep one with least expected run time.
Makoto Onuki61283ec2018-01-31 17:22:36 -08001532
1533 // If any of the duplicate ones has exemption, then we inherit it.
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001534 if (!syncOperation.isPeriodic) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001535 int inheritedSyncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001536
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001537 // Check currently running syncs
1538 for (ActiveSyncContext asc: mActiveSyncContexts) {
1539 if (asc.mSyncOperation.key.equals(syncOperation.key)) {
1540 if (isLoggable) {
1541 Log.v(TAG, "Duplicate sync is already running. Not scheduling "
1542 + syncOperation);
1543 }
1544 return;
1545 }
1546 }
1547
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001548 int duplicatesCount = 0;
1549 long now = SystemClock.elapsedRealtime();
1550 syncOperation.expectedRuntime = now + minDelay;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001551 List<SyncOperation> pending = getAllPendingSyncs();
Makoto Onuki61283ec2018-01-31 17:22:36 -08001552 SyncOperation syncToRun = syncOperation;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001553 for (SyncOperation op : pending) {
1554 if (op.isPeriodic) {
1555 continue;
1556 }
1557 if (op.key.equals(syncOperation.key)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001558 if (syncToRun.expectedRuntime > op.expectedRuntime) {
1559 syncToRun = op;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001560 }
1561 duplicatesCount++;
1562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001564 if (duplicatesCount > 1) {
1565 Slog.e(TAG, "FATAL ERROR! File a bug if you see this.");
1566 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001567
1568 if (syncOperation != syncToRun) {
1569 // If there's a duplicate with an earlier run time that's not exempted,
1570 // and if the current operation is exempted with no minDelay,
1571 // cancel the duplicate one and keep the current one.
1572 //
1573 // This means the duplicate one has a negative expected run time, but it hasn't
1574 // been executed possibly because of app-standby.
1575
Makoto Onuki75ad2492018-03-28 14:42:42 -07001576 if ((minDelay == 0)
1577 && (syncToRun.syncExemptionFlag < syncOperation.syncExemptionFlag)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001578 syncToRun = syncOperation;
Makoto Onuki75ad2492018-03-28 14:42:42 -07001579 inheritedSyncExemptionFlag =
1580 Math.max(inheritedSyncExemptionFlag, syncToRun.syncExemptionFlag);
Makoto Onuki61283ec2018-01-31 17:22:36 -08001581 }
1582 }
1583
1584 // Cancel all other duplicate syncs.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001585 for (SyncOperation op : pending) {
1586 if (op.isPeriodic) {
1587 continue;
1588 }
1589 if (op.key.equals(syncOperation.key)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001590 if (op != syncToRun) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001591 if (isLoggable) {
1592 Slog.v(TAG, "Cancelling duplicate sync " + op);
1593 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07001594 inheritedSyncExemptionFlag =
1595 Math.max(inheritedSyncExemptionFlag, op.syncExemptionFlag);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001596 cancelJob(op, "scheduleSyncOperationH-duplicate");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001597 }
1598 }
1599 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001600 if (syncToRun != syncOperation) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001601 // Don't schedule because a duplicate sync with earlier expected runtime exists.
1602 if (isLoggable) {
1603 Slog.v(TAG, "Not scheduling because a duplicate exists.");
1604 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001605
1606 // TODO Should we give the winning one SYNC_EXTRAS_APP_STANDBY_EXEMPTED
1607 // if the current one has it?
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001608 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001610
1611 // If any of the duplicates had exemption, we exempt the current one.
Makoto Onuki75ad2492018-03-28 14:42:42 -07001612 //
1613 if (inheritedSyncExemptionFlag > ContentResolver.SYNC_EXEMPTION_NONE) {
1614 syncOperation.syncExemptionFlag = inheritedSyncExemptionFlag;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001617
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001618 // Syncs that are re-scheduled shouldn't get a new job id.
1619 if (syncOperation.jobId == SyncOperation.NO_JOB_ID) {
1620 syncOperation.jobId = getUnusedJobIdH();
1621 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001622
1623 if (isLoggable) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001624 Slog.v(TAG, "scheduling sync operation " + syncOperation.toString());
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001625 }
1626
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001627 int priority = syncOperation.findPriority();
1628
1629 final int networkType = syncOperation.isNotAllowedOnMetered() ?
1630 JobInfo.NETWORK_TYPE_UNMETERED : JobInfo.NETWORK_TYPE_ANY;
1631
Makoto Onuki61283ec2018-01-31 17:22:36 -08001632 // Note this logic means when an exempted sync fails,
1633 // the back-off one will inherit it too, and will be exempted from app-standby.
Makoto Onuki75ad2492018-03-28 14:42:42 -07001634 final int jobFlags = syncOperation.isAppStandbyExempted()
Makoto Onuki61283ec2018-01-31 17:22:36 -08001635 ? JobInfo.FLAG_EXEMPT_FROM_APP_STANDBY : 0;
1636
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001637 JobInfo.Builder b = new JobInfo.Builder(syncOperation.jobId,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001638 new ComponentName(mContext, SyncJobService.class))
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001639 .setExtras(syncOperation.toJobInfoExtras())
1640 .setRequiredNetworkType(networkType)
1641 .setPersisted(true)
Makoto Onuki61283ec2018-01-31 17:22:36 -08001642 .setPriority(priority)
1643 .setFlags(jobFlags);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001644
1645 if (syncOperation.isPeriodic) {
1646 b.setPeriodic(syncOperation.periodMillis, syncOperation.flexMillis);
1647 } else {
1648 if (minDelay > 0) {
1649 b.setMinimumLatency(minDelay);
1650 }
1651 getSyncStorageEngine().markPending(syncOperation.target, true);
1652 }
1653
1654 if (syncOperation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)) {
1655 b.setRequiresCharging(true);
1656 }
1657
Makoto Onuki75ad2492018-03-28 14:42:42 -07001658 if (syncOperation.syncExemptionFlag
Makoto Onukid5f25d22018-05-22 16:02:17 -07001659 == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001660 DeviceIdleController.LocalService dic =
1661 LocalServices.getService(DeviceIdleController.LocalService.class);
1662 if (dic != null) {
1663 dic.addPowerSaveTempWhitelistApp(Process.SYSTEM_UID,
1664 syncOperation.owningPackage,
1665 mConstants.getKeyExemptionTempWhitelistDurationInSeconds() * 1000,
1666 UserHandle.getUserId(syncOperation.owningUid),
1667 /* sync=*/ false, "sync by top app");
1668 }
1669 }
1670
Makoto Onukid5f25d22018-05-22 16:02:17 -07001671 if (syncOperation.isAppStandbyExempted()) {
1672 final UsageStatsManagerInternal usmi = LocalServices.getService(
1673 UsageStatsManagerInternal.class);
1674 if (usmi != null) {
1675 usmi.reportExemptedSyncScheduled(syncOperation.owningPackage,
1676 UserHandle.getUserId(syncOperation.owningUid));
1677 }
1678 }
1679
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001680 getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
Shreyas Basargeeda34e42016-04-26 00:14:02 +01001681 syncOperation.target.userId, syncOperation.wakeLockName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 }
1683
1684 /**
Fred Quintanaac9385e2009-06-22 18:00:59 -07001685 * Remove scheduled sync operations.
Matthew Williams8ef22042013-07-26 12:56:39 -07001686 * @param info limit the removals to operations that match this target. The target can
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001687 * have null account/provider info to specify all accounts/providers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 */
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001689 public void clearScheduledSyncOperations(SyncStorageEngine.EndPoint info) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001690 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001691 for (SyncOperation op: ops) {
1692 if (!op.isPeriodic && op.target.matchesSpec(info)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001693 cancelJob(op, "clearScheduledSyncOperations");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001694 getSyncStorageEngine().markPending(op.target, false);
1695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001697 mSyncStorageEngine.setBackoff(info,
Fred Quintana918339a2010-10-05 14:00:39 -07001698 SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
1700
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001701 /**
1702 * Remove a specified sync, if it exists.
1703 * @param info Authority for which the sync is to be removed.
1704 * @param extras extras bundle to uniquely identify sync.
1705 */
1706 public void cancelScheduledSyncOperation(SyncStorageEngine.EndPoint info, Bundle extras) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001707 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001708 for (SyncOperation op: ops) {
1709 if (!op.isPeriodic && op.target.matchesSpec(info)
1710 && syncExtrasEquals(extras, op.extras, false)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001711 cancelJob(op, "cancelScheduledSyncOperation");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001712 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001713 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001714 setAuthorityPendingState(info);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001715 // Reset the back-off if there are no more syncs pending.
1716 if (!mSyncStorageEngine.isSyncPending(info)) {
1717 mSyncStorageEngine.setBackoff(info,
1718 SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
1719 }
1720 }
1721
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001722 private void maybeRescheduleSync(SyncResult syncResult, SyncOperation operation) {
1723 final boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 if (isLoggable) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001725 Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 }
1727
Fred Quintana53bd2522010-02-05 15:28:12 -08001728 // The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
1729 // request. Retries of the request will always honor the backoff, so clear the
1730 // flag in case we retry this request.
1731 if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
1732 operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
1733 }
1734
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01001735 if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
1736 && !syncResult.syncAlreadyInProgress) {
1737 // syncAlreadyInProgress flag is set by AbstractThreadedSyncAdapter. The sync adapter
1738 // has no way of knowing that a sync error occured. So we DO retry if the error is
1739 // syncAlreadyInProgress.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001740 if (isLoggable) {
1741 Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
1742 + operation);
1743 }
Fred Quintana918339a2010-10-05 14:00:39 -07001744 } else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)
1745 && !syncResult.syncAlreadyInProgress) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001746 // If this was an upward sync then schedule a two-way sync immediately.
Fred Quintana53bd2522010-02-05 15:28:12 -08001747 operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001748 if (isLoggable) {
1749 Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
1750 + "encountered an error: " + operation);
1751 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001752 scheduleSyncOperationH(operation);
Fred Quintana307da1a2010-01-21 14:24:20 -08001753 } else if (syncResult.tooManyRetries) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001754 // If this sync aborted because the internal sync loop retried too many times then
1755 // don't reschedule. Otherwise we risk getting into a retry loop.
1756 if (isLoggable) {
1757 Log.d(TAG, "not retrying sync operation because it retried too many times: "
1758 + operation);
1759 }
Fred Quintanaaa7edda2009-12-03 14:18:58 -08001760 } else if (syncResult.madeSomeProgress()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001761 // If the operation succeeded to some extent then retry immediately.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 if (isLoggable) {
Fred Quintana307da1a2010-01-21 14:24:20 -08001763 Log.d(TAG, "retrying sync operation because even though it had an error "
1764 + "it achieved some success");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00001766 scheduleSyncOperationH(operation);
Fred Quintana8570f742010-02-18 10:32:54 -08001767 } else if (syncResult.syncAlreadyInProgress) {
1768 if (isLoggable) {
1769 Log.d(TAG, "retrying sync operation that failed because there was already a "
1770 + "sync in progress: " + operation);
1771 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001772 scheduleSyncOperationH(operation, DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 } else if (syncResult.hasSoftError()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001774 // If this was a two-way sync then retry soft errors with an exponential backoff.
Fred Quintana307da1a2010-01-21 14:24:20 -08001775 if (isLoggable) {
1776 Log.d(TAG, "retrying sync operation because it encountered a soft error: "
1777 + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001779 scheduleSyncOperationH(operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 } else {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001781 // Otherwise do not reschedule.
Fred Quintana307da1a2010-01-21 14:24:20 -08001782 Log.d(TAG, "not retrying sync operation because the error is a hard error: "
1783 + operation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 }
1785 }
1786
Jeff Sharkey9d8a1042015-12-03 17:56:20 -07001787 private void onUserUnlocked(int userId) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001788 // Make sure that accounts we're about to use are valid.
Jeff Sharkey6eb96202012-10-10 13:13:54 -07001789 AccountManagerService.getSingleton().validateAccounts(userId);
1790
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001791 mSyncAdapters.invalidateCache(userId);
1792
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001793 EndPoint target = new EndPoint(null, null, userId);
1794 updateRunningAccounts(target);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001795
Makoto Onuki61283ec2018-01-31 17:22:36 -08001796 // Schedule sync for any accounts under started user, but only the NOT_INITIALIZED adapters.
Svetoslavf3f02ac2015-09-08 14:36:35 -07001797 final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId,
1798 mContext.getOpPackageName());
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001799 for (Account account : accounts) {
Alon Albert57286f92012-10-09 14:21:38 -07001800 scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
Makoto Onuki75ad2492018-03-28 14:42:42 -07001801 AuthorityInfo.NOT_INITIALIZED, ContentResolver.SYNC_EXEMPTION_NONE);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001802 }
Alon Albert8e285552012-09-17 15:05:27 -07001803 }
Amith Yamasani13593602012-03-22 16:16:17 -07001804
Amith Yamasaniad2e4bf2016-04-26 14:35:54 -07001805 private void onUserStopped(int userId) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001806 updateRunningAccounts(null /* Don't sync any target */);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001807
1808 cancelActiveSync(
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001809 new SyncStorageEngine.EndPoint(
1810 null /* any account */,
1811 null /* any authority */,
1812 userId),
Makoto Onukia9dca242017-06-21 17:06:49 -07001813 null /* any sync. */,
1814 "onUserStopped"
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001815 );
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001816 }
1817
1818 private void onUserRemoved(int userId) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07001819 mLogger.log("onUserRemoved: u", userId);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001820 updateRunningAccounts(null /* Don't sync any target */);
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001821
Amith Yamasani13593602012-03-22 16:16:17 -07001822 // Clean up the storage engine database
1823 mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00001824 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001825 for (SyncOperation op: ops) {
1826 if (op.target.userId == userId) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07001827 cancelJob(op, "user removed u" + userId);
Dianne Hackbornbef28fe2015-10-29 17:57:11 -07001828 }
1829 }
1830 }
1831
Amith Yamasani96a0fd652015-04-10 16:16:30 -07001832 /**
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001833 * Construct intent used to bind to an adapter.
1834 *
1835 * @param context Context to create intent for
1836 * @param syncAdapterComponent The adapter description
1837 * @param userId The user the adapter belongs to
1838 *
1839 * @return The intent required to bind to the adapter
1840 */
1841 static @NonNull Intent getAdapterBindIntent(@NonNull Context context,
1842 @NonNull ComponentName syncAdapterComponent, @UserIdInt int userId) {
1843 final Intent intent = new Intent();
1844 intent.setAction("android.content.SyncAdapter");
1845 intent.setComponent(syncAdapterComponent);
1846 intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
1847 com.android.internal.R.string.sync_binding_label);
1848 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0,
1849 new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId)));
1850
1851 return intent;
1852 }
1853
1854 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 * @hide
1856 */
Alon Alberteca75112010-12-08 15:02:33 -08001857 class ActiveSyncContext extends ISyncContext.Stub
1858 implements ServiceConnection, IBinder.DeathRecipient {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 final SyncOperation mSyncOperation;
1860 final long mHistoryRowId;
Fred Quintana718d8a22009-04-29 17:53:20 -07001861 ISyncAdapter mSyncAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 final long mStartTime;
1863 long mTimeoutStartTime;
Fred Quintana3ec47302010-03-10 10:08:31 -08001864 boolean mBound;
Fred Quintana918339a2010-10-05 14:00:39 -07001865 final PowerManager.WakeLock mSyncWakeLock;
1866 final int mSyncAdapterUid;
1867 SyncInfo mSyncInfo;
Alon Alberteca75112010-12-08 15:02:33 -08001868 boolean mIsLinkedToDeath = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001869 String mEventName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870
Matthew Williams1967c8d2015-06-19 19:03:13 -07001871 /** Total bytes transferred, counted at {@link #mLastPolledTimeElapsed} */
1872 long mBytesTransferredAtLastPoll;
1873 /**
1874 * Last point in {@link SystemClock#elapsedRealtime()} at which we checked the # of bytes
1875 * transferred to/fro by this adapter.
1876 */
1877 long mLastPolledTimeElapsed;
1878
Fred Quintana918339a2010-10-05 14:00:39 -07001879 /**
1880 * Create an ActiveSyncContext for an impending sync and grab the wakelock for that
1881 * sync adapter. Since this grabs the wakelock you need to be sure to call
1882 * close() when you are done with this ActiveSyncContext, whether the sync succeeded
1883 * or not.
1884 * @param syncOperation the SyncOperation we are about to sync
1885 * @param historyRowId the row in which to record the history info for this sync
1886 * @param syncAdapterUid the UID of the application that contains the sync adapter
1887 * for this sync. This is used to attribute the wakelock hold to that application.
1888 */
1889 public ActiveSyncContext(SyncOperation syncOperation, long historyRowId,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00001890 int syncAdapterUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 super();
Fred Quintana918339a2010-10-05 14:00:39 -07001892 mSyncAdapterUid = syncAdapterUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893 mSyncOperation = syncOperation;
1894 mHistoryRowId = historyRowId;
Fred Quintana718d8a22009-04-29 17:53:20 -07001895 mSyncAdapter = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 mStartTime = SystemClock.elapsedRealtime();
1897 mTimeoutStartTime = mStartTime;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001898 mSyncWakeLock = mSyncHandler.getSyncWakeLock(mSyncOperation);
Fred Quintana918339a2010-10-05 14:00:39 -07001899 mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
1900 mSyncWakeLock.acquire();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001901 }
1902
1903 public void sendHeartbeat() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001904 // Heartbeats are no longer used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 }
1906
1907 public void onFinished(SyncResult result) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001908 if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "onFinished: " + this);
1909 // Include "this" in the message so that the handler can ignore it if this
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 // ActiveSyncContext is no longer the mActiveSyncContext at message handling
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001911 // time.
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001912 mLogger.log("onFinished result=", result, " endpoint=",
1913 (mSyncOperation == null ? "null" : mSyncOperation.target));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001914 sendSyncFinishedOrCanceledMessage(this, result);
1915 }
1916
1917 public void toString(StringBuilder sb) {
1918 sb.append("startTime ").append(mStartTime)
1919 .append(", mTimeoutStartTime ").append(mTimeoutStartTime)
1920 .append(", mHistoryRowId ").append(mHistoryRowId)
1921 .append(", syncOperation ").append(mSyncOperation);
1922 }
1923
Fred Quintana718d8a22009-04-29 17:53:20 -07001924 public void onServiceConnected(ComponentName name, IBinder service) {
1925 Message msg = mSyncHandler.obtainMessage();
1926 msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001927 msg.obj = new ServiceConnectionData(this, service);
Fred Quintana718d8a22009-04-29 17:53:20 -07001928 mSyncHandler.sendMessage(msg);
1929 }
1930
1931 public void onServiceDisconnected(ComponentName name) {
1932 Message msg = mSyncHandler.obtainMessage();
1933 msg.what = SyncHandler.MESSAGE_SERVICE_DISCONNECTED;
1934 msg.obj = new ServiceConnectionData(this, null);
1935 mSyncHandler.sendMessage(msg);
1936 }
1937
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001938 boolean bindToSyncAdapter(ComponentName serviceComponent, int userId) {
Fred Quintana718d8a22009-04-29 17:53:20 -07001939 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001940 Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
Fred Quintana718d8a22009-04-29 17:53:20 -07001941 }
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001942 Intent intent = getAdapterBindIntent(mContext, serviceComponent, userId);
1943
Fred Quintana3ec47302010-03-10 10:08:31 -08001944 mBound = true;
Amith Yamasani27b89e62013-01-16 12:30:11 -08001945 final boolean bindResult = mContext.bindServiceAsUser(intent, this,
Philip P. Moltmann486b2412018-01-03 11:29:01 -08001946 SYNC_ADAPTER_CONNECTION_FLAGS, new UserHandle(mSyncOperation.target.userId));
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001947 mLogger.log("bindService() returned=", mBound, " for ", this);
Fred Quintana3ec47302010-03-10 10:08:31 -08001948 if (!bindResult) {
1949 mBound = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001950 } else {
1951 try {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08001952 mEventName = mSyncOperation.wakeLockName();
Dianne Hackbornfdb19562014-07-11 16:03:36 -07001953 mBatteryStats.noteSyncStart(mEventName, mSyncAdapterUid);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001954 } catch (RemoteException e) {
1955 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001956 }
1957 return bindResult;
Fred Quintana718d8a22009-04-29 17:53:20 -07001958 }
1959
Fred Quintana918339a2010-10-05 14:00:39 -07001960 /**
1961 * Performs the required cleanup, which is the releasing of the wakelock and
1962 * unbinding from the sync adapter (if actually bound).
1963 */
Fred Quintana3ec47302010-03-10 10:08:31 -08001964 protected void close() {
Fred Quintana718d8a22009-04-29 17:53:20 -07001965 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1966 Log.d(TAG, "unBindFromSyncAdapter: connection " + this);
1967 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001968 if (mBound) {
1969 mBound = false;
Makoto Onuki6a6ae042017-07-20 13:30:12 -07001970 mLogger.log("unbindService for ", this);
Fred Quintana3ec47302010-03-10 10:08:31 -08001971 mContext.unbindService(this);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001972 try {
Dianne Hackbornfdb19562014-07-11 16:03:36 -07001973 mBatteryStats.noteSyncFinish(mEventName, mSyncAdapterUid);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -08001974 } catch (RemoteException e) {
1975 }
Fred Quintana3ec47302010-03-10 10:08:31 -08001976 }
Fred Quintana918339a2010-10-05 14:00:39 -07001977 mSyncWakeLock.release();
Dianne Hackbornc24ab862011-10-18 15:55:03 -07001978 mSyncWakeLock.setWorkSource(null);
Fred Quintana718d8a22009-04-29 17:53:20 -07001979 }
1980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 public String toString() {
1982 StringBuilder sb = new StringBuilder();
1983 toString(sb);
1984 return sb.toString();
1985 }
Alon Alberteca75112010-12-08 15:02:33 -08001986
1987 @Override
1988 public void binderDied() {
1989 sendSyncFinishedOrCanceledMessage(this, null);
1990 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 }
1992
Makoto Onukia9dca242017-06-21 17:06:49 -07001993 protected void dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07001994 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
Makoto Onuki75ad2492018-03-28 14:42:42 -07001995
1996 final SyncAdapterStateFetcher buckets = new SyncAdapterStateFetcher();
1997
1998 dumpSyncState(ipw, buckets);
Makoto Onukiaad2b512018-02-07 09:31:46 -08001999 mConstants.dump(pw, "");
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002000 dumpSyncAdapters(ipw);
Makoto Onukia9dca242017-06-21 17:06:49 -07002001
2002 if (dumpAll) {
2003 ipw.println("Detailed Sync History");
2004 mLogger.dumpAll(pw);
2005 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002006 }
2007
Dianne Hackborn231cc602009-04-27 17:10:36 -07002008 static String formatTime(long time) {
Makoto Onukif74cf942018-04-16 17:04:58 -07002009 if (time == 0) {
2010 return "N/A";
2011 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07002012 Time tobj = new Time();
2013 tobj.set(time);
2014 return tobj.format("%Y-%m-%d %H:%M:%S");
2015 }
Doug Zongker44f57472009-09-20 15:52:43 -07002016
Makoto Onuki15e7a252017-06-08 17:12:05 -07002017 private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
2018 int res = Integer.compare(op1.target.userId, op2.target.userId);
2019 if (res != 0) return res;
2020
2021 final Comparator<String> stringComparator = String.CASE_INSENSITIVE_ORDER;
2022
2023 res = stringComparator.compare(op1.target.account.type, op2.target.account.type);
2024 if (res != 0) return res;
2025
2026 res = stringComparator.compare(op1.target.account.name, op2.target.account.name);
2027 if (res != 0) return res;
2028
2029 res = stringComparator.compare(op1.target.provider, op2.target.provider);
2030 if (res != 0) return res;
2031
2032 res = Integer.compare(op1.reason, op2.reason);
2033 if (res != 0) return res;
2034
2035 res = Long.compare(op1.periodMillis, op2.periodMillis);
2036 if (res != 0) return res;
2037
2038 res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
2039 if (res != 0) return res;
2040
2041 res = Long.compare(op1.jobId, op2.jobId);
2042 if (res != 0) return res;
2043
2044 return 0;
2045 };
2046
2047 private final static Comparator<SyncOperation> sOpRuntimeComparator = (op1, op2) -> {
2048 int res = Long.compare(op1.expectedRuntime, op2.expectedRuntime);
2049 if (res != 0) return res;
2050
2051 return sOpDumpComparator.compare(op1, op2);
2052 };
2053
2054 private static <T> int countIf(Collection<T> col, Predicate<T> p) {
2055 int ret = 0;
2056 for (T item : col) {
2057 if (p.test(item)) ret++;
2058 }
2059 return ret;
2060 }
2061
Makoto Onuki75ad2492018-03-28 14:42:42 -07002062 protected void dumpPendingSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00002063 List<SyncOperation> pendingSyncs = getAllPendingSyncs();
Makoto Onuki15e7a252017-06-08 17:12:05 -07002064
2065 pw.print("Pending Syncs: ");
2066 pw.println(countIf(pendingSyncs, op -> !op.isPeriodic));
2067
2068 Collections.sort(pendingSyncs, sOpRuntimeComparator);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002069 int count = 0;
2070 for (SyncOperation op: pendingSyncs) {
2071 if (!op.isPeriodic) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07002072 pw.println(op.dump(null, false, buckets));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002073 count++;
2074 }
2075 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002076 pw.println();
2077 }
2078
Makoto Onuki75ad2492018-03-28 14:42:42 -07002079 protected void dumpPeriodicSyncs(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00002080 List<SyncOperation> pendingSyncs = getAllPendingSyncs();
Makoto Onuki15e7a252017-06-08 17:12:05 -07002081
2082 pw.print("Periodic Syncs: ");
2083 pw.println(countIf(pendingSyncs, op -> op.isPeriodic));
2084
2085 Collections.sort(pendingSyncs, sOpDumpComparator);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002086 int count = 0;
2087 for (SyncOperation op: pendingSyncs) {
2088 if (op.isPeriodic) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07002089 pw.println(op.dump(null, false, buckets));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002090 count++;
2091 }
2092 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002093 pw.println();
2094 }
2095
Makoto Onuki15e7a252017-06-08 17:12:05 -07002096 /**
2097 * Similar to {@link android.util.TimeUtils#formatDuration}, but it's more suitable and concise
2098 * for the sync manager dumpsys. (Don't add the leading + sign, don't show milliseconds.)
2099 */
2100 public static StringBuilder formatDurationHMS(StringBuilder sb, long duration) {
2101 duration /= 1000;
2102 if (duration < 0) {
2103 sb.append('-');
2104 duration = -duration;
2105 }
2106 final long seconds = duration % 60;
2107 duration /= 60;
2108
2109 final long minutes = duration % 60;
2110 duration /= 60;
2111
2112 final long hours = duration % 24;
2113 duration /= 24;
2114
2115 final long days = duration;
2116
2117 boolean print = false;
2118 if (days > 0) {
2119 sb.append(days);
2120 sb.append('d');
2121 print = true;
2122 }
2123 print = printTwoDigitNumber(sb, hours, 'h', print);
2124 print = printTwoDigitNumber(sb, minutes, 'm', print);
2125 print = printTwoDigitNumber(sb, seconds, 's', print);
2126 if (!print) {
2127 sb.append("0s");
2128 }
2129
2130 return sb;
2131 }
2132
2133 private static boolean printTwoDigitNumber(StringBuilder sb, long value, char unit,
2134 boolean always) {
2135 if (!always && (value == 0)) {
2136 return false;
2137 }
2138 if (always && (value < 10)) {
2139 sb.append('0');
2140 }
2141 sb.append(value);
2142 sb.append(unit);
2143 return true;
2144 }
2145
Makoto Onuki75ad2492018-03-28 14:42:42 -07002146 protected void dumpSyncState(PrintWriter pw, SyncAdapterStateFetcher buckets) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07002147 final StringBuilder sb = new StringBuilder();
2148
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002149 pw.print("Data connected: "); pw.println(mDataConnectionIsConnected);
2150 pw.print("Battery saver: ");
2151 pw.println((mPowerManager != null) && mPowerManager.isPowerSaveMode());
2152
2153 pw.print("Background network restriction: ");
2154 {
2155 final ConnectivityManager cm = getConnectivityManager();
2156 final int status = (cm == null) ? -1 : cm.getRestrictBackgroundStatus();
2157 switch (status) {
2158 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
2159 pw.println(" disabled");
2160 break;
2161 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
2162 pw.println(" whitelisted");
2163 break;
2164 case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
2165 pw.println(" enabled");
2166 break;
2167 default:
2168 pw.print("Unknown(");
2169 pw.print(status);
2170 pw.println(")");
2171 break;
2172 }
2173 }
2174
2175 pw.print("Auto sync: ");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002176 List<UserInfo> users = getAllUsers();
2177 if (users != null) {
2178 for (UserInfo user : users) {
2179 pw.print("u" + user.id + "="
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002180 + mSyncStorageEngine.getMasterSyncAutomatically(user.id) + " ");
Amith Yamasani04e0d262012-02-14 11:50:53 -08002181 }
2182 pw.println();
2183 }
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002184 pw.print("Memory low: "); pw.println(mStorageIsLow);
2185 pw.print("Device idle: "); pw.println(mDeviceIsIdle);
2186 pw.print("Reported active: "); pw.println(mReportedSyncActive);
Makoto Onuki94986212018-04-11 16:24:46 -07002187 pw.print("Clock valid: "); pw.println(mSyncStorageEngine.isClockValid());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188
Jeff Sharkey6eb96202012-10-10 13:13:54 -07002189 final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
Amith Yamasani04e0d262012-02-14 11:50:53 -08002190
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002191 pw.print("Accounts: ");
Fred Quintana53bd2522010-02-05 15:28:12 -08002192 if (accounts != INITIAL_ACCOUNTS_ARRAY) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07002193 pw.println(accounts.length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 } else {
Fred Quintana53bd2522010-02-05 15:28:12 -08002195 pw.println("not known yet");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 final long now = SystemClock.elapsedRealtime();
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002198 pw.print("Now: "); pw.print(now);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002199 pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002200
2201 sb.setLength(0);
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002202 pw.print("Uptime: "); pw.print(formatDurationHMS(sb, now));
Makoto Onuki15e7a252017-06-08 17:12:05 -07002203 pw.println();
Makoto Onuki1ba9ebc2018-02-15 10:39:26 -08002204 pw.print("Time spent syncing: ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002205
2206 sb.setLength(0);
2207 pw.print(formatDurationHMS(sb,
2208 mSyncHandler.mSyncTimeTracker.timeSpentSyncing()));
2209 pw.print(", sync ");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002210 pw.print(mSyncHandler.mSyncTimeTracker.mLastWasSyncing ? "" : "not ");
2211 pw.println("in progress");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212
Fred Quintana918339a2010-10-05 14:00:39 -07002213 pw.println();
2214 pw.println("Active Syncs: " + mActiveSyncContexts.size());
Alon Albert57286f92012-10-09 14:21:38 -07002215 final PackageManager pm = mContext.getPackageManager();
Fred Quintana918339a2010-10-05 14:00:39 -07002216 for (SyncManager.ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07002217 final long durationInSeconds = (now - activeSyncContext.mStartTime);
Fred Quintana918339a2010-10-05 14:00:39 -07002218 pw.print(" ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002219 sb.setLength(0);
2220 pw.print(formatDurationHMS(sb, durationInSeconds));
Fred Quintana918339a2010-10-05 14:00:39 -07002221 pw.print(" - ");
Makoto Onuki75ad2492018-03-28 14:42:42 -07002222 pw.print(activeSyncContext.mSyncOperation.dump(pm, false, buckets));
Fred Quintana918339a2010-10-05 14:00:39 -07002223 pw.println();
2224 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002225 pw.println();
2226
Makoto Onuki75ad2492018-03-28 14:42:42 -07002227 dumpPendingSyncs(pw, buckets);
2228 dumpPeriodicSyncs(pw, buckets);
Fred Quintana918339a2010-10-05 14:00:39 -07002229
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002230 // Join the installed sync adapter with the accounts list and emit for everything.
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002231 pw.println("Sync Status");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002232
2233 final ArrayList<Pair<EndPoint, SyncStatusInfo>> statuses = new ArrayList<>();
2234
Makoto Onuki94986212018-04-11 16:24:46 -07002235 mSyncStorageEngine.resetTodayStats(/* force=*/ false);
2236
Amith Yamasani04e0d262012-02-14 11:50:53 -08002237 for (AccountAndUser account : accounts) {
Alon Albert57286f92012-10-09 14:21:38 -07002238 pw.printf("Account %s u%d %s\n",
2239 account.account.name, account.userId, account.account.type);
2240
2241 pw.println("=======================================================================");
Makoto Onuki94986212018-04-11 16:24:46 -07002242 final PrintTable table = new PrintTable(16);
Alon Albert57286f92012-10-09 14:21:38 -07002243 table.set(0, 0,
2244 "Authority", // 0
2245 "Syncable", // 1
2246 "Enabled", // 2
Makoto Onuki94986212018-04-11 16:24:46 -07002247
2248 "Stats", // 3 "Total", "Today" or "Yesterday".
2249
2250 "Loc", // 4 # of syncs with local sources. (including failures/cancels. )
2251 "Poll", // 5 "poll" syncs.
2252 "Per", // 6 Periodic syncs.
2253 "Feed", // 7 Syncs with a "feed" extra. (subscribedfeeds?)
2254 "User", // 8 User-initiated
2255 "Othr", // 9 Other sources.
2256
2257 "Tot", // 10 Total syncs (including failures / cancels)
2258 "Fail", // 11 (Failure)
2259 "Can", // 12 (Cancel)
2260
2261 "Time", // 13 Total time
2262 "Last Sync", // 14
2263 "Backoff" // 15
Alon Albert57286f92012-10-09 14:21:38 -07002264 );
2265
2266 final List<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> sorted =
2267 Lists.newArrayList();
2268 sorted.addAll(mSyncAdapters.getAllServices(account.userId));
2269 Collections.sort(sorted,
2270 new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002271 @Override
2272 public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00002273 RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002274 return lhs.type.authority.compareTo(rhs.type.authority);
2275 }
2276 });
Alon Albert57286f92012-10-09 14:21:38 -07002277 for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType : sorted) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08002278 if (!syncAdapterType.type.accountType.equals(account.account.type)) {
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002279 continue;
2280 }
Alon Albert57286f92012-10-09 14:21:38 -07002281 int row = table.getNumRows();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002282 Pair<AuthorityInfo, SyncStatusInfo> syncAuthoritySyncStatus =
Georgi Nikolovdbe846b2013-06-25 14:09:56 -07002283 mSyncStorageEngine.getCopyOfAuthorityWithSyncStatus(
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002284 new SyncStorageEngine.EndPoint(
2285 account.account,
2286 syncAdapterType.type.authority,
2287 account.userId));
Georgi Nikolovdbe846b2013-06-25 14:09:56 -07002288 SyncStorageEngine.AuthorityInfo settings = syncAuthoritySyncStatus.first;
2289 SyncStatusInfo status = syncAuthoritySyncStatus.second;
Makoto Onuki15e7a252017-06-08 17:12:05 -07002290 statuses.add(Pair.create(settings.target, status));
Matthew Williams8ef22042013-07-26 12:56:39 -07002291 String authority = settings.target.provider;
Alon Albert57286f92012-10-09 14:21:38 -07002292 if (authority.length() > 50) {
2293 authority = authority.substring(authority.length() - 50);
2294 }
2295 table.set(row, 0, authority, settings.syncable, settings.enabled);
Makoto Onuki15e7a252017-06-08 17:12:05 -07002296
Makoto Onuki94986212018-04-11 16:24:46 -07002297 QuadConsumer<String, Stats, Function<Integer, String>, Integer> c =
2298 (label, stats, filter, r) -> {
2299 sb.setLength(0);
2300 table.set(r, 3,
2301 label,
2302 filter.apply(stats.numSourceLocal),
2303 filter.apply(stats.numSourcePoll),
2304 filter.apply(stats.numSourcePeriodic),
2305 filter.apply(stats.numSourceFeed),
2306 filter.apply(stats.numSourceUser),
2307 filter.apply(stats.numSourceOther),
2308 filter.apply(stats.numSyncs),
2309 filter.apply(stats.numFailures),
2310 filter.apply(stats.numCancels),
2311 formatDurationHMS(sb, stats.totalElapsedTime));
2312 };
2313 c.accept("Total", status.totalStats, (i) -> Integer.toString(i), row);
2314 c.accept("Today", status.todayStats, this::zeroToEmpty, row + 1);
2315 c.accept("Yestr", status.yesterdayStats, this::zeroToEmpty, row + 2);
2316
2317 final int LAST_SYNC = 14;
2318 final int BACKOFF = LAST_SYNC + 1;
Alon Albert57286f92012-10-09 14:21:38 -07002319
Alon Albert57286f92012-10-09 14:21:38 -07002320 int row1 = row;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002321 if (settings.delayUntil > now) {
Makoto Onuki94986212018-04-11 16:24:46 -07002322 table.set(row1++, BACKOFF, "D: " + (settings.delayUntil - now) / 1000);
Alon Albert57286f92012-10-09 14:21:38 -07002323 if (settings.backoffTime > now) {
Makoto Onuki94986212018-04-11 16:24:46 -07002324 table.set(row1++, BACKOFF, "B: " + (settings.backoffTime - now) / 1000);
2325 table.set(row1++, BACKOFF, settings.backoffDelay / 1000);
Alon Albert57286f92012-10-09 14:21:38 -07002326 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002327 }
Alon Albert57286f92012-10-09 14:21:38 -07002328
Makoto Onuki010291d2017-06-06 16:32:47 -07002329 row1 = row;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002330 if (status.lastSuccessTime != 0) {
Makoto Onuki94986212018-04-11 16:24:46 -07002331 table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastSuccessSource]
Alon Albert57286f92012-10-09 14:21:38 -07002332 + " " + "SUCCESS");
Makoto Onuki94986212018-04-11 16:24:46 -07002333 table.set(row1++, LAST_SYNC, formatTime(status.lastSuccessTime));
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08002334 }
2335 if (status.lastFailureTime != 0) {
Makoto Onuki94986212018-04-11 16:24:46 -07002336 table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastFailureSource]
Alon Albert57286f92012-10-09 14:21:38 -07002337 + " " + "FAILURE");
Makoto Onuki94986212018-04-11 16:24:46 -07002338 table.set(row1++, LAST_SYNC, formatTime(status.lastFailureTime));
Alon Albert57286f92012-10-09 14:21:38 -07002339 //noinspection UnusedAssignment
Makoto Onuki94986212018-04-11 16:24:46 -07002340 table.set(row1++, LAST_SYNC, status.lastFailureMesg);
Dianne Hackborn231cc602009-04-27 17:10:36 -07002341 }
2342 }
Alon Albert57286f92012-10-09 14:21:38 -07002343 table.writeTo(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002344 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002345
2346 dumpSyncHistory(pw);
2347
2348 pw.println();
2349 pw.println("Per Adapter History");
Makoto Onuki94986212018-04-11 16:24:46 -07002350 pw.println("(SERVER is now split up to FEED and OTHER)");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002351
2352 for (int i = 0; i < statuses.size(); i++) {
2353 final Pair<EndPoint, SyncStatusInfo> event = statuses.get(i);
2354
2355 pw.print(" ");
2356 pw.print(event.first.account.name);
2357 pw.print('/');
2358 pw.print(event.first.account.type);
2359 pw.print(" u");
2360 pw.print(event.first.userId);
2361 pw.print(" [");
2362 pw.print(event.first.provider);
2363 pw.print("]");
2364 pw.println();
2365
Makoto Onukif74cf942018-04-16 17:04:58 -07002366 pw.println(" Per source last syncs:");
2367 for (int j = 0; j < SyncStorageEngine.SOURCES.length; j++) {
2368 pw.print(" ");
2369 pw.print(String.format("%8s", SyncStorageEngine.SOURCES[j]));
2370 pw.print(" Success: ");
2371 pw.print(formatTime(event.second.perSourceLastSuccessTimes[j]));
2372
2373 pw.print(" Failure: ");
2374 pw.println(formatTime(event.second.perSourceLastFailureTimes[j]));
2375 }
2376
2377 pw.println(" Last syncs:");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002378 for (int j = 0; j < event.second.getEventCount(); j++) {
Makoto Onukif74cf942018-04-16 17:04:58 -07002379 pw.print(" ");
Makoto Onuki15e7a252017-06-08 17:12:05 -07002380 pw.print(formatTime(event.second.getEventTime(j)));
2381 pw.print(' ');
2382 pw.print(event.second.getEvent(j));
2383 pw.println();
2384 }
Makoto Onukif74cf942018-04-16 17:04:58 -07002385 if (event.second.getEventCount() == 0) {
2386 pw.println(" N/A");
2387 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07002388 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002389 }
2390
Makoto Onuki94986212018-04-11 16:24:46 -07002391 private String zeroToEmpty(int value) {
2392 return (value != 0) ? Integer.toString(value) : "";
2393 }
2394
Dianne Hackborn231cc602009-04-27 17:10:36 -07002395 private void dumpTimeSec(PrintWriter pw, long time) {
2396 pw.print(time/1000); pw.print('.'); pw.print((time/100)%10);
2397 pw.print('s');
2398 }
Doug Zongker44f57472009-09-20 15:52:43 -07002399
Dianne Hackborn231cc602009-04-27 17:10:36 -07002400 private void dumpDayStatistic(PrintWriter pw, SyncStorageEngine.DayStats ds) {
2401 pw.print("Success ("); pw.print(ds.successCount);
2402 if (ds.successCount > 0) {
2403 pw.print(" for "); dumpTimeSec(pw, ds.successTime);
2404 pw.print(" avg="); dumpTimeSec(pw, ds.successTime/ds.successCount);
2405 }
2406 pw.print(") Failure ("); pw.print(ds.failureCount);
2407 if (ds.failureCount > 0) {
2408 pw.print(" for "); dumpTimeSec(pw, ds.failureTime);
2409 pw.print(" avg="); dumpTimeSec(pw, ds.failureTime/ds.failureCount);
2410 }
2411 pw.println(")");
2412 }
Doug Zongker44f57472009-09-20 15:52:43 -07002413
Alon Alberte0bde332011-09-22 14:26:16 -07002414 protected void dumpSyncHistory(PrintWriter pw) {
2415 dumpRecentHistory(pw);
2416 dumpDayStatistics(pw);
2417 }
2418
2419 private void dumpRecentHistory(PrintWriter pw) {
2420 final ArrayList<SyncStorageEngine.SyncHistoryItem> items
2421 = mSyncStorageEngine.getSyncHistory();
2422 if (items != null && items.size() > 0) {
2423 final Map<String, AuthoritySyncStats> authorityMap = Maps.newHashMap();
2424 long totalElapsedTime = 0;
2425 long totalTimes = 0;
2426 final int N = items.size();
2427
2428 int maxAuthority = 0;
2429 int maxAccount = 0;
2430 for (SyncStorageEngine.SyncHistoryItem item : items) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002431 SyncStorageEngine.AuthorityInfo authorityInfo
Alon Alberte0bde332011-09-22 14:26:16 -07002432 = mSyncStorageEngine.getAuthority(item.authorityId);
2433 final String authorityName;
2434 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002435 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002436 authorityName = authorityInfo.target.provider;
2437 accountKey = authorityInfo.target.account.name + "/"
2438 + authorityInfo.target.account.type
2439 + " u" + authorityInfo.target.userId;
Alon Alberte0bde332011-09-22 14:26:16 -07002440 } else {
2441 authorityName = "Unknown";
2442 accountKey = "Unknown";
2443 }
2444
2445 int length = authorityName.length();
2446 if (length > maxAuthority) {
2447 maxAuthority = length;
2448 }
2449 length = accountKey.length();
2450 if (length > maxAccount) {
2451 maxAccount = length;
2452 }
2453
2454 final long elapsedTime = item.elapsedTime;
2455 totalElapsedTime += elapsedTime;
2456 totalTimes++;
2457 AuthoritySyncStats authoritySyncStats = authorityMap.get(authorityName);
2458 if (authoritySyncStats == null) {
2459 authoritySyncStats = new AuthoritySyncStats(authorityName);
2460 authorityMap.put(authorityName, authoritySyncStats);
2461 }
2462 authoritySyncStats.elapsedTime += elapsedTime;
2463 authoritySyncStats.times++;
2464 final Map<String, AccountSyncStats> accountMap = authoritySyncStats.accountMap;
2465 AccountSyncStats accountSyncStats = accountMap.get(accountKey);
2466 if (accountSyncStats == null) {
2467 accountSyncStats = new AccountSyncStats(accountKey);
2468 accountMap.put(accountKey, accountSyncStats);
2469 }
2470 accountSyncStats.elapsedTime += elapsedTime;
2471 accountSyncStats.times++;
2472
2473 }
2474
Alon Albert27096822012-01-11 18:06:41 -08002475 if (totalElapsedTime > 0) {
2476 pw.println();
2477 pw.printf("Detailed Statistics (Recent history): "
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002478 + "%d (# of times) %ds (sync time)\n",
Alon Albert27096822012-01-11 18:06:41 -08002479 totalTimes, totalElapsedTime / 1000);
Alon Alberte0bde332011-09-22 14:26:16 -07002480
Alon Albert27096822012-01-11 18:06:41 -08002481 final List<AuthoritySyncStats> sortedAuthorities =
2482 new ArrayList<AuthoritySyncStats>(authorityMap.values());
2483 Collections.sort(sortedAuthorities, new Comparator<AuthoritySyncStats>() {
Alon Albertbf976ba2011-10-03 13:06:43 -07002484 @Override
Alon Albert27096822012-01-11 18:06:41 -08002485 public int compare(AuthoritySyncStats lhs, AuthoritySyncStats rhs) {
Alon Albertbf976ba2011-10-03 13:06:43 -07002486 // reverse order
2487 int compare = Integer.compare(rhs.times, lhs.times);
2488 if (compare == 0) {
2489 compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
Alon Alberte0bde332011-09-22 14:26:16 -07002490 }
Alon Albertbf976ba2011-10-03 13:06:43 -07002491 return compare;
Alon Alberte0bde332011-09-22 14:26:16 -07002492 }
Alon Albertbf976ba2011-10-03 13:06:43 -07002493 });
Alon Albert27096822012-01-11 18:06:41 -08002494
2495 final int maxLength = Math.max(maxAuthority, maxAccount + 3);
2496 final int padLength = 2 + 2 + maxLength + 2 + 10 + 11;
2497 final char chars[] = new char[padLength];
2498 Arrays.fill(chars, '-');
2499 final String separator = new String(chars);
2500
2501 final String authorityFormat =
2502 String.format(" %%-%ds: %%-9s %%-11s\n", maxLength + 2);
2503 final String accountFormat =
2504 String.format(" %%-%ds: %%-9s %%-11s\n", maxLength);
2505
2506 pw.println(separator);
2507 for (AuthoritySyncStats authoritySyncStats : sortedAuthorities) {
2508 String name = authoritySyncStats.name;
2509 long elapsedTime;
2510 int times;
2511 String timeStr;
2512 String timesStr;
2513
2514 elapsedTime = authoritySyncStats.elapsedTime;
2515 times = authoritySyncStats.times;
Alon Albertbf976ba2011-10-03 13:06:43 -07002516 timeStr = String.format("%ds/%d%%",
2517 elapsedTime / 1000,
2518 elapsedTime * 100 / totalElapsedTime);
2519 timesStr = String.format("%d/%d%%",
2520 times,
2521 times * 100 / totalTimes);
Alon Albert27096822012-01-11 18:06:41 -08002522 pw.printf(authorityFormat, name, timesStr, timeStr);
2523
2524 final List<AccountSyncStats> sortedAccounts =
2525 new ArrayList<AccountSyncStats>(
2526 authoritySyncStats.accountMap.values());
2527 Collections.sort(sortedAccounts, new Comparator<AccountSyncStats>() {
2528 @Override
2529 public int compare(AccountSyncStats lhs, AccountSyncStats rhs) {
2530 // reverse order
2531 int compare = Integer.compare(rhs.times, lhs.times);
2532 if (compare == 0) {
2533 compare = Long.compare(rhs.elapsedTime, lhs.elapsedTime);
2534 }
2535 return compare;
2536 }
2537 });
2538 for (AccountSyncStats stats: sortedAccounts) {
2539 elapsedTime = stats.elapsedTime;
2540 times = stats.times;
2541 timeStr = String.format("%ds/%d%%",
2542 elapsedTime / 1000,
2543 elapsedTime * 100 / totalElapsedTime);
2544 timesStr = String.format("%d/%d%%",
2545 times,
2546 times * 100 / totalTimes);
2547 pw.printf(accountFormat, stats.name, timesStr, timeStr);
2548 }
2549 pw.println(separator);
Alon Alberte0bde332011-09-22 14:26:16 -07002550 }
Alon Alberte0bde332011-09-22 14:26:16 -07002551 }
2552
2553 pw.println();
2554 pw.println("Recent Sync History");
Makoto Onuki94986212018-04-11 16:24:46 -07002555 pw.println("(SERVER is now split up to FEED and OTHER)");
Alon Albert57286f92012-10-09 14:21:38 -07002556 final String format = " %-" + maxAccount + "s %-" + maxAuthority + "s %s\n";
Alon Albertbf976ba2011-10-03 13:06:43 -07002557 final Map<String, Long> lastTimeMap = Maps.newHashMap();
Alon Albert57286f92012-10-09 14:21:38 -07002558 final PackageManager pm = mContext.getPackageManager();
Alon Alberte0bde332011-09-22 14:26:16 -07002559 for (int i = 0; i < N; i++) {
2560 SyncStorageEngine.SyncHistoryItem item = items.get(i);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002561 SyncStorageEngine.AuthorityInfo authorityInfo
Alon Alberte0bde332011-09-22 14:26:16 -07002562 = mSyncStorageEngine.getAuthority(item.authorityId);
2563 final String authorityName;
2564 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002565 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002566 authorityName = authorityInfo.target.provider;
2567 accountKey = authorityInfo.target.account.name + "/"
2568 + authorityInfo.target.account.type
2569 + " u" + authorityInfo.target.userId;
Alon Alberte0bde332011-09-22 14:26:16 -07002570 } else {
2571 authorityName = "Unknown";
2572 accountKey = "Unknown";
2573 }
2574 final long elapsedTime = item.elapsedTime;
2575 final Time time = new Time();
2576 final long eventTime = item.eventTime;
2577 time.set(eventTime);
2578
Alon Albertbf976ba2011-10-03 13:06:43 -07002579 final String key = authorityName + "/" + accountKey;
2580 final Long lastEventTime = lastTimeMap.get(key);
2581 final String diffString;
2582 if (lastEventTime == null) {
2583 diffString = "";
2584 } else {
2585 final long diff = (lastEventTime - eventTime) / 1000;
2586 if (diff < 60) {
2587 diffString = String.valueOf(diff);
2588 } else if (diff < 3600) {
2589 diffString = String.format("%02d:%02d", diff / 60, diff % 60);
2590 } else {
2591 final long sec = diff % 3600;
2592 diffString = String.format("%02d:%02d:%02d",
2593 diff / 3600, sec / 60, sec % 60);
2594 }
2595 }
2596 lastTimeMap.put(key, eventTime);
2597
2598 pw.printf(" #%-3d: %s %8s %5.1fs %8s",
Alon Alberte0bde332011-09-22 14:26:16 -07002599 i + 1,
2600 formatTime(eventTime),
2601 SyncStorageEngine.SOURCES[item.source],
Alon Albertbf976ba2011-10-03 13:06:43 -07002602 ((float) elapsedTime) / 1000,
2603 diffString);
Alon Albert57286f92012-10-09 14:21:38 -07002604 pw.printf(format, accountKey, authorityName,
2605 SyncOperation.reasonToString(pm, item.reason));
Alon Alberte0bde332011-09-22 14:26:16 -07002606
2607 if (item.event != SyncStorageEngine.EVENT_STOP
2608 || item.upstreamActivity != 0
2609 || item.downstreamActivity != 0) {
2610 pw.printf(" event=%d upstreamActivity=%d downstreamActivity=%d\n",
2611 item.event,
2612 item.upstreamActivity,
2613 item.downstreamActivity);
2614 }
2615 if (item.mesg != null
2616 && !SyncStorageEngine.MESG_SUCCESS.equals(item.mesg)) {
2617 pw.printf(" mesg=%s\n", item.mesg);
2618 }
2619 }
Alon Albert57286f92012-10-09 14:21:38 -07002620 pw.println();
2621 pw.println("Recent Sync History Extras");
Makoto Onuki94986212018-04-11 16:24:46 -07002622 pw.println("(SERVER is now split up to FEED and OTHER)");
Alon Albert57286f92012-10-09 14:21:38 -07002623 for (int i = 0; i < N; i++) {
2624 final SyncStorageEngine.SyncHistoryItem item = items.get(i);
2625 final Bundle extras = item.extras;
2626 if (extras == null || extras.size() == 0) {
2627 continue;
2628 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002629 final SyncStorageEngine.AuthorityInfo authorityInfo
Alon Albert57286f92012-10-09 14:21:38 -07002630 = mSyncStorageEngine.getAuthority(item.authorityId);
2631 final String authorityName;
2632 final String accountKey;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002633 if (authorityInfo != null) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002634 authorityName = authorityInfo.target.provider;
2635 accountKey = authorityInfo.target.account.name + "/"
2636 + authorityInfo.target.account.type
2637 + " u" + authorityInfo.target.userId;
Alon Albert57286f92012-10-09 14:21:38 -07002638 } else {
2639 authorityName = "Unknown";
2640 accountKey = "Unknown";
2641 }
2642 final Time time = new Time();
2643 final long eventTime = item.eventTime;
2644 time.set(eventTime);
2645
2646 pw.printf(" #%-3d: %s %8s ",
2647 i + 1,
2648 formatTime(eventTime),
2649 SyncStorageEngine.SOURCES[item.source]);
2650
2651 pw.printf(format, accountKey, authorityName, extras);
2652 }
Alon Alberte0bde332011-09-22 14:26:16 -07002653 }
2654 }
2655
2656 private void dumpDayStatistics(PrintWriter pw) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07002657 SyncStorageEngine.DayStats dses[] = mSyncStorageEngine.getDayStatistics();
2658 if (dses != null && dses[0] != null) {
2659 pw.println();
2660 pw.println("Sync Statistics");
2661 pw.print(" Today: "); dumpDayStatistic(pw, dses[0]);
2662 int today = dses[0].day;
2663 int i;
2664 SyncStorageEngine.DayStats ds;
Doug Zongker44f57472009-09-20 15:52:43 -07002665
Dianne Hackborn231cc602009-04-27 17:10:36 -07002666 // Print each day in the current week.
2667 for (i=1; i<=6 && i < dses.length; i++) {
2668 ds = dses[i];
2669 if (ds == null) break;
2670 int delta = today-ds.day;
2671 if (delta > 6) break;
Doug Zongker44f57472009-09-20 15:52:43 -07002672
Dianne Hackborn231cc602009-04-27 17:10:36 -07002673 pw.print(" Day-"); pw.print(delta); pw.print(": ");
2674 dumpDayStatistic(pw, ds);
2675 }
Doug Zongker44f57472009-09-20 15:52:43 -07002676
Dianne Hackborn231cc602009-04-27 17:10:36 -07002677 // Aggregate all following days into weeks and print totals.
2678 int weekDay = today;
2679 while (i < dses.length) {
2680 SyncStorageEngine.DayStats aggr = null;
2681 weekDay -= 7;
2682 while (i < dses.length) {
2683 ds = dses[i];
2684 if (ds == null) {
2685 i = dses.length;
2686 break;
2687 }
2688 int delta = weekDay-ds.day;
2689 if (delta > 6) break;
2690 i++;
Doug Zongker44f57472009-09-20 15:52:43 -07002691
Dianne Hackborn231cc602009-04-27 17:10:36 -07002692 if (aggr == null) {
2693 aggr = new SyncStorageEngine.DayStats(weekDay);
2694 }
2695 aggr.successCount += ds.successCount;
2696 aggr.successTime += ds.successTime;
2697 aggr.failureCount += ds.failureCount;
2698 aggr.failureTime += ds.failureTime;
2699 }
2700 if (aggr != null) {
2701 pw.print(" Week-"); pw.print((today-weekDay)/7); pw.print(": ");
2702 dumpDayStatistic(pw, aggr);
2703 }
2704 }
2705 }
Alon Alberte0bde332011-09-22 14:26:16 -07002706 }
Doug Zongker44f57472009-09-20 15:52:43 -07002707
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002708 private void dumpSyncAdapters(IndentingPrintWriter pw) {
2709 pw.println();
2710 final List<UserInfo> users = getAllUsers();
2711 if (users != null) {
2712 for (UserInfo user : users) {
2713 pw.println("Sync adapters for " + user + ":");
2714 pw.increaseIndent();
2715 for (RegisteredServicesCache.ServiceInfo<?> info :
2716 mSyncAdapters.getAllServices(user.id)) {
2717 pw.println(info);
2718 }
2719 pw.decreaseIndent();
2720 pw.println();
2721 }
2722 }
2723 }
2724
Alon Alberte0bde332011-09-22 14:26:16 -07002725 private static class AuthoritySyncStats {
2726 String name;
2727 long elapsedTime;
2728 int times;
2729 Map<String, AccountSyncStats> accountMap = Maps.newHashMap();
2730
2731 private AuthoritySyncStats(String name) {
2732 this.name = name;
2733 }
2734 }
2735
2736 private static class AccountSyncStats {
2737 String name;
2738 long elapsedTime;
2739 int times;
2740
2741 private AccountSyncStats(String name) {
2742 this.name = name;
Dianne Hackborn231cc602009-04-27 17:10:36 -07002743 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 }
2745
Philip P. Moltmann486b2412018-01-03 11:29:01 -08002746 interface OnReadyCallback {
2747 void onReady();
2748 }
2749
2750 static void sendOnUnsyncableAccount(@NonNull Context context,
2751 @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
2752 @UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) {
2753 OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo,
2754 onReadyCallback);
2755
2756 boolean isBound = context.bindServiceAsUser(
2757 getAdapterBindIntent(context, syncAdapterInfo.componentName, userId),
2758 connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId));
2759
2760 if (isBound) {
2761 // Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection.
2762 (new Handler(Looper.getMainLooper())).postDelayed(
2763 () -> context.unbindService(connection),
2764 OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS);
2765 } else {
2766 /*
2767 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
2768 * there the service cannot be bound, assume the default behavior.
2769 */
2770 connection.onReady();
2771 }
2772 }
2773
2774
2775 /**
2776 * Helper class for calling ISyncAdapter.onUnsyncableAccountDone.
2777 *
2778 * If this returns {@code true} the onReadyCallback is called. Otherwise nothing happens.
2779 */
2780 private static class OnUnsyncableAccountCheck implements ServiceConnection {
2781 static final long SERVICE_BOUND_TIME_MILLIS = 5000;
2782
2783 private final @NonNull OnReadyCallback mOnReadyCallback;
2784 private final @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType>
2785 mSyncAdapterInfo;
2786
2787 OnUnsyncableAccountCheck(
2788 @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
2789 @NonNull OnReadyCallback onReadyCallback) {
2790 mSyncAdapterInfo = syncAdapterInfo;
2791 mOnReadyCallback = onReadyCallback;
2792 }
2793
2794 private void onReady() {
2795 long identity = Binder.clearCallingIdentity();
2796 try {
2797 mOnReadyCallback.onReady();
2798 } finally {
2799 Binder.restoreCallingIdentity(identity);
2800 }
2801 }
2802
2803 @Override
2804 public void onServiceConnected(ComponentName name, IBinder service) {
2805 final ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
2806
2807 try {
2808 adapter.onUnsyncableAccount(new ISyncAdapterUnsyncableAccountCallback.Stub() {
2809 @Override
2810 public void onUnsyncableAccountDone(boolean isReady) {
2811 if (isReady) {
2812 onReady();
2813 }
2814 }
2815 });
2816 } catch (RemoteException e) {
2817 Slog.e(TAG, "Could not call onUnsyncableAccountDone " + mSyncAdapterInfo, e);
2818 /*
2819 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
2820 * there is a crash in the implementation, assume the default behavior.
2821 */
2822 onReady();
2823 }
2824 }
2825
2826 @Override
2827 public void onServiceDisconnected(ComponentName name) {
2828 // Wait until the service connects again
2829 }
2830 }
2831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002832 /**
2833 * A helper object to keep track of the time we have spent syncing since the last boot
2834 */
2835 private class SyncTimeTracker {
2836 /** True if a sync was in progress on the most recent call to update() */
2837 boolean mLastWasSyncing = false;
2838 /** Used to track when lastWasSyncing was last set */
2839 long mWhenSyncStarted = 0;
2840 /** The cumulative time we have spent syncing */
2841 private long mTimeSpentSyncing;
2842
2843 /** Call to let the tracker know that the sync state may have changed */
2844 public synchronized void update() {
Fred Quintana918339a2010-10-05 14:00:39 -07002845 final boolean isSyncInProgress = !mActiveSyncContexts.isEmpty();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002846 if (isSyncInProgress == mLastWasSyncing) return;
2847 final long now = SystemClock.elapsedRealtime();
2848 if (isSyncInProgress) {
2849 mWhenSyncStarted = now;
2850 } else {
2851 mTimeSpentSyncing += now - mWhenSyncStarted;
2852 }
2853 mLastWasSyncing = isSyncInProgress;
2854 }
2855
2856 /** Get how long we have been syncing, in ms */
2857 public synchronized long timeSpentSyncing() {
2858 if (!mLastWasSyncing) return mTimeSpentSyncing;
2859
2860 final long now = SystemClock.elapsedRealtime();
2861 return mTimeSpentSyncing + (now - mWhenSyncStarted);
2862 }
2863 }
2864
Fred Quintana718d8a22009-04-29 17:53:20 -07002865 class ServiceConnectionData {
2866 public final ActiveSyncContext activeSyncContext;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002867 public final IBinder adapter;
2868
2869 ServiceConnectionData(ActiveSyncContext activeSyncContext, IBinder adapter) {
Fred Quintana718d8a22009-04-29 17:53:20 -07002870 this.activeSyncContext = activeSyncContext;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002871 this.adapter = adapter;
Fred Quintana718d8a22009-04-29 17:53:20 -07002872 }
2873 }
2874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002875 /**
Makoto Onuki056a9752018-05-08 15:21:56 -07002876 * @return whether the device is ready to run sync jobs.
2877 */
2878 public static boolean readyToSync() {
2879 synchronized (SyncManager.class) {
2880 return sInstance != null && sInstance.mProvisioned && sInstance.mBootCompleted
2881 && sInstance.mJobServiceReady;
2882 }
2883 }
2884
2885 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 * Handles SyncOperation Messages that are posted to the associated
2887 * HandlerThread.
2888 */
2889 class SyncHandler extends Handler {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002890 // Messages that can be sent on mHandler.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002891 private static final int MESSAGE_SYNC_FINISHED = 1;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002892 private static final int MESSAGE_RELEASE_MESSAGES_FROM_QUEUE = 2;
Fred Quintana718d8a22009-04-29 17:53:20 -07002893 private static final int MESSAGE_SERVICE_CONNECTED = 4;
2894 private static final int MESSAGE_SERVICE_DISCONNECTED = 5;
Fred Quintana918339a2010-10-05 14:00:39 -07002895 private static final int MESSAGE_CANCEL = 6;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002896 static final int MESSAGE_JOBSERVICE_OBJECT = 7;
2897 static final int MESSAGE_START_SYNC = 10;
2898 static final int MESSAGE_STOP_SYNC = 11;
2899 static final int MESSAGE_SCHEDULE_SYNC = 12;
2900 static final int MESSAGE_UPDATE_PERIODIC_SYNC = 13;
2901 static final int MESSAGE_REMOVE_PERIODIC_SYNC = 14;
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002902
Matthew Williams1967c8d2015-06-19 19:03:13 -07002903 /**
2904 * Posted periodically to monitor network process for long-running syncs.
2905 * obj: {@link com.android.server.content.SyncManager.ActiveSyncContext}
2906 */
2907 private static final int MESSAGE_MONITOR_SYNC = 8;
振淦王60a74312015-12-01 16:37:31 +08002908 private static final int MESSAGE_ACCOUNTS_UPDATED = 9;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002910 public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07002911 private final HashMap<String, PowerManager.WakeLock> mWakeLocks = Maps.newHashMap();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002912
Matthew Williams8b76d202015-05-03 18:16:25 -07002913 private List<Message> mUnreadyQueue = new ArrayList<Message>();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -07002914
Matthew Williams8b76d202015-05-03 18:16:25 -07002915 void onBootCompleted() {
Matthew Williams8704fc32013-09-27 11:32:35 -07002916 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002917 Slog.v(TAG, "Boot completed.");
Matthew Williams8704fc32013-09-27 11:32:35 -07002918 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002919 checkIfDeviceReady();
Matthew Williams8b76d202015-05-03 18:16:25 -07002920 }
2921
2922 void onDeviceProvisioned() {
2923 if (Log.isLoggable(TAG, Log.DEBUG)) {
2924 Log.d(TAG, "mProvisioned=" + mProvisioned);
2925 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002926 checkIfDeviceReady();
2927 }
2928
2929 void checkIfDeviceReady() {
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002930 if (mProvisioned && mBootCompleted && mJobServiceReady) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002931 synchronized(this) {
Shreyas Basarge3147bbc2016-02-19 23:51:40 +00002932 mSyncStorageEngine.restoreAllPeriodicSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002933 // Dispatch any stashed messages.
2934 obtainMessage(MESSAGE_RELEASE_MESSAGES_FROM_QUEUE).sendToTarget();
2935 }
Matthew Williams8b76d202015-05-03 18:16:25 -07002936 }
2937 }
2938
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002939 /**
2940 * Stash any messages that come to the handler before boot is complete or before the device
2941 * is properly provisioned (i.e. out of set-up wizard).
2942 * {@link #onBootCompleted()} and {@link SyncHandler#onDeviceProvisioned} both
2943 * need to come in before we start syncing.
2944 * @param msg Message to dispatch at a later point.
2945 * @return true if a message was enqueued, false otherwise. This is to avoid losing the
2946 * message if we manage to acquire the lock but by the time we do boot has completed.
2947 */
2948 private boolean tryEnqueueMessageUntilReadyToRun(Message msg) {
2949 synchronized (this) {
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002950 if (!mBootCompleted || !mProvisioned || !mJobServiceReady) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002951 // Need to copy the message bc looper will recycle it.
2952 Message m = Message.obtain(msg);
2953 mUnreadyQueue.add(m);
2954 return true;
2955 } else {
2956 return false;
Matthew Williams8704fc32013-09-27 11:32:35 -07002957 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002958 }
2959 }
2960
2961 public SyncHandler(Looper looper) {
2962 super(looper);
2963 }
2964
2965 public void handleMessage(Message msg) {
2966 try {
2967 mSyncManagerWakeLock.acquire();
2968 // We only want to enqueue sync related messages until device is ready.
2969 // Other messages are handled without enqueuing.
2970 if (msg.what == MESSAGE_JOBSERVICE_OBJECT) {
2971 Slog.i(TAG, "Got SyncJobService instance.");
2972 mSyncJobService = (SyncJobService) msg.obj;
Shreyas Basargea4ac5ab2016-04-21 20:31:44 +01002973 mJobServiceReady = true;
2974 checkIfDeviceReady();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00002975 } else if (msg.what == SyncHandler.MESSAGE_ACCOUNTS_UPDATED) {
2976 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2977 Slog.v(TAG, "handleSyncHandlerMessage: MESSAGE_ACCOUNTS_UPDATED");
2978 }
2979 EndPoint targets = (EndPoint) msg.obj;
2980 updateRunningAccountsH(targets);
2981 } else if (msg.what == MESSAGE_RELEASE_MESSAGES_FROM_QUEUE) {
2982 if (mUnreadyQueue != null) {
2983 for (Message m : mUnreadyQueue) {
2984 handleSyncMessage(m);
2985 }
2986 mUnreadyQueue = null;
2987 }
2988 } else if (tryEnqueueMessageUntilReadyToRun(msg)) {
2989 // No work to be done.
2990 } else {
2991 handleSyncMessage(msg);
2992 }
2993 } finally {
2994 mSyncManagerWakeLock.release();
2995 }
2996 }
2997
2998 private void handleSyncMessage(Message msg) {
2999 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3000
3001 try {
3002 mDataConnectionIsConnected = readDataConnectionState();
3003 switch (msg.what) {
3004 case MESSAGE_SCHEDULE_SYNC:
Shreyas Basargeba1f7902016-10-01 00:19:44 +01003005 ScheduleSyncMessagePayload syncPayload =
3006 (ScheduleSyncMessagePayload) msg.obj;
3007 SyncOperation op = syncPayload.syncOperation;
3008 scheduleSyncOperationH(op, syncPayload.minDelayMillis);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003009 break;
3010
3011 case MESSAGE_START_SYNC:
3012 op = (SyncOperation) msg.obj;
3013 startSyncH(op);
3014 break;
3015
3016 case MESSAGE_STOP_SYNC:
3017 op = (SyncOperation) msg.obj;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003018 if (isLoggable) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003019 Slog.v(TAG, "Stop sync received.");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003020 }
3021 ActiveSyncContext asc = findActiveSyncContextH(op.jobId);
3022 if (asc != null) {
3023 runSyncFinishedOrCanceledH(null /* no result */, asc);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003024 boolean reschedule = msg.arg1 != 0;
3025 boolean applyBackoff = msg.arg2 != 0;
3026 if (isLoggable) {
3027 Slog.v(TAG, "Stopping sync. Reschedule: " + reschedule
3028 + "Backoff: " + applyBackoff);
3029 }
3030 if (applyBackoff) {
3031 increaseBackoffSetting(op.target);
3032 }
3033 if (reschedule) {
3034 deferStoppedSyncH(op, 0);
3035 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003036 }
3037 break;
3038
3039 case MESSAGE_UPDATE_PERIODIC_SYNC:
3040 UpdatePeriodicSyncMessagePayload data =
3041 (UpdatePeriodicSyncMessagePayload) msg.obj;
3042 updateOrAddPeriodicSyncH(data.target, data.pollFrequency,
3043 data.flex, data.extras);
3044 break;
3045 case MESSAGE_REMOVE_PERIODIC_SYNC:
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003046 Pair<EndPoint, String> args = (Pair<EndPoint, String>) (msg.obj);
3047 removePeriodicSyncH(args.first, msg.getData(), args.second);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003048 break;
3049
3050 case SyncHandler.MESSAGE_CANCEL:
3051 SyncStorageEngine.EndPoint endpoint = (SyncStorageEngine.EndPoint) msg.obj;
3052 Bundle extras = msg.peekData();
3053 if (Log.isLoggable(TAG, Log.DEBUG)) {
3054 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_CANCEL: "
3055 + endpoint + " bundle: " + extras);
3056 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003057 cancelActiveSyncH(endpoint, extras, "MESSAGE_CANCEL");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003058 break;
3059
3060 case SyncHandler.MESSAGE_SYNC_FINISHED:
3061 SyncFinishedOrCancelledMessagePayload payload =
3062 (SyncFinishedOrCancelledMessagePayload) msg.obj;
3063 if (!isSyncStillActiveH(payload.activeSyncContext)) {
3064 Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
3065 + "sync is no longer active: "
3066 + payload.activeSyncContext);
3067 break;
3068 }
3069 if (isLoggable) {
3070 Slog.v(TAG, "syncFinished" + payload.activeSyncContext.mSyncOperation);
3071 }
3072 mSyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003073 payload.activeSyncContext.mSyncOperation.jobId, false,
3074 "sync finished");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003075 runSyncFinishedOrCanceledH(payload.syncResult,
3076 payload.activeSyncContext);
3077 break;
3078
3079 case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
3080 ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
3081 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3082 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
3083 + msgData.activeSyncContext);
3084 }
3085 // Check that this isn't an old message.
3086 if (isSyncStillActiveH(msgData.activeSyncContext)) {
3087 runBoundToAdapterH(
3088 msgData.activeSyncContext,
3089 msgData.adapter);
3090 }
3091 break;
3092 }
3093
3094 case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
3095 final ActiveSyncContext currentSyncContext =
3096 ((ServiceConnectionData) msg.obj).activeSyncContext;
3097 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3098 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
3099 + currentSyncContext);
3100 }
3101 // Check that this isn't an old message.
3102 if (isSyncStillActiveH(currentSyncContext)) {
3103 // cancel the sync if we have a syncadapter, which means one is
3104 // outstanding
3105 try {
3106 if (currentSyncContext.mSyncAdapter != null) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003107 mLogger.log("Calling cancelSync for SERVICE_DISCONNECTED ",
3108 currentSyncContext,
3109 " adapter=", currentSyncContext.mSyncAdapter);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003110 currentSyncContext.mSyncAdapter.cancelSync(currentSyncContext);
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003111 mLogger.log("Canceled");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003112 }
3113 } catch (RemoteException e) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003114 mLogger.log("RemoteException ", Log.getStackTraceString(e));
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003115 // We don't need to retry this in this case.
3116 }
3117
3118 // Pretend that the sync failed with an IOException,
3119 // which is a soft error.
3120 SyncResult syncResult = new SyncResult();
3121 syncResult.stats.numIoExceptions++;
3122 mSyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003123 currentSyncContext.mSyncOperation.jobId, false,
3124 "service disconnected");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003125 runSyncFinishedOrCanceledH(syncResult, currentSyncContext);
3126 }
3127 break;
3128 }
3129
3130 case SyncHandler.MESSAGE_MONITOR_SYNC:
3131 ActiveSyncContext monitoredSyncContext = (ActiveSyncContext) msg.obj;
3132 if (Log.isLoggable(TAG, Log.DEBUG)) {
3133 Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_MONITOR_SYNC: " +
3134 monitoredSyncContext.mSyncOperation.target);
3135 }
3136
3137 if (isSyncNotUsingNetworkH(monitoredSyncContext)) {
3138 Log.w(TAG, String.format(
3139 "Detected sync making no progress for %s. cancelling.",
3140 monitoredSyncContext));
3141 mSyncJobService.callJobFinished(
Makoto Onukia9dca242017-06-21 17:06:49 -07003142 monitoredSyncContext.mSyncOperation.jobId, false,
3143 "no network activity");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003144 runSyncFinishedOrCanceledH(
3145 null /* cancel => no result */, monitoredSyncContext);
3146 } else {
3147 // Repost message to check again.
3148 postMonitorSyncProgressMessage(monitoredSyncContext);
3149 }
3150 break;
3151
3152 }
3153 } finally {
3154 mSyncTimeTracker.update();
Fred Quintanae91ebe22009-09-29 20:44:30 -07003155 }
3156 }
3157
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003158 private PowerManager.WakeLock getSyncWakeLock(SyncOperation operation) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08003159 final String wakeLockKey = operation.wakeLockName();
Fred Quintanab3029c32010-04-06 13:27:12 -07003160 PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
3161 if (wakeLock == null) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -08003162 final String name = SYNC_WAKE_LOCK_PREFIX + wakeLockKey;
Fred Quintanab3029c32010-04-06 13:27:12 -07003163 wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
3164 wakeLock.setReferenceCounted(false);
3165 mWakeLocks.put(wakeLockKey, wakeLock);
3166 }
3167 return wakeLock;
3168 }
3169
Matthew Williams8704fc32013-09-27 11:32:35 -07003170 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003171 * Defer the specified SyncOperation by rescheduling it on the JobScheduler with some
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003172 * delay. This is equivalent to a failure. If this is a periodic sync, a delayed one-off
3173 * sync will be scheduled.
Matthew Williams8704fc32013-09-27 11:32:35 -07003174 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003175 private void deferSyncH(SyncOperation op, long delay, String why) {
3176 mLogger.log("deferSyncH() ", (op.isPeriodic ? "periodic " : ""),
3177 "sync. op=", op, " delay=", delay, " why=", why);
3178 mSyncJobService.callJobFinished(op.jobId, false, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003179 if (op.isPeriodic) {
3180 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
3181 } else {
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003182 // mSyncJobService.callJobFinished is async, so cancel the job to ensure we don't
3183 // find the this job in the pending jobs list while looking for duplicates
3184 // before scheduling it at a later time.
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003185 cancelJob(op, "deferSyncH()");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003186 scheduleSyncOperationH(op, delay);
Fred Quintanae91ebe22009-09-29 20:44:30 -07003187 }
3188 }
Matthew Williams8704fc32013-09-27 11:32:35 -07003189
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003190 /* Same as deferSyncH, but assumes that job is no longer running on JobScheduler. */
3191 private void deferStoppedSyncH(SyncOperation op, long delay) {
3192 if (op.isPeriodic) {
3193 scheduleSyncOperationH(op.createOneTimeSyncOperation(), delay);
3194 } else {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003195 scheduleSyncOperationH(op, delay);
3196 }
3197 }
3198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003199 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003200 * Cancel an active sync and reschedule it on the JobScheduler with some delay.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003202 private void deferActiveSyncH(ActiveSyncContext asc, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003203 SyncOperation op = asc.mSyncOperation;
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003204 runSyncFinishedOrCanceledH(null, asc);
Makoto Onukia9dca242017-06-21 17:06:49 -07003205 deferSyncH(op, SYNC_DELAY_ON_CONFLICT, why);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 }
3207
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003208 private void startSyncH(SyncOperation op) {
3209 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3210 if (isLoggable) Slog.v(TAG, op.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211
Makoto Onuki94986212018-04-11 16:24:46 -07003212 // At this point, we know the device has been connected to the server, so
3213 // assume the clock is correct.
3214 mSyncStorageEngine.setClockValid();
3215
Makoto Onuki5397be12017-12-20 16:22:34 +09003216 mSyncJobService.markSyncStarted(op.jobId);
3217
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003218 if (mStorageIsLow) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003219 deferSyncH(op, SYNC_DELAY_ON_LOW_STORAGE, "storage low");
Matthew Williams8704fc32013-09-27 11:32:35 -07003220 return;
3221 }
3222
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003223 if (op.isPeriodic) {
3224 // Don't allow this periodic to run if a previous instance failed and is currently
3225 // scheduled according to some backoff criteria.
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003226 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003227 for (SyncOperation syncOperation: ops) {
3228 if (syncOperation.sourcePeriodicId == op.jobId) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003229 mSyncJobService.callJobFinished(op.jobId, false,
3230 "periodic sync, pending");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003231 return;
Fred Quintana718d8a22009-04-29 17:53:20 -07003232 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003233 }
3234 // Don't allow this periodic to run if a previous instance failed and is currently
3235 // executing according to some backoff criteria.
3236 for (ActiveSyncContext asc: mActiveSyncContexts) {
3237 if (asc.mSyncOperation.sourcePeriodicId == op.jobId) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003238 mSyncJobService.callJobFinished(op.jobId, false,
3239 "periodic sync, already running");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003240 return;
Fred Quintana718d8a22009-04-29 17:53:20 -07003241 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003242 }
3243 // Check for adapter delays.
3244 if (isAdapterDelayed(op.target)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003245 deferSyncH(op, 0 /* No minimum delay */, "backing off");
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003246 return;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003247 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003248 }
Fred Quintana718d8a22009-04-29 17:53:20 -07003249
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003250 // Check for conflicting syncs.
3251 for (ActiveSyncContext asc: mActiveSyncContexts) {
3252 if (asc.mSyncOperation.isConflict(op)) {
3253 // If the provided SyncOperation conflicts with a running one, the lower
3254 // priority sync is pre-empted.
3255 if (asc.mSyncOperation.findPriority() >= op.findPriority()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003257 Slog.v(TAG, "Rescheduling sync due to conflict " + op.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003258 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003259 deferSyncH(op, SYNC_DELAY_ON_CONFLICT, "delay on conflict");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003260 return;
Matthew Williamsfa774182013-06-18 15:44:11 -07003261 } else {
Matthew Williamsfa774182013-06-18 15:44:11 -07003262 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003263 Slog.v(TAG, "Pushing back running sync due to a higher priority sync");
Fred Quintana918339a2010-10-05 14:00:39 -07003264 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003265 deferActiveSyncH(asc, "preempted");
Shreyas Basarge7680dd92016-02-11 14:52:47 +00003266 break;
Alon Albert8e285552012-09-17 15:05:27 -07003267 }
3268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 }
3270
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003271 final int syncOpState = computeSyncOpState(op);
3272 switch (syncOpState) {
3273 case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS:
3274 case SYNC_OP_STATE_INVALID: {
Makoto Onukia9dca242017-06-21 17:06:49 -07003275 mSyncJobService.callJobFinished(op.jobId, false,
3276 "invalid op state: " + syncOpState);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003277 } return;
3278 }
3279
3280 if (!dispatchSyncOperation(op)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003281 mSyncJobService.callJobFinished(op.jobId, false, "dispatchSyncOperation() failed");
Fred Quintana918339a2010-10-05 14:00:39 -07003282 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003283
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003284 setAuthorityPendingState(op.target);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003285 }
3286
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003287 private ActiveSyncContext findActiveSyncContextH(int jobId) {
3288 for (ActiveSyncContext asc: mActiveSyncContexts) {
3289 SyncOperation op = asc.mSyncOperation;
3290 if (op != null && op.jobId == jobId) {
3291 return asc;
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003292 }
3293 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003294 return null;
Matthew Williamsa4745542015-12-10 20:29:02 +00003295 }
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003296
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003297 private void updateRunningAccountsH(EndPoint syncTargets) {
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003298 AccountAndUser[] oldAccounts = mRunningAccounts;
振淦王60a74312015-12-01 16:37:31 +08003299 mRunningAccounts = AccountManagerService.getSingleton().getRunningAccounts();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003300 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3301 Slog.v(TAG, "Accounts list: ");
3302 for (AccountAndUser acc : mRunningAccounts) {
3303 Slog.v(TAG, acc.toString());
3304 }
3305 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003306 if (mLogger.enabled()) {
3307 mLogger.log("updateRunningAccountsH: ", Arrays.toString(mRunningAccounts));
3308 }
振淦王60a74312015-12-01 16:37:31 +08003309 if (mBootCompleted) {
3310 doDatabaseCleanup();
3311 }
3312
3313 AccountAndUser[] accounts = mRunningAccounts;
3314 for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
3315 if (!containsAccountAndUser(accounts,
3316 currentSyncContext.mSyncOperation.target.account,
3317 currentSyncContext.mSyncOperation.target.userId)) {
3318 Log.d(TAG, "canceling sync since the account is no longer running");
3319 sendSyncFinishedOrCanceledMessage(currentSyncContext,
3320 null /* no result since this is a cancel */);
3321 }
3322 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003323
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003324 // On account add, check if there are any settings to be restored.
3325 for (AccountAndUser aau : mRunningAccounts) {
3326 if (!containsAccountAndUser(oldAccounts, aau.account, aau.userId)) {
3327 if (Log.isLoggable(TAG, Log.DEBUG)) {
3328 Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
3329 }
3330 AccountSyncSettingsBackupHelper.accountAdded(mContext);
3331 break;
3332 }
3333 }
3334
Rubin Xu2c548e02016-04-01 17:47:28 +01003335 // Cancel all jobs from non-existent accounts.
3336 AccountAndUser[] allAccounts = AccountManagerService.getSingleton().getAllAccounts();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003337 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003338 for (SyncOperation op: ops) {
Rubin Xu2c548e02016-04-01 17:47:28 +01003339 if (!containsAccountAndUser(allAccounts, op.target.account, op.target.userId)) {
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003340 mLogger.log("canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003341 cancelJob(op, "updateRunningAccountsH()");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003342 }
3343 }
3344
3345 if (syncTargets != null) {
3346 scheduleSync(syncTargets.account, syncTargets.userId,
Svet Ganovf6d424f12016-09-20 20:18:53 -07003347 SyncOperation.REASON_ACCOUNTS_UPDATED, syncTargets.provider,
Makoto Onuki61283ec2018-01-31 17:22:36 -08003348 null, AuthorityInfo.NOT_INITIALIZED,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003349 ContentResolver.SYNC_EXEMPTION_NONE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003350 }
3351 }
3352
3353 /**
3354 * The given SyncOperation will be removed and a new one scheduled in its place if
3355 * an updated period or flex is specified.
3356 * @param syncOperation SyncOperation whose period and flex is to be updated.
3357 * @param pollFrequencyMillis new period in milliseconds.
3358 * @param flexMillis new flex time in milliseconds.
3359 */
3360 private void maybeUpdateSyncPeriodH(SyncOperation syncOperation, long pollFrequencyMillis,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003361 long flexMillis) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003362 if (!(pollFrequencyMillis == syncOperation.periodMillis
3363 && flexMillis == syncOperation.flexMillis)) {
3364 if (Log.isLoggable(TAG, Log.VERBOSE)) {
3365 Slog.v(TAG, "updating period " + syncOperation + " to " + pollFrequencyMillis
3366 + " and flex to " + flexMillis);
3367 }
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003368 SyncOperation newOp = new SyncOperation(syncOperation, pollFrequencyMillis,
3369 flexMillis);
3370 newOp.jobId = syncOperation.jobId;
3371 scheduleSyncOperationH(newOp);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003372 }
3373 }
3374
3375 private void updateOrAddPeriodicSyncH(EndPoint target, long pollFrequency, long flex,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003376 Bundle extras) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003377 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
3378 verifyJobScheduler(); // Will fill in mScheduledSyncs cache if it is not already filled.
3379 final long pollFrequencyMillis = pollFrequency * 1000L;
3380 final long flexMillis = flex * 1000L;
3381 if (isLoggable) {
3382 Slog.v(TAG, "Addition to periodic syncs requested: " + target
3383 + " period: " + pollFrequency
3384 + " flexMillis: " + flex
3385 + " extras: " + extras.toString());
3386 }
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003387 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003388 for (SyncOperation op: ops) {
3389 if (op.isPeriodic && op.target.matchesSpec(target)
3390 && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
3391 maybeUpdateSyncPeriodH(op, pollFrequencyMillis, flexMillis);
3392 return;
3393 }
3394 }
3395
3396 if (isLoggable) {
3397 Slog.v(TAG, "Adding new periodic sync: " + target
3398 + " period: " + pollFrequency
3399 + " flexMillis: " + flex
3400 + " extras: " + extras.toString());
3401 }
3402
3403 final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
3404 syncAdapterInfo = mSyncAdapters.getServiceInfo(
3405 SyncAdapterType.newKey(
3406 target.provider, target.account.type),
3407 target.userId);
3408 if (syncAdapterInfo == null) {
3409 return;
3410 }
3411
3412 SyncOperation op = new SyncOperation(target, syncAdapterInfo.uid,
3413 syncAdapterInfo.componentName.getPackageName(), SyncOperation.REASON_PERIODIC,
3414 SyncStorageEngine.SOURCE_PERIODIC, extras,
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003415 syncAdapterInfo.type.allowParallelSyncs(), true, SyncOperation.NO_JOB_ID,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003416 pollFrequencyMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003417
3418 final int syncOpState = computeSyncOpState(op);
3419 switch (syncOpState) {
3420 case SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS: {
Svet Ganov973edd192016-09-08 20:15:55 -07003421 String packageName = op.owningPackage;
3422 final int userId = UserHandle.getUserId(op.owningUid);
3423 // If the app did not run and has no account access, done
3424 if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
3425 return;
3426 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003427 mAccountManagerInternal.requestAccountAccess(op.target.account,
Svet Ganov973edd192016-09-08 20:15:55 -07003428 packageName, userId, new RemoteCallback((Bundle result) -> {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003429 if (result != null
3430 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
3431 updateOrAddPeriodicSync(target, pollFrequency, flex, extras);
3432 }
3433 }
3434 ));
3435 } return;
3436
3437 case SYNC_OP_STATE_INVALID: {
3438 return;
3439 }
3440 }
3441
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003442 scheduleSyncOperationH(op);
3443 mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
3444 }
3445
3446 /**
3447 * Remove this periodic sync operation and all one-off operations initiated by it.
3448 */
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003449 private void removePeriodicSyncInternalH(SyncOperation syncOperation, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003450 // Remove this periodic sync and all one-off syncs initiated by it.
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003451 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003452 for (SyncOperation op: ops) {
3453 if (op.sourcePeriodicId == syncOperation.jobId || op.jobId == syncOperation.jobId) {
3454 ActiveSyncContext asc = findActiveSyncContextH(syncOperation.jobId);
3455 if (asc != null) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003456 mSyncJobService.callJobFinished(syncOperation.jobId, false,
3457 "removePeriodicSyncInternalH");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003458 runSyncFinishedOrCanceledH(null, asc);
3459 }
Makoto Onukibbf6d8c2017-08-11 12:11:39 -07003460 mLogger.log("removePeriodicSyncInternalH-canceling: ", op);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003461 cancelJob(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003462 }
3463 }
3464 }
3465
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003466 private void removePeriodicSyncH(EndPoint target, Bundle extras, String why) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003467 verifyJobScheduler();
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003468 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003469 for (SyncOperation op: ops) {
3470 if (op.isPeriodic && op.target.matchesSpec(target)
3471 && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003472 removePeriodicSyncInternalH(op, why);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003473 }
3474 }
Dianne Hackborn627dfa12015-11-11 18:10:30 -08003475 }
3476
Matthew Williams1967c8d2015-06-19 19:03:13 -07003477 private boolean isSyncNotUsingNetworkH(ActiveSyncContext activeSyncContext) {
3478 final long bytesTransferredCurrent =
3479 getTotalBytesTransferredByUid(activeSyncContext.mSyncAdapterUid);
3480 final long deltaBytesTransferred =
3481 bytesTransferredCurrent - activeSyncContext.mBytesTransferredAtLastPoll;
3482
3483 if (Log.isLoggable(TAG, Log.DEBUG)) {
3484 // Bytes transferred
3485 long remainder = deltaBytesTransferred;
3486 long mb = remainder / (1024 * 1024);
3487 remainder %= 1024 * 1024;
3488 long kb = remainder / 1024;
3489 remainder %= 1024;
3490 long b = remainder;
3491 Log.d(TAG, String.format(
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003492 "Time since last update: %ds. Delta transferred: %dMBs,%dKBs,%dBs",
3493 (SystemClock.elapsedRealtime()
3494 - activeSyncContext.mLastPolledTimeElapsed)/1000,
3495 mb, kb, b)
Matthew Williams1967c8d2015-06-19 19:03:13 -07003496 );
3497 }
3498 return (deltaBytesTransferred <= SYNC_MONITOR_PROGRESS_THRESHOLD_BYTES);
3499 }
3500
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003501 /**
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003502 * Determine if a sync is no longer valid and should be dropped.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003503 */
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003504 private int computeSyncOpState(SyncOperation op) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003505 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003506 int state;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003507 final EndPoint target = op.target;
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003508
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003509 // Drop the sync if the account of this operation no longer exists.
3510 AccountAndUser[] accounts = mRunningAccounts;
3511 if (!containsAccountAndUser(accounts, target.account, target.userId)) {
3512 if (isLoggable) {
3513 Slog.v(TAG, " Dropping sync operation: account doesn't exist.");
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003514 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003515 return SYNC_OP_STATE_INVALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003516 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003517 // Drop this sync request if it isn't syncable.
Philip P. Moltmann486b2412018-01-03 11:29:01 -08003518 state = computeSyncable(target.account, target.userId, target.provider, true);
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003519 if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003520 if (isLoggable) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003521 Slog.v(TAG, " Dropping sync operation: "
3522 + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003523 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003524 return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003525 }
Svet Ganovdfed1c72016-08-25 15:40:52 -07003526 if (state == AuthorityInfo.NOT_SYNCABLE) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003527 if (isLoggable) {
Svet Ganovdfed1c72016-08-25 15:40:52 -07003528 Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE");
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003529 }
3530 return SYNC_OP_STATE_INVALID;
3531 }
3532
3533 final boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
3534 && mSyncStorageEngine.getSyncAutomatically(target.account,
3535 target.userId, target.provider);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003536
3537 // We ignore system settings that specify the sync is invalid if:
3538 // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
3539 // or
3540 // 2) it's an initialisation sync - we just need to connect to it.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003541 final boolean ignoreSystemConfiguration = op.isIgnoreSettings() || (state < 0);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003542
3543 // Sync not enabled.
3544 if (!syncEnabled && !ignoreSystemConfiguration) {
3545 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003546 Slog.v(TAG, " Dropping sync operation: disallowed by settings/network.");
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003547 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003548 return SYNC_OP_STATE_INVALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003549 }
Svetoslav Ganov5cb29732016-07-11 19:32:30 -07003550 return SYNC_OP_STATE_VALID;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003551 }
Fred Quintana918339a2010-10-05 14:00:39 -07003552
Fred Quintana87b14662011-09-12 10:32:55 -07003553 private boolean dispatchSyncOperation(SyncOperation op) {
Fred Quintana918339a2010-10-05 14:00:39 -07003554 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003555 Slog.v(TAG, "dispatchSyncOperation: we are going to sync " + op);
3556 Slog.v(TAG, "num active syncs: " + mActiveSyncContexts.size());
Fred Quintana918339a2010-10-05 14:00:39 -07003557 for (ActiveSyncContext syncContext : mActiveSyncContexts) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003558 Slog.v(TAG, syncContext.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003559 }
3560 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07003561 if (op.isAppStandbyExempted()) {
3562 final UsageStatsManagerInternal usmi = LocalServices.getService(
3563 UsageStatsManagerInternal.class);
3564 if (usmi != null) {
3565 usmi.reportExemptedSyncStart(op.owningPackage,
3566 UserHandle.getUserId(op.owningUid));
3567 }
3568 }
3569
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003570 // Connect to the sync adapter.
3571 int targetUid;
3572 ComponentName targetComponent;
3573 final SyncStorageEngine.EndPoint info = op.target;
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003574 SyncAdapterType syncAdapterType =
3575 SyncAdapterType.newKey(info.provider, info.account.type);
3576 final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
3577 syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId);
3578 if (syncAdapterInfo == null) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003579 mLogger.log("dispatchSyncOperation() failed: no sync adapter info for ",
3580 syncAdapterType);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003581 Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
3582 + ", removing settings for it");
3583 mSyncStorageEngine.removeAuthority(info);
3584 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003586 targetUid = syncAdapterInfo.uid;
3587 targetComponent = syncAdapterInfo.componentName;
Fred Quintana718d8a22009-04-29 17:53:20 -07003588 ActiveSyncContext activeSyncContext =
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003589 new ActiveSyncContext(op, insertStartSyncEvent(op), targetUid);
Fred Quintana718d8a22009-04-29 17:53:20 -07003590 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003591 Slog.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);
Fred Quintana718d8a22009-04-29 17:53:20 -07003592 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07003593
3594 activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);
3595 mActiveSyncContexts.add(activeSyncContext);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003596
3597 // Post message to begin monitoring this sync's progress.
3598 postMonitorSyncProgressMessage(activeSyncContext);
3599
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003600 if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003601 mLogger.log("dispatchSyncOperation() failed: bind failed. target: ",
3602 targetComponent);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003603 Slog.e(TAG, "Bind attempt failed - target: " + targetComponent);
Fred Quintana918339a2010-10-05 14:00:39 -07003604 closeActiveSyncContext(activeSyncContext);
Fred Quintana87b14662011-09-12 10:32:55 -07003605 return false;
Fred Quintana718d8a22009-04-29 17:53:20 -07003606 }
3607
Fred Quintana87b14662011-09-12 10:32:55 -07003608 return true;
Fred Quintana718d8a22009-04-29 17:53:20 -07003609 }
3610
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003611 private void runBoundToAdapterH(final ActiveSyncContext activeSyncContext,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003612 IBinder syncAdapter) {
Fred Quintana918339a2010-10-05 14:00:39 -07003613 final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
Fred Quintana718d8a22009-04-29 17:53:20 -07003614 try {
Alon Alberteca75112010-12-08 15:02:33 -08003615 activeSyncContext.mIsLinkedToDeath = true;
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003616 syncAdapter.linkToDeath(activeSyncContext, 0);
Alon Alberteca75112010-12-08 15:02:33 -08003617
Makoto Onukia9dca242017-06-21 17:06:49 -07003618 mLogger.log("Sync start: account=" + syncOperation.target.account,
3619 " authority=", syncOperation.target.provider,
3620 " reason=", SyncOperation.reasonToString(null, syncOperation.reason),
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003621 " extras=", SyncOperation.extrasToString(syncOperation.extras),
3622 " adapter=", activeSyncContext.mSyncAdapter);
Makoto Onukia9dca242017-06-21 17:06:49 -07003623
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003624 activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter);
3625 activeSyncContext.mSyncAdapter
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003626 .startSync(activeSyncContext, syncOperation.target.provider,
3627 syncOperation.target.account, syncOperation.extras);
Makoto Onukia9dca242017-06-21 17:06:49 -07003628
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003629 mLogger.log("Sync is running now...");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003630 } catch (RemoteException remoteExc) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003631 mLogger.log("Sync failed with RemoteException: ", remoteExc.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003632 Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);
3633 closeActiveSyncContext(activeSyncContext);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003634 increaseBackoffSetting(syncOperation.target);
3635 scheduleSyncOperationH(syncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003636 } catch (RuntimeException exc) {
Makoto Onukia9dca242017-06-21 17:06:49 -07003637 mLogger.log("Sync failed with RuntimeException: ", exc.toString());
Fred Quintana918339a2010-10-05 14:00:39 -07003638 closeActiveSyncContext(activeSyncContext);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003639 Slog.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003641 }
3642
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003643 /**
Matthew Williams8ef22042013-07-26 12:56:39 -07003644 * Cancel the sync for the provided target that matches the given bundle.
Matthew Williams1967c8d2015-06-19 19:03:13 -07003645 * @param info Can have null fields to indicate all the active syncs for that field.
3646 * @param extras Can be null to indicate <strong>all</strong> syncs for the given endpoint.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003647 */
Makoto Onukia9dca242017-06-21 17:06:49 -07003648 private void cancelActiveSyncH(SyncStorageEngine.EndPoint info, Bundle extras,
3649 String why) {
Fred Quintana918339a2010-10-05 14:00:39 -07003650 ArrayList<ActiveSyncContext> activeSyncs =
3651 new ArrayList<ActiveSyncContext>(mActiveSyncContexts);
3652 for (ActiveSyncContext activeSyncContext : activeSyncs) {
3653 if (activeSyncContext != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003654 final SyncStorageEngine.EndPoint opInfo =
3655 activeSyncContext.mSyncOperation.target;
Matthew Williams8ef22042013-07-26 12:56:39 -07003656 if (!opInfo.matchesSpec(info)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003657 continue;
Fred Quintana918339a2010-10-05 14:00:39 -07003658 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003659 if (extras != null &&
3660 !syncExtrasEquals(activeSyncContext.mSyncOperation.extras,
3661 extras,
3662 false /* no config settings */)) {
Amith Yamasani04e0d262012-02-14 11:50:53 -08003663 continue;
3664 }
Makoto Onukia9dca242017-06-21 17:06:49 -07003665 mSyncJobService.callJobFinished(activeSyncContext.mSyncOperation.jobId, false,
3666 why);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003667 runSyncFinishedOrCanceledH(null /* cancel => no result */, activeSyncContext);
Fred Quintana918339a2010-10-05 14:00:39 -07003668 }
3669 }
3670 }
3671
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003672 /**
3673 * Should be called when a one-off instance of a periodic sync completes successfully.
3674 */
3675 private void reschedulePeriodicSyncH(SyncOperation syncOperation) {
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003676 // Ensure that the periodic sync wasn't removed.
3677 SyncOperation periodicSync = null;
Shreyas Basargecbf5ae92016-03-08 16:13:06 +00003678 List<SyncOperation> ops = getAllPendingSyncs();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +00003679 for (SyncOperation op: ops) {
3680 if (op.isPeriodic && syncOperation.matchesPeriodicOperation(op)) {
3681 periodicSync = op;
3682 break;
3683 }
3684 }
3685 if (periodicSync == null) {
3686 return;
3687 }
3688 scheduleSyncOperationH(periodicSync);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003689 }
3690
Matthew Williams8b76d202015-05-03 18:16:25 -07003691 private void runSyncFinishedOrCanceledH(SyncResult syncResult,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003692 ActiveSyncContext activeSyncContext) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003693 final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
Alon Alberteca75112010-12-08 15:02:33 -08003694
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003695 final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
3696 final SyncStorageEngine.EndPoint info = syncOperation.target;
3697
Alon Alberteca75112010-12-08 15:02:33 -08003698 if (activeSyncContext.mIsLinkedToDeath) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003699 activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
Alon Alberteca75112010-12-08 15:02:33 -08003700 activeSyncContext.mIsLinkedToDeath = false;
3701 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003702 final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003703 String historyMessage;
3704 int downstreamActivity;
3705 int upstreamActivity;
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003706
Makoto Onukia9dca242017-06-21 17:06:49 -07003707 mLogger.log("runSyncFinishedOrCanceledH() op=", syncOperation, " result=", syncResult);
Shreyas Basargebd4c3ea2016-06-16 11:54:35 +01003708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003709 if (syncResult != null) {
3710 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003711 Slog.v(TAG, "runSyncFinishedOrCanceled [finished]: "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003712 + syncOperation + ", result " + syncResult);
3713 }
3714
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003715 // In the non-canceled case, close the active sync context before doing the rest
3716 // of the stuff.
3717 closeActiveSyncContext(activeSyncContext);
3718
3719 // Note this part is probably okay to do before closeActiveSyncContext()...
3720 // But moved here to restore OC-dev's behavior. See b/64597061.
3721 if (!syncOperation.isPeriodic) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003722 cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-finished");
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003723 }
3724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003725 if (!syncResult.hasError()) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07003726 historyMessage = SyncStorageEngine.MESG_SUCCESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003727 // TODO: set these correctly when the SyncResult is extended to include it
3728 downstreamActivity = 0;
3729 upstreamActivity = 0;
Makoto Onukia9dca242017-06-21 17:06:49 -07003730 clearBackoffSetting(syncOperation.target, "sync success");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003731
3732 // If the operation completes successfully and it was scheduled due to
3733 // a periodic operation failing, we reschedule the periodic operation to
3734 // start from now.
3735 if (syncOperation.isDerivedFromFailedPeriodicSync()) {
3736 reschedulePeriodicSyncH(syncOperation);
3737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003738 } else {
Makoto Onukiaad2b512018-02-07 09:31:46 -08003739 Log.w(TAG, "failed sync operation " + syncOperation + ", " + syncResult);
3740
3741 syncOperation.retries++;
3742 if (syncOperation.retries > mConstants.getMaxRetriesWithAppStandbyExemption()) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07003743 syncOperation.syncExemptionFlag = ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onukiaad2b512018-02-07 09:31:46 -08003744 }
3745
Fred Quintana307da1a2010-01-21 14:24:20 -08003746 // the operation failed so increase the backoff time
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003747 increaseBackoffSetting(syncOperation.target);
3748 if (!syncOperation.isPeriodic) {
3749 // reschedule the sync if so indicated by the syncResult
3750 maybeRescheduleSync(syncResult, syncOperation);
3751 } else {
3752 // create a normal sync instance that will respect adapter backoffs
Shreyas Basargeba1f7902016-10-01 00:19:44 +01003753 postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation(),
3754 0 /* min delay */);
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003755 }
Alon Albert57286f92012-10-09 14:21:38 -07003756 historyMessage = ContentResolver.syncErrorToString(
3757 syncResultToErrorNumber(syncResult));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003758 // TODO: set these correctly when the SyncResult is extended to include it
3759 downstreamActivity = 0;
3760 upstreamActivity = 0;
3761 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003762 setDelayUntilTime(syncOperation.target, syncResult.delayUntil);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003763 } else {
3764 if (isLoggable) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003765 Slog.v(TAG, "runSyncFinishedOrCanceled [canceled]: " + syncOperation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003766 }
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003767
3768 if (!syncOperation.isPeriodic) {
Makoto Onukidd4b14f2017-08-17 14:03:48 -07003769 cancelJob(syncOperation, "runSyncFinishedOrCanceledH()-canceled");
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003770 }
3771
Fred Quintana718d8a22009-04-29 17:53:20 -07003772 if (activeSyncContext.mSyncAdapter != null) {
3773 try {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003774 mLogger.log("Calling cancelSync for runSyncFinishedOrCanceled ",
3775 activeSyncContext, " adapter=", activeSyncContext.mSyncAdapter);
Fred Quintana21bb0de2009-06-16 10:24:58 -07003776 activeSyncContext.mSyncAdapter.cancelSync(activeSyncContext);
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003777 mLogger.log("Canceled");
Fred Quintana718d8a22009-04-29 17:53:20 -07003778 } catch (RemoteException e) {
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003779 mLogger.log("RemoteException ", Log.getStackTraceString(e));
Fred Quintana718d8a22009-04-29 17:53:20 -07003780 // we don't need to retry this in this case
3781 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003782 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07003783 historyMessage = SyncStorageEngine.MESG_CANCELED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003784 downstreamActivity = 0;
3785 upstreamActivity = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003786
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003787 // In the cancel sync case, close it after calling cancelSync().
3788 closeActiveSyncContext(activeSyncContext);
3789 }
Makoto Onuki6a6ae042017-07-20 13:30:12 -07003790
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003791 stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
3792 upstreamActivity, downstreamActivity, elapsedTime);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003793 // Check for full-resync and schedule it after closing off the last sync.
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003794 if (syncResult != null && syncResult.tooManyDeletions) {
3795 installHandleTooManyDeletesNotification(info.account,
3796 info.provider, syncResult.stats.numDeletes,
3797 info.userId);
3798 } else {
Chris Wren282cfef2017-03-27 15:01:44 -04003799 mNotificationMgr.cancelAsUser(
3800 Integer.toString(info.account.hashCode() ^ info.provider.hashCode()),
3801 SystemMessage.NOTE_SYNC_ERROR,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003802 new UserHandle(info.userId));
3803 }
3804 if (syncResult != null && syncResult.fullSyncRequested) {
3805 scheduleSyncOperationH(
3806 new SyncOperation(info.account, info.userId,
3807 syncOperation.owningUid, syncOperation.owningPackage,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003808 syncOperation.reason,
3809 syncOperation.syncSource, info.provider, new Bundle(),
Makoto Onuki61283ec2018-01-31 17:22:36 -08003810 syncOperation.allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -07003811 syncOperation.syncExemptionFlag));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003813 }
3814
Fred Quintana918339a2010-10-05 14:00:39 -07003815 private void closeActiveSyncContext(ActiveSyncContext activeSyncContext) {
3816 activeSyncContext.close();
3817 mActiveSyncContexts.remove(activeSyncContext);
Amith Yamasani04e0d262012-02-14 11:50:53 -08003818 mSyncStorageEngine.removeActiveSync(activeSyncContext.mSyncInfo,
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003819 activeSyncContext.mSyncOperation.target.userId);
Matthew Williams1967c8d2015-06-19 19:03:13 -07003820
3821 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +00003822 Slog.v(TAG, "removing all MESSAGE_MONITOR_SYNC & MESSAGE_SYNC_EXPIRED for "
Matthew Williams1967c8d2015-06-19 19:03:13 -07003823 + activeSyncContext.toString());
3824 }
Matthew Williams1967c8d2015-06-19 19:03:13 -07003825 mSyncHandler.removeMessages(SyncHandler.MESSAGE_MONITOR_SYNC, activeSyncContext);
Makoto Onuki9243d9c2017-08-15 14:56:47 -07003826
3827 mLogger.log("closeActiveSyncContext: ", activeSyncContext);
Fred Quintana918339a2010-10-05 14:00:39 -07003828 }
3829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 /**
3831 * Convert the error-containing SyncResult into the Sync.History error number. Since
3832 * the SyncResult may indicate multiple errors at once, this method just returns the
3833 * most "serious" error.
3834 * @param syncResult the SyncResult from which to read
3835 * @return the most "serious" error set in the SyncResult
3836 * @throws IllegalStateException if the SyncResult does not indicate any errors.
3837 * If SyncResult.error() is true then it is safe to call this.
3838 */
3839 private int syncResultToErrorNumber(SyncResult syncResult) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07003840 if (syncResult.syncAlreadyInProgress)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003841 return ContentResolver.SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003842 if (syncResult.stats.numAuthExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003843 return ContentResolver.SYNC_ERROR_AUTHENTICATION;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003844 if (syncResult.stats.numIoExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003845 return ContentResolver.SYNC_ERROR_IO;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003846 if (syncResult.stats.numParseExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003847 return ContentResolver.SYNC_ERROR_PARSE;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003848 if (syncResult.stats.numConflictDetectedExceptions > 0)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003849 return ContentResolver.SYNC_ERROR_CONFLICT;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003850 if (syncResult.tooManyDeletions)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003851 return ContentResolver.SYNC_ERROR_TOO_MANY_DELETIONS;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003852 if (syncResult.tooManyRetries)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003853 return ContentResolver.SYNC_ERROR_TOO_MANY_RETRIES;
Dianne Hackborn231cc602009-04-27 17:10:36 -07003854 if (syncResult.databaseError)
Fred Quintanaac9385e2009-06-22 18:00:59 -07003855 return ContentResolver.SYNC_ERROR_INTERNAL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003856 throw new IllegalStateException("we are not in an error state, " + syncResult);
3857 }
3858
Fred Quintanad9d2f112009-04-23 13:36:27 -07003859 private void installHandleTooManyDeletesNotification(Account account, String authority,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003860 long numDeletes, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003861 if (mNotificationMgr == null) return;
Fred Quintanac848b702009-08-25 20:18:46 -07003862
3863 final ProviderInfo providerInfo = mContext.getPackageManager().resolveContentProvider(
3864 authority, 0 /* flags */);
3865 if (providerInfo == null) {
3866 return;
3867 }
3868 CharSequence authorityName = providerInfo.loadLabel(mContext.getPackageManager());
3869
Fred Quintanab19e62a2010-12-16 13:54:43 -08003870 Intent clickIntent = new Intent(mContext, SyncActivityTooManyDeletes.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003871 clickIntent.putExtra("account", account);
Tadashi G. Takaoka86135d32009-09-24 19:31:44 -07003872 clickIntent.putExtra("authority", authority);
Fred Quintanac848b702009-08-25 20:18:46 -07003873 clickIntent.putExtra("provider", authorityName.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 clickIntent.putExtra("numDeletes", numDeletes);
3875
3876 if (!isActivityAvailable(clickIntent)) {
3877 Log.w(TAG, "No activity found to handle too many deletes.");
3878 return;
3879 }
3880
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003881 UserHandle user = new UserHandle(userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882 final PendingIntent pendingIntent = PendingIntent
Dianne Hackborn41203752012-08-31 14:05:51 -07003883 .getActivityAsUser(mContext, 0, clickIntent,
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003884 PendingIntent.FLAG_CANCEL_CURRENT, null, user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885
3886 CharSequence tooManyDeletesDescFormat = mContext.getResources().getText(
3887 R.string.contentServiceTooManyDeletesNotificationDesc);
3888
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003889 Context contextForUser = getContextForUser(user);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003890 Notification notification =
3891 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
Chris Wren1ce4b6d2015-06-11 10:19:43 -04003892 .setSmallIcon(R.drawable.stat_notify_sync_error)
3893 .setTicker(mContext.getString(R.string.contentServiceSync))
3894 .setWhen(System.currentTimeMillis())
3895 .setColor(contextForUser.getColor(
3896 com.android.internal.R.color.system_notification_accent_color))
3897 .setContentTitle(contextForUser.getString(
3898 R.string.contentServiceSyncNotificationTitle))
3899 .setContentText(
3900 String.format(tooManyDeletesDescFormat.toString(), authorityName))
3901 .setContentIntent(pendingIntent)
3902 .build();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 notification.flags |= Notification.FLAG_ONGOING_EVENT;
Chris Wren282cfef2017-03-27 15:01:44 -04003904 mNotificationMgr.notifyAsUser(
3905 Integer.toString(account.hashCode() ^ authority.hashCode()),
3906 SystemMessage.NOTE_SYNC_ERROR,
Kenny Guy07ad8dc2014-09-01 20:56:12 +01003907 notification, user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003908 }
3909
3910 /**
3911 * Checks whether an activity exists on the system image for the given intent.
3912 *
3913 * @param intent The intent for an activity.
3914 * @return Whether or not an activity exists.
3915 */
3916 private boolean isActivityAvailable(Intent intent) {
3917 PackageManager pm = mContext.getPackageManager();
3918 List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
3919 int listSize = list.size();
3920 for (int i = 0; i < listSize; i++) {
3921 ResolveInfo resolveInfo = list.get(i);
3922 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
3923 != 0) {
3924 return true;
3925 }
3926 }
3927
3928 return false;
3929 }
3930
3931 public long insertStartSyncEvent(SyncOperation syncOperation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003932 final long now = System.currentTimeMillis();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003933 EventLog.writeEvent(2720,
3934 syncOperation.toEventLog(SyncStorageEngine.EVENT_START));
3935 return mSyncStorageEngine.insertStartSyncEvent(syncOperation, now);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003936 }
3937
3938 public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
Ritesh Reddyae0bcdd2015-12-23 18:24:23 +00003939 int upstreamActivity, int downstreamActivity, long elapsedTime) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003940 EventLog.writeEvent(2720,
3941 syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
Fred Quintana77c560f2010-03-29 22:20:26 -07003942 mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
Fred Quintanac5d1c6d2010-01-27 12:17:49 -08003943 resultMessage, downstreamActivity, upstreamActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003944 }
3945 }
Fred Quintana918339a2010-10-05 14:00:39 -07003946
Matthew Williams8b76d202015-05-03 18:16:25 -07003947 private boolean isSyncStillActiveH(ActiveSyncContext activeSyncContext) {
Fred Quintana918339a2010-10-05 14:00:39 -07003948 for (ActiveSyncContext sync : mActiveSyncContexts) {
3949 if (sync == activeSyncContext) {
3950 return true;
3951 }
3952 }
3953 return false;
3954 }
Alon Albert57286f92012-10-09 14:21:38 -07003955
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003956 /**
3957 * Sync extra comparison function.
3958 * @param b1 bundle to compare
3959 * @param b2 other bundle to compare
3960 * @param includeSyncSettings if false, ignore system settings in bundle.
3961 */
3962 public static boolean syncExtrasEquals(Bundle b1, Bundle b2, boolean includeSyncSettings) {
3963 if (b1 == b2) {
3964 return true;
3965 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003966 // Exit early if we can.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003967 if (includeSyncSettings && b1.size() != b2.size()) {
3968 return false;
3969 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003970 Bundle bigger = b1.size() > b2.size() ? b1 : b2;
3971 Bundle smaller = b1.size() > b2.size() ? b2 : b1;
3972 for (String key : bigger.keySet()) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003973 if (!includeSyncSettings && isSyncSetting(key)) {
3974 continue;
3975 }
Matthew Williams8ef22042013-07-26 12:56:39 -07003976 if (!smaller.containsKey(key)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003977 return false;
3978 }
Matthew Williams9ad2c842015-10-16 12:01:31 -07003979 if (!Objects.equals(bigger.get(key), smaller.get(key))) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07003980 return false;
3981 }
3982 }
3983 return true;
3984 }
3985
3986 /**
3987 * @return true if the provided key is used by the SyncManager in scheduling the sync.
3988 */
3989 private static boolean isSyncSetting(String key) {
3990 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
3991 return true;
3992 }
3993 if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
3994 return true;
3995 }
3996 if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF)) {
3997 return true;
3998 }
3999 if (key.equals(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY)) {
4000 return true;
4001 }
4002 if (key.equals(ContentResolver.SYNC_EXTRAS_MANUAL)) {
4003 return true;
4004 }
4005 if (key.equals(ContentResolver.SYNC_EXTRAS_UPLOAD)) {
4006 return true;
4007 }
4008 if (key.equals(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS)) {
4009 return true;
4010 }
4011 if (key.equals(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS)) {
4012 return true;
4013 }
4014 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD)) {
4015 return true;
4016 }
4017 if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD)) {
4018 return true;
4019 }
4020 if (key.equals(ContentResolver.SYNC_EXTRAS_PRIORITY)) {
4021 return true;
4022 }
4023 if (key.equals(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED)) {
4024 return true;
4025 }
4026 if (key.equals(ContentResolver.SYNC_EXTRAS_INITIALIZE)) {
4027 return true;
4028 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08004029// if (key.equals(ContentResolver.SYNC_EXTRAS_APP_STANDBY_EXEMPTED)) {
4030// return true;
4031// }
4032 // No need to check virtual flags such as SYNC_VIRTUAL_EXTRAS_FORCE_FG_SYNC.
Matthew Williams56dbf8f2013-07-26 12:56:39 -07004033 return false;
4034 }
4035
Alon Albert57286f92012-10-09 14:21:38 -07004036 static class PrintTable {
Makoto Onuki15e7a252017-06-08 17:12:05 -07004037 private ArrayList<String[]> mTable = Lists.newArrayList();
Alon Albert57286f92012-10-09 14:21:38 -07004038 private final int mCols;
4039
4040 PrintTable(int cols) {
4041 mCols = cols;
4042 }
4043
4044 void set(int row, int col, Object... values) {
4045 if (col + values.length > mCols) {
4046 throw new IndexOutOfBoundsException("Table only has " + mCols +
4047 " columns. can't set " + values.length + " at column " + col);
4048 }
4049 for (int i = mTable.size(); i <= row; i++) {
Makoto Onuki15e7a252017-06-08 17:12:05 -07004050 final String[] list = new String[mCols];
Alon Albert57286f92012-10-09 14:21:38 -07004051 mTable.add(list);
4052 for (int j = 0; j < mCols; j++) {
4053 list[j] = "";
4054 }
4055 }
Makoto Onuki15e7a252017-06-08 17:12:05 -07004056 final String[] rowArray = mTable.get(row);
4057 for (int i = 0; i < values.length; i++) {
4058 final Object value = values[i];
4059 rowArray[col + i] = (value == null) ? "" : value.toString();
4060 }
Alon Albert57286f92012-10-09 14:21:38 -07004061 }
4062
4063 void writeTo(PrintWriter out) {
4064 final String[] formats = new String[mCols];
4065 int totalLength = 0;
4066 for (int col = 0; col < mCols; ++col) {
4067 int maxLength = 0;
4068 for (Object[] row : mTable) {
4069 final int length = row[col].toString().length();
4070 if (length > maxLength) {
4071 maxLength = length;
4072 }
4073 }
4074 totalLength += maxLength;
4075 formats[col] = String.format("%%-%ds", maxLength);
4076 }
Patrick Tjin31068162014-01-30 13:28:46 -08004077 formats[mCols - 1] = "%s";
Alon Albert57286f92012-10-09 14:21:38 -07004078 printRow(out, formats, mTable.get(0));
4079 totalLength += (mCols - 1) * 2;
4080 for (int i = 0; i < totalLength; ++i) {
4081 out.print("-");
4082 }
4083 out.println();
4084 for (int i = 1, mTableSize = mTable.size(); i < mTableSize; i++) {
4085 Object[] row = mTable.get(i);
4086 printRow(out, formats, row);
4087 }
4088 }
4089
4090 private void printRow(PrintWriter out, String[] formats, Object[] row) {
4091 for (int j = 0, rowLength = row.length; j < rowLength; j++) {
4092 out.printf(String.format(formats[j], row[j].toString()));
4093 out.print(" ");
4094 }
4095 out.println();
4096 }
4097
4098 public int getNumRows() {
4099 return mTable.size();
4100 }
4101 }
Kenny Guy07ad8dc2014-09-01 20:56:12 +01004102
4103 private Context getContextForUser(UserHandle user) {
4104 try {
4105 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
4106 } catch (NameNotFoundException e) {
4107 // Default to mContext, not finding the package system is running as is unlikely.
4108 return mContext;
4109 }
4110 }
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004111
4112 private void cancelJob(SyncOperation op, String why) {
4113 if (op == null) {
4114 Slog.wtf(TAG, "Null sync operation detected.");
4115 return;
4116 }
4117 if (op.isPeriodic) {
4118 mLogger.log("Removing periodic sync ", op, " for ", why);
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004119 }
4120 getJobScheduler().cancel(op.jobId);
4121 }
4122
Makoto Onukidd4b14f2017-08-17 14:03:48 -07004123 private void wtfWithLog(String message) {
4124 Slog.wtf(TAG, message);
4125 mLogger.log("WTF: ", message);
4126 }
Makoto Onuki94986212018-04-11 16:24:46 -07004127
4128 public void resetTodayStats() {
4129 mSyncStorageEngine.resetTodayStats(/*force=*/ true);
4130 }
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004131}