blob: 25edf40706895537e431cf5202e14092b66f2832 [file] [log] [blame]
Kenny Root15a4d2f2010-03-11 18:20:12 -08001/*
2 * Copyright (C) 2010 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;
Fred Quintana307da1a2010-01-21 14:24:20 -080018
19import android.accounts.Account;
Dianne Hackborn1085ff62016-02-23 17:04:58 -080020import android.app.job.JobInfo;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080021import android.content.ContentResolver;
Makoto Onuki75ad2492018-03-28 14:42:42 -070022import android.content.ContentResolver.SyncExemption;
Makoto Onuki15e7a252017-06-08 17:12:05 -070023import android.content.pm.PackageManager;
Fred Quintana307da1a2010-01-21 14:24:20 -080024import android.os.Bundle;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000025import android.os.PersistableBundle;
Makoto Onuki15e7a252017-06-08 17:12:05 -070026import android.os.SystemClock;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -070027import android.os.UserHandle;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000028import android.util.Slog;
Fred Quintana307da1a2010-01-21 14:24:20 -080029
30/**
31 * Value type that represents a sync operation.
Shreyas Basarge8c834c02016-01-07 13:53:16 +000032 * This holds all information related to a sync operation - both one off and periodic.
33 * Data stored in this is used to schedule a job with the JobScheduler.
Matthew Williamsfa774182013-06-18 15:44:11 -070034 * {@hide}
Fred Quintana307da1a2010-01-21 14:24:20 -080035 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +000036public class SyncOperation {
Matthew Williams56dbf8f2013-07-26 12:56:39 -070037 public static final String TAG = "SyncManager";
38
Shreyas Basarge8c834c02016-01-07 13:53:16 +000039 /**
40 * This is used in the {@link #sourcePeriodicId} field if the operation is not initiated by a failed
41 * periodic sync.
42 */
43 public static final int NO_JOB_ID = -1;
44
Alon Albert57286f92012-10-09 14:21:38 -070045 public static final int REASON_BACKGROUND_DATA_SETTINGS_CHANGED = -1;
46 public static final int REASON_ACCOUNTS_UPDATED = -2;
47 public static final int REASON_SERVICE_CHANGED = -3;
48 public static final int REASON_PERIODIC = -4;
Matthew Williams56dbf8f2013-07-26 12:56:39 -070049 /** Sync started because it has just been set to isSyncable. */
Alon Albert57286f92012-10-09 14:21:38 -070050 public static final int REASON_IS_SYNCABLE = -5;
Matthew Williamsfa774182013-06-18 15:44:11 -070051 /** Sync started because it has just been set to sync automatically. */
Alon Albert57286f92012-10-09 14:21:38 -070052 public static final int REASON_SYNC_AUTO = -6;
Matthew Williamsfa774182013-06-18 15:44:11 -070053 /** Sync started because master sync automatically has been set to true. */
Alon Albert57286f92012-10-09 14:21:38 -070054 public static final int REASON_MASTER_SYNC_AUTO = -7;
55 public static final int REASON_USER_START = -8;
56
57 private static String[] REASON_NAMES = new String[] {
58 "DataSettingsChanged",
59 "AccountsUpdated",
60 "ServiceChanged",
61 "Periodic",
62 "IsSyncable",
63 "AutoSync",
64 "MasterSyncAuto",
65 "UserStart",
66 };
67
Matthew Williams8ef22042013-07-26 12:56:39 -070068 /** Identifying info for the target for this operation. */
Matthew Williams56dbf8f2013-07-26 12:56:39 -070069 public final SyncStorageEngine.EndPoint target;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -070070 public final int owningUid;
71 public final String owningPackage;
Matthew Williams56dbf8f2013-07-26 12:56:39 -070072 /** Why this sync was kicked off. {@link #REASON_NAMES} */
Alon Albert57286f92012-10-09 14:21:38 -070073 public final int reason;
Matthew Williams56dbf8f2013-07-26 12:56:39 -070074 /** Where this sync was initiated. */
Matthew Williams64280462014-01-09 10:49:23 -080075 public final int syncSource;
Fred Quintana0c4d04a2010-11-03 17:02:55 -070076 public final boolean allowParallelSyncs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000077 public final Bundle extras;
78 public final boolean isPeriodic;
79 /** jobId of the periodic SyncOperation that initiated this one */
80 public final int sourcePeriodicId;
81 /** Operations are considered duplicates if keys are equal */
Fred Quintana307da1a2010-01-21 14:24:20 -080082 public final String key;
Fred Quintana307da1a2010-01-21 14:24:20 -080083
Shreyas Basarge8c834c02016-01-07 13:53:16 +000084 /** Poll frequency of periodic sync in milliseconds */
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +000085 public final long periodMillis;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000086 /** Flex time of periodic sync in milliseconds */
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +000087 public final long flexMillis;
Dianne Hackbornd45665b2014-02-26 12:35:32 -080088 /** Descriptive string key for this operation */
89 public String wakeLockName;
Shreyas Basarge8c834c02016-01-07 13:53:16 +000090 /**
91 * Used when duplicate pending syncs are present. The one with the lowest expectedRuntime
92 * is kept, others are discarded.
93 */
94 public long expectedRuntime;
Dianne Hackbornd45665b2014-02-26 12:35:32 -080095
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +000096 /** Stores the number of times this sync operation failed and had to be retried. */
97 int retries;
98
Shreyas Basarge8c834c02016-01-07 13:53:16 +000099 /** jobId of the JobScheduler job corresponding to this sync */
100 public int jobId;
Amith Yamasani96a0fd652015-04-10 16:16:30 -0700101
Makoto Onuki75ad2492018-03-28 14:42:42 -0700102 @SyncExemption
103 public int syncExemptionFlag;
Makoto Onuki61283ec2018-01-31 17:22:36 -0800104
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700105 public SyncOperation(Account account, int userId, int owningUid, String owningPackage,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000106 int reason, int source, String provider, Bundle extras,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700107 boolean allowParallelSyncs, @SyncExemption int syncExemptionFlag) {
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700108 this(new SyncStorageEngine.EndPoint(account, provider, userId), owningUid, owningPackage,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700109 reason, source, extras, allowParallelSyncs, syncExemptionFlag);
Matthew Williams64280462014-01-09 10:49:23 -0800110 }
111
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700112 private SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800113 int reason, int source, Bundle extras, boolean allowParallelSyncs,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700114 @SyncExemption int syncExemptionFlag) {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000115 this(info, owningUid, owningPackage, reason, source, extras, allowParallelSyncs, false,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700116 NO_JOB_ID, 0, 0, syncExemptionFlag);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000117 }
118
119 public SyncOperation(SyncOperation op, long periodMillis, long flexMillis) {
120 this(op.target, op.owningUid, op.owningPackage, op.reason, op.syncSource,
121 new Bundle(op.extras), op.allowParallelSyncs, op.isPeriodic, op.sourcePeriodicId,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700122 periodMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000123 }
124
125 public SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
126 int reason, int source, Bundle extras, boolean allowParallelSyncs,
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000127 boolean isPeriodic, int sourcePeriodicId, long periodMillis,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700128 long flexMillis, @SyncExemption int syncExemptionFlag) {
Matthew Williams64280462014-01-09 10:49:23 -0800129 this.target = info;
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700130 this.owningUid = owningUid;
131 this.owningPackage = owningPackage;
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700132 this.reason = reason;
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700133 this.syncSource = source;
Fred Quintana307da1a2010-01-21 14:24:20 -0800134 this.extras = new Bundle(extras);
Matthew Williams64280462014-01-09 10:49:23 -0800135 this.allowParallelSyncs = allowParallelSyncs;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000136 this.isPeriodic = isPeriodic;
137 this.sourcePeriodicId = sourcePeriodicId;
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000138 this.periodMillis = periodMillis;
139 this.flexMillis = flexMillis;
140 this.jobId = NO_JOB_ID;
141 this.key = toKey();
Makoto Onuki75ad2492018-03-28 14:42:42 -0700142 this.syncExemptionFlag = syncExemptionFlag;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000143 }
144
145 /* Get a one off sync operation instance from a periodic sync. */
146 public SyncOperation createOneTimeSyncOperation() {
147 if (!isPeriodic) {
148 return null;
Fred Quintana307da1a2010-01-21 14:24:20 -0800149 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000150 SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, syncSource,
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000151 new Bundle(extras), allowParallelSyncs, false, jobId /* sourcePeriodicId */,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700152 periodMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000153 return op;
Fred Quintana307da1a2010-01-21 14:24:20 -0800154 }
155
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000156 public SyncOperation(SyncOperation other) {
157 target = other.target;
158 owningUid = other.owningUid;
159 owningPackage = other.owningPackage;
160 reason = other.reason;
161 syncSource = other.syncSource;
162 allowParallelSyncs = other.allowParallelSyncs;
163 extras = new Bundle(other.extras);
164 wakeLockName = other.wakeLockName();
165 isPeriodic = other.isPeriodic;
166 sourcePeriodicId = other.sourcePeriodicId;
167 periodMillis = other.periodMillis;
168 flexMillis = other.flexMillis;
169 this.key = other.key;
Makoto Onuki75ad2492018-03-28 14:42:42 -0700170 syncExemptionFlag = other.syncExemptionFlag;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000171 }
172
173 /**
174 * All fields are stored in a corresponding key in the persistable bundle.
175 *
176 * {@link #extras} is a Bundle and can contain parcelable objects. But only the type Account
177 * is allowed {@link ContentResolver#validateSyncExtrasBundle(Bundle)} that can't be stored in
178 * a PersistableBundle. For every value of type Account with key 'key', we store a
179 * PersistableBundle containing account information at key 'ACCOUNT:key'. The Account object
180 * can be reconstructed using this.
181 *
182 * We put a flag with key 'SyncManagerJob', to identify while reconstructing a sync operation
183 * from a bundle whether the bundle actually contains information about a sync.
184 * @return A persistable bundle containing all information to re-construct the sync operation.
185 */
186 PersistableBundle toJobInfoExtras() {
187 // This will be passed as extras bundle to a JobScheduler job.
188 PersistableBundle jobInfoExtras = new PersistableBundle();
189
190 PersistableBundle syncExtrasBundle = new PersistableBundle();
191 for (String key: extras.keySet()) {
192 Object value = extras.get(key);
193 if (value instanceof Account) {
194 Account account = (Account) value;
195 PersistableBundle accountBundle = new PersistableBundle();
196 accountBundle.putString("accountName", account.name);
197 accountBundle.putString("accountType", account.type);
198 // This is stored in jobInfoExtras so that we don't override a user specified
199 // sync extra with the same key.
200 jobInfoExtras.putPersistableBundle("ACCOUNT:" + key, accountBundle);
201 } else if (value instanceof Long) {
202 syncExtrasBundle.putLong(key, (Long) value);
203 } else if (value instanceof Integer) {
204 syncExtrasBundle.putInt(key, (Integer) value);
205 } else if (value instanceof Boolean) {
206 syncExtrasBundle.putBoolean(key, (Boolean) value);
207 } else if (value instanceof Float) {
Shreyas Basargeace6f6d2016-06-24 18:45:51 +0100208 syncExtrasBundle.putDouble(key, (double) (float) value);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000209 } else if (value instanceof Double) {
210 syncExtrasBundle.putDouble(key, (Double) value);
211 } else if (value instanceof String) {
212 syncExtrasBundle.putString(key, (String) value);
213 } else if (value == null) {
214 syncExtrasBundle.putString(key, null);
215 } else {
216 Slog.e(TAG, "Unknown extra type.");
217 }
218 }
219 jobInfoExtras.putPersistableBundle("syncExtras", syncExtrasBundle);
220
221 jobInfoExtras.putBoolean("SyncManagerJob", true);
222
223 jobInfoExtras.putString("provider", target.provider);
224 jobInfoExtras.putString("accountName", target.account.name);
225 jobInfoExtras.putString("accountType", target.account.type);
226 jobInfoExtras.putInt("userId", target.userId);
227 jobInfoExtras.putInt("owningUid", owningUid);
228 jobInfoExtras.putString("owningPackage", owningPackage);
229 jobInfoExtras.putInt("reason", reason);
230 jobInfoExtras.putInt("source", syncSource);
231 jobInfoExtras.putBoolean("allowParallelSyncs", allowParallelSyncs);
232 jobInfoExtras.putInt("jobId", jobId);
233 jobInfoExtras.putBoolean("isPeriodic", isPeriodic);
234 jobInfoExtras.putInt("sourcePeriodicId", sourcePeriodicId);
235 jobInfoExtras.putLong("periodMillis", periodMillis);
236 jobInfoExtras.putLong("flexMillis", flexMillis);
237 jobInfoExtras.putLong("expectedRuntime", expectedRuntime);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000238 jobInfoExtras.putInt("retries", retries);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700239 jobInfoExtras.putInt("syncExemptionFlag", syncExemptionFlag);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000240 return jobInfoExtras;
241 }
242
243 /**
244 * Reconstructs a sync operation from an extras Bundle. Returns null if the bundle doesn't
245 * contain a valid sync operation.
246 */
247 static SyncOperation maybeCreateFromJobExtras(PersistableBundle jobExtras) {
Makoto Onukia9dca242017-06-21 17:06:49 -0700248 if (jobExtras == null) {
249 return null;
250 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000251 String accountName, accountType;
252 String provider;
253 int userId, owningUid;
254 String owningPackage;
255 int reason, source;
256 int initiatedBy;
257 Bundle extras;
258 boolean allowParallelSyncs, isPeriodic;
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000259 long periodMillis, flexMillis;
Makoto Onuki75ad2492018-03-28 14:42:42 -0700260 int syncExemptionFlag;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000261
262 if (!jobExtras.getBoolean("SyncManagerJob", false)) {
263 return null;
264 }
265
266 accountName = jobExtras.getString("accountName");
267 accountType = jobExtras.getString("accountType");
268 provider = jobExtras.getString("provider");
269 userId = jobExtras.getInt("userId", Integer.MAX_VALUE);
270 owningUid = jobExtras.getInt("owningUid");
271 owningPackage = jobExtras.getString("owningPackage");
272 reason = jobExtras.getInt("reason", Integer.MAX_VALUE);
273 source = jobExtras.getInt("source", Integer.MAX_VALUE);
274 allowParallelSyncs = jobExtras.getBoolean("allowParallelSyncs", false);
275 isPeriodic = jobExtras.getBoolean("isPeriodic", false);
276 initiatedBy = jobExtras.getInt("sourcePeriodicId", NO_JOB_ID);
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000277 periodMillis = jobExtras.getLong("periodMillis");
278 flexMillis = jobExtras.getLong("flexMillis");
Makoto Onuki75ad2492018-03-28 14:42:42 -0700279 syncExemptionFlag = jobExtras.getInt("syncExemptionFlag",
280 ContentResolver.SYNC_EXEMPTION_NONE);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000281 extras = new Bundle();
282
283 PersistableBundle syncExtras = jobExtras.getPersistableBundle("syncExtras");
284 if (syncExtras != null) {
285 extras.putAll(syncExtras);
286 }
287
288 for (String key: jobExtras.keySet()) {
289 if (key!= null && key.startsWith("ACCOUNT:")) {
290 String newKey = key.substring(8); // Strip off the 'ACCOUNT:' prefix.
291 PersistableBundle accountsBundle = jobExtras.getPersistableBundle(key);
292 Account account = new Account(accountsBundle.getString("accountName"),
293 accountsBundle.getString("accountType"));
294 extras.putParcelable(newKey, account);
295 }
296 }
297
298 Account account = new Account(accountName, accountType);
299 SyncStorageEngine.EndPoint target =
300 new SyncStorageEngine.EndPoint(account, provider, userId);
301 SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, source,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800302 extras, allowParallelSyncs, isPeriodic, initiatedBy, periodMillis, flexMillis,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700303 syncExemptionFlag);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000304 op.jobId = jobExtras.getInt("jobId");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000305 op.expectedRuntime = jobExtras.getLong("expectedRuntime");
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000306 op.retries = jobExtras.getInt("retries");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000307 return op;
Matthew Williamsfa774182013-06-18 15:44:11 -0700308 }
309
310 /**
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700311 * Determine whether if this sync operation is running, the provided operation would conflict
312 * with it.
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000313 * Parallel syncs allow multiple accounts to be synced at the same time.
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700314 */
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000315 boolean isConflict(SyncOperation toRun) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700316 final SyncStorageEngine.EndPoint other = toRun.target;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000317 return target.account.type.equals(other.account.type)
318 && target.provider.equals(other.provider)
319 && target.userId == other.userId
320 && (!allowParallelSyncs
321 || target.account.name.equals(other.account.name));
322 }
323
324 boolean isReasonPeriodic() {
325 return reason == REASON_PERIODIC;
326 }
327
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000328 boolean matchesPeriodicOperation(SyncOperation other) {
329 return target.matchesSpec(other.target)
330 && SyncManager.syncExtrasEquals(extras, other.extras, true)
331 && periodMillis == other.periodMillis && flexMillis == other.flexMillis;
332 }
333
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000334 boolean isDerivedFromFailedPeriodicSync() {
335 return sourcePeriodicId != NO_JOB_ID;
336 }
337
338 int findPriority() {
339 if (isInitialization()) {
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800340 return JobInfo.PRIORITY_SYNC_INITIALIZATION;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000341 } else if (isExpedited()) {
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800342 return JobInfo.PRIORITY_SYNC_EXPEDITED;
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700343 }
Dianne Hackborn1085ff62016-02-23 17:04:58 -0800344 return JobInfo.PRIORITY_DEFAULT;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000345 }
346
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000347 private String toKey() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000348 StringBuilder sb = new StringBuilder();
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000349 sb.append("provider: ").append(target.provider);
350 sb.append(" account {name=" + target.account.name
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000351 + ", user="
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000352 + target.userId
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000353 + ", type="
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000354 + target.account.type
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000355 + "}");
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000356 sb.append(" isPeriodic: ").append(isPeriodic);
357 sb.append(" period: ").append(periodMillis);
358 sb.append(" flex: ").append(flexMillis);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000359 sb.append(" extras: ");
360 extrasToStringBuilder(extras, sb);
361 return sb.toString();
Fred Quintana307da1a2010-01-21 14:24:20 -0800362 }
363
Matthew Williamsfa774182013-06-18 15:44:11 -0700364 @Override
Fred Quintana307da1a2010-01-21 14:24:20 -0800365 public String toString() {
Makoto Onuki75ad2492018-03-28 14:42:42 -0700366 return dump(null, true, null);
Fred Quintana918339a2010-10-05 14:00:39 -0700367 }
368
Makoto Onuki75ad2492018-03-28 14:42:42 -0700369 String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700370 StringBuilder sb = new StringBuilder();
Makoto Onuki15e7a252017-06-08 17:12:05 -0700371 sb.append("JobId=").append(jobId)
372 .append(" ")
Shreyas Basarge2b4c8f92016-02-08 23:52:27 +0000373 .append(target.account.name)
Makoto Onuki15e7a252017-06-08 17:12:05 -0700374 .append("/")
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700375 .append(target.account.type)
Makoto Onuki15e7a252017-06-08 17:12:05 -0700376 .append(" u")
377 .append(target.userId)
378 .append(" [")
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700379 .append(target.provider)
Makoto Onuki15e7a252017-06-08 17:12:05 -0700380 .append("] ");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000381 sb.append(SyncStorageEngine.SOURCES[syncSource]);
Makoto Onuki15e7a252017-06-08 17:12:05 -0700382 if (expectedRuntime != 0) {
383 sb.append(" ExpectedIn=");
384 SyncManager.formatDurationHMS(sb,
385 (expectedRuntime - SystemClock.elapsedRealtime()));
Fred Quintana918339a2010-10-05 14:00:39 -0700386 }
Makoto Onuki15e7a252017-06-08 17:12:05 -0700387 if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
388 sb.append(" EXPEDITED");
389 }
Makoto Onuki75ad2492018-03-28 14:42:42 -0700390 switch (syncExemptionFlag) {
391 case ContentResolver.SYNC_EXEMPTION_NONE:
392 break;
Makoto Onukid5f25d22018-05-22 16:02:17 -0700393 case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET:
Makoto Onuki75ad2492018-03-28 14:42:42 -0700394 sb.append(" STANDBY-EXEMPTED");
395 break;
Makoto Onukid5f25d22018-05-22 16:02:17 -0700396 case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP:
Makoto Onuki75ad2492018-03-28 14:42:42 -0700397 sb.append(" STANDBY-EXEMPTED(TOP)");
398 break;
399 default:
400 sb.append(" ExemptionFlag=" + syncExemptionFlag);
401 break;
Makoto Onuki61283ec2018-01-31 17:22:36 -0800402 }
Makoto Onuki15e7a252017-06-08 17:12:05 -0700403 sb.append(" Reason=");
Alon Albert57286f92012-10-09 14:21:38 -0700404 sb.append(reasonToString(pm, reason));
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000405 if (isPeriodic) {
Makoto Onuki15e7a252017-06-08 17:12:05 -0700406 sb.append(" (period=");
407 SyncManager.formatDurationHMS(sb, periodMillis);
408 sb.append(" flex=");
409 SyncManager.formatDurationHMS(sb, flexMillis);
410 sb.append(")");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000411 }
Makoto Onuki75ad2492018-03-28 14:42:42 -0700412 if (retries > 0) {
413 sb.append(" Retries=");
414 sb.append(retries);
415 }
Makoto Onuki15e7a252017-06-08 17:12:05 -0700416 if (!shorter) {
417 sb.append(" Owner={");
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700418 UserHandle.formatUid(sb, owningUid);
Makoto Onuki15e7a252017-06-08 17:12:05 -0700419 sb.append(" ");
Dianne Hackbornbef28fe2015-10-29 17:57:11 -0700420 sb.append(owningPackage);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700421 if (appStates != null) {
422 sb.append(" [");
423 sb.append(appStates.getStandbyBucket(
424 UserHandle.getUserId(owningUid), owningPackage));
425 sb.append("]");
426
427 if (appStates.isAppActive(owningUid)) {
428 sb.append(" [ACTIVE]");
429 }
430 }
Makoto Onuki15e7a252017-06-08 17:12:05 -0700431 sb.append("}");
432 if (!extras.keySet().isEmpty()) {
433 sb.append(" ");
434 extrasToStringBuilder(extras, sb);
435 }
Fred Quintana918339a2010-10-05 14:00:39 -0700436 }
Fred Quintana307da1a2010-01-21 14:24:20 -0800437 return sb.toString();
438 }
439
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000440 static String reasonToString(PackageManager pm, int reason) {
Alon Albert57286f92012-10-09 14:21:38 -0700441 if (reason >= 0) {
442 if (pm != null) {
443 final String[] packages = pm.getPackagesForUid(reason);
444 if (packages != null && packages.length == 1) {
445 return packages[0];
446 }
447 final String name = pm.getNameForUid(reason);
448 if (name != null) {
449 return name;
450 }
451 return String.valueOf(reason);
452 } else {
453 return String.valueOf(reason);
454 }
455 } else {
456 final int index = -reason - 1;
457 if (index >= REASON_NAMES.length) {
458 return String.valueOf(reason);
459 } else {
460 return REASON_NAMES[index];
461 }
462 }
463 }
464
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000465 boolean isInitialization() {
Fred Quintana918339a2010-10-05 14:00:39 -0700466 return extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
467 }
468
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000469 boolean isExpedited() {
470 return extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
Fred Quintanadc475562012-05-04 15:51:54 -0700471 }
472
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000473 boolean ignoreBackoff() {
Fred Quintana918339a2010-10-05 14:00:39 -0700474 return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false);
475 }
476
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000477 boolean isNotAllowedOnMetered() {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700478 return extras.getBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, false);
479 }
480
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000481 boolean isManual() {
Matthew Williams92a1c092014-08-25 19:18:32 -0700482 return extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
483 }
484
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000485 boolean isIgnoreSettings() {
Matthew Williams92a1c092014-08-25 19:18:32 -0700486 return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
487 }
488
Makoto Onuki75ad2492018-03-28 14:42:42 -0700489 boolean isAppStandbyExempted() {
490 return syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE;
491 }
492
Makoto Onuki15e7a252017-06-08 17:12:05 -0700493 static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
Makoto Onukia9dca242017-06-21 17:06:49 -0700494 if (bundle == null) {
495 sb.append("null");
496 return;
497 }
Fred Quintana307da1a2010-01-21 14:24:20 -0800498 sb.append("[");
499 for (String key : bundle.keySet()) {
Fred Quintana307da1a2010-01-21 14:24:20 -0800500 sb.append(key).append("=").append(bundle.get(key)).append(" ");
501 }
502 sb.append("]");
503 }
504
Makoto Onukia9dca242017-06-21 17:06:49 -0700505 static String extrasToString(Bundle bundle) {
506 final StringBuilder sb = new StringBuilder();
507 extrasToStringBuilder(bundle, sb);
508 return sb.toString();
509 }
510
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000511 String wakeLockName() {
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800512 if (wakeLockName != null) {
513 return wakeLockName;
514 }
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000515 return (wakeLockName = target.provider
516 + "/" + target.account.type
517 + "/" + target.account.name);
Fred Quintana307da1a2010-01-21 14:24:20 -0800518 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700519
520 // TODO: Test this to make sure that casting to object doesn't lose the type info for EventLog.
521 public Object[] toEventLog(int event) {
522 Object[] logArray = new Object[4];
523 logArray[1] = event;
524 logArray[2] = syncSource;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000525 logArray[0] = target.provider;
526 logArray[3] = target.account.name.hashCode();
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700527 return logArray;
528 }
Fred Quintana307da1a2010-01-21 14:24:20 -0800529}