blob: ded11cfd82ef317fd2c0c951c43dd0c0549e427d [file] [log] [blame]
Dianne Hackborn231cc602009-04-27 17:10:36 -07001/*
2 * Copyright (C) 2009 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
17package android.content;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.util.Log;
22
Fred Quintanac5d1c6d2010-01-27 12:17:49 -080023import java.util.ArrayList;
Makoto Onuki94986212018-04-11 16:24:46 -070024import java.util.Calendar;
25import java.util.GregorianCalendar;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -080026
Dianne Hackborn231cc602009-04-27 17:10:36 -070027/** @hide */
28public class SyncStatusInfo implements Parcelable {
Makoto Onuki15e7a252017-06-08 17:12:05 -070029 private static final String TAG = "Sync";
30
Makoto Onuki94986212018-04-11 16:24:46 -070031 static final int VERSION = 5;
Makoto Onuki15e7a252017-06-08 17:12:05 -070032
33 private static final int MAX_EVENT_COUNT = 10;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -080034
Dianne Hackborn231cc602009-04-27 17:10:36 -070035 public final int authorityId;
Makoto Onuki94986212018-04-11 16:24:46 -070036
37 /**
38 * # of syncs for each sync source, etc.
39 */
40 public static class Stats {
41 public long totalElapsedTime;
42 public int numSyncs;
43 public int numSourcePoll;
44 public int numSourceOther;
45 public int numSourceLocal;
46 public int numSourceUser;
47 public int numSourcePeriodic;
48 public int numSourceFeed;
49 public int numFailures;
50 public int numCancels;
51
52 /** Copy all the stats to another instance. */
53 public void copyTo(Stats to) {
54 to.totalElapsedTime = totalElapsedTime;
55 to.numSyncs = numSyncs;
56 to.numSourcePoll = numSourcePoll;
57 to.numSourceOther = numSourceOther;
58 to.numSourceLocal = numSourceLocal;
59 to.numSourceUser = numSourceUser;
60 to.numSourcePeriodic = numSourcePeriodic;
61 to.numSourceFeed = numSourceFeed;
62 to.numFailures = numFailures;
63 to.numCancels = numCancels;
64 }
65
66 /** Clear all the stats. */
67 public void clear() {
68 totalElapsedTime = 0;
69 numSyncs = 0;
70 numSourcePoll = 0;
71 numSourceOther = 0;
72 numSourceLocal = 0;
73 numSourceUser = 0;
74 numSourcePeriodic = 0;
75 numSourceFeed = 0;
76 numFailures = 0;
77 numCancels = 0;
78 }
79
80 /** Write all the stats to a parcel. */
81 public void writeToParcel(Parcel parcel) {
82 parcel.writeLong(totalElapsedTime);
83 parcel.writeInt(numSyncs);
84 parcel.writeInt(numSourcePoll);
85 parcel.writeInt(numSourceOther);
86 parcel.writeInt(numSourceLocal);
87 parcel.writeInt(numSourceUser);
88 parcel.writeInt(numSourcePeriodic);
89 parcel.writeInt(numSourceFeed);
90 parcel.writeInt(numFailures);
91 parcel.writeInt(numCancels);
92 }
93
94 /** Read all the stats from a parcel. */
95 public void readFromParcel(Parcel parcel) {
96 totalElapsedTime = parcel.readLong();
97 numSyncs = parcel.readInt();
98 numSourcePoll = parcel.readInt();
99 numSourceOther = parcel.readInt();
100 numSourceLocal = parcel.readInt();
101 numSourceUser = parcel.readInt();
102 numSourcePeriodic = parcel.readInt();
103 numSourceFeed = parcel.readInt();
104 numFailures = parcel.readInt();
105 numCancels = parcel.readInt();
106 }
107 }
108
109 public long lastTodayResetTime;
110
111 public final Stats totalStats = new Stats();
112 public final Stats todayStats = new Stats();
113 public final Stats yesterdayStats = new Stats();
114
Dianne Hackborn231cc602009-04-27 17:10:36 -0700115 public long lastSuccessTime;
116 public int lastSuccessSource;
117 public long lastFailureTime;
118 public int lastFailureSource;
119 public String lastFailureMesg;
120 public long initialFailureTime;
121 public boolean pending;
Costin Manolache5ed64cd2009-09-22 14:41:46 -0700122 public boolean initialize;
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700123
124 // Warning: It is up to the external caller to ensure there are
125 // no race conditions when accessing this list
126 private ArrayList<Long> periodicSyncTimes;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800127
Makoto Onuki15e7a252017-06-08 17:12:05 -0700128 private final ArrayList<Long> mLastEventTimes = new ArrayList<>();
129 private final ArrayList<String> mLastEvents = new ArrayList<>();
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800130
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800131 public SyncStatusInfo(int authorityId) {
Dianne Hackborn231cc602009-04-27 17:10:36 -0700132 this.authorityId = authorityId;
133 }
134
135 public int getLastFailureMesgAsInt(int def) {
Alon Albert5c113fa2013-02-07 08:07:32 -0800136 final int i = ContentResolver.syncErrorStringToInt(lastFailureMesg);
137 if (i > 0) {
138 return i;
139 } else {
140 Log.d(TAG, "Unknown lastFailureMesg:" + lastFailureMesg);
141 return def;
Dianne Hackborn231cc602009-04-27 17:10:36 -0700142 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700143 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800144
Dianne Hackborn231cc602009-04-27 17:10:36 -0700145 public int describeContents() {
146 return 0;
147 }
148
149 public void writeToParcel(Parcel parcel, int flags) {
150 parcel.writeInt(VERSION);
151 parcel.writeInt(authorityId);
Makoto Onuki94986212018-04-11 16:24:46 -0700152
153 // Note we can't use Stats.writeToParcel() here; see the below constructor for the reason.
154 parcel.writeLong(totalStats.totalElapsedTime);
155 parcel.writeInt(totalStats.numSyncs);
156 parcel.writeInt(totalStats.numSourcePoll);
157 parcel.writeInt(totalStats.numSourceOther);
158 parcel.writeInt(totalStats.numSourceLocal);
159 parcel.writeInt(totalStats.numSourceUser);
160
Dianne Hackborn231cc602009-04-27 17:10:36 -0700161 parcel.writeLong(lastSuccessTime);
162 parcel.writeInt(lastSuccessSource);
163 parcel.writeLong(lastFailureTime);
164 parcel.writeInt(lastFailureSource);
165 parcel.writeString(lastFailureMesg);
166 parcel.writeLong(initialFailureTime);
167 parcel.writeInt(pending ? 1 : 0);
Costin Manolache5ed64cd2009-09-22 14:41:46 -0700168 parcel.writeInt(initialize ? 1 : 0);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800169 if (periodicSyncTimes != null) {
170 parcel.writeInt(periodicSyncTimes.size());
171 for (long periodicSyncTime : periodicSyncTimes) {
172 parcel.writeLong(periodicSyncTime);
173 }
174 } else {
175 parcel.writeInt(-1);
176 }
Makoto Onuki15e7a252017-06-08 17:12:05 -0700177 parcel.writeInt(mLastEventTimes.size());
178 for (int i = 0; i < mLastEventTimes.size(); i++) {
179 parcel.writeLong(mLastEventTimes.get(i));
180 parcel.writeString(mLastEvents.get(i));
181 }
Makoto Onuki94986212018-04-11 16:24:46 -0700182 // Version 4
183 parcel.writeInt(totalStats.numSourcePeriodic);
184
185 // Version 5
186 parcel.writeInt(totalStats.numSourceFeed);
187 parcel.writeInt(totalStats.numFailures);
188 parcel.writeInt(totalStats.numCancels);
189
190 parcel.writeLong(lastTodayResetTime);
191
192 todayStats.writeToParcel(parcel);
193 yesterdayStats.writeToParcel(parcel);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700194 }
195
Jeff Sharkey7a96c392012-11-15 14:01:46 -0800196 public SyncStatusInfo(Parcel parcel) {
Dianne Hackborn231cc602009-04-27 17:10:36 -0700197 int version = parcel.readInt();
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800198 if (version != VERSION && version != 1) {
Dianne Hackborn231cc602009-04-27 17:10:36 -0700199 Log.w("SyncStatusInfo", "Unknown version: " + version);
200 }
201 authorityId = parcel.readInt();
Makoto Onuki94986212018-04-11 16:24:46 -0700202
203 // Note we can't use Stats.writeToParcel() here because the data is persisted and we need
204 // to be able to read from the old format too.
205 totalStats.totalElapsedTime = parcel.readLong();
206 totalStats.numSyncs = parcel.readInt();
207 totalStats.numSourcePoll = parcel.readInt();
208 totalStats.numSourceOther = parcel.readInt();
209 totalStats.numSourceLocal = parcel.readInt();
210 totalStats.numSourceUser = parcel.readInt();
Dianne Hackborn231cc602009-04-27 17:10:36 -0700211 lastSuccessTime = parcel.readLong();
212 lastSuccessSource = parcel.readInt();
213 lastFailureTime = parcel.readLong();
214 lastFailureSource = parcel.readInt();
215 lastFailureMesg = parcel.readString();
216 initialFailureTime = parcel.readLong();
217 pending = parcel.readInt() != 0;
Costin Manolache5ed64cd2009-09-22 14:41:46 -0700218 initialize = parcel.readInt() != 0;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800219 if (version == 1) {
220 periodicSyncTimes = null;
221 } else {
Makoto Onuki15e7a252017-06-08 17:12:05 -0700222 final int count = parcel.readInt();
223 if (count < 0) {
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800224 periodicSyncTimes = null;
225 } else {
226 periodicSyncTimes = new ArrayList<Long>();
Makoto Onuki15e7a252017-06-08 17:12:05 -0700227 for (int i = 0; i < count; i++) {
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800228 periodicSyncTimes.add(parcel.readLong());
229 }
230 }
Makoto Onuki15e7a252017-06-08 17:12:05 -0700231 if (version >= 3) {
232 mLastEventTimes.clear();
233 mLastEvents.clear();
234 final int nEvents = parcel.readInt();
235 for (int i = 0; i < nEvents; i++) {
236 mLastEventTimes.add(parcel.readLong());
237 mLastEvents.add(parcel.readString());
238 }
239 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800240 }
Makoto Onukifdc57232017-07-21 15:30:35 -0700241 if (version < 4) {
242 // Before version 4, numSourcePeriodic wasn't persisted.
Makoto Onuki94986212018-04-11 16:24:46 -0700243 totalStats.numSourcePeriodic =
244 totalStats.numSyncs - totalStats.numSourceLocal - totalStats.numSourcePoll
245 - totalStats.numSourceOther
246 - totalStats.numSourceUser;
247 if (totalStats.numSourcePeriodic < 0) { // Sanity check.
248 totalStats.numSourcePeriodic = 0;
Makoto Onukifdc57232017-07-21 15:30:35 -0700249 }
250 } else {
Makoto Onuki94986212018-04-11 16:24:46 -0700251 totalStats.numSourcePeriodic = parcel.readInt();
252 }
253 if (version >= 5) {
254 totalStats.numSourceFeed = parcel.readInt();
255 totalStats.numFailures = parcel.readInt();
256 totalStats.numCancels = parcel.readInt();
257
258 lastTodayResetTime = parcel.readLong();
259
260 todayStats.readFromParcel(parcel);
261 yesterdayStats.readFromParcel(parcel);
Makoto Onukifdc57232017-07-21 15:30:35 -0700262 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700263 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800264
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700265 public SyncStatusInfo(SyncStatusInfo other) {
266 authorityId = other.authorityId;
Makoto Onuki94986212018-04-11 16:24:46 -0700267
268 other.totalStats.copyTo(totalStats);
269 other.todayStats.copyTo(todayStats);
270 other.yesterdayStats.copyTo(yesterdayStats);
271
272 lastTodayResetTime = other.lastTodayResetTime;
273
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700274 lastSuccessTime = other.lastSuccessTime;
275 lastSuccessSource = other.lastSuccessSource;
276 lastFailureTime = other.lastFailureTime;
277 lastFailureSource = other.lastFailureSource;
278 lastFailureMesg = other.lastFailureMesg;
279 initialFailureTime = other.initialFailureTime;
280 pending = other.pending;
281 initialize = other.initialize;
282 if (other.periodicSyncTimes != null) {
283 periodicSyncTimes = new ArrayList<Long>(other.periodicSyncTimes);
284 }
Makoto Onuki15e7a252017-06-08 17:12:05 -0700285 mLastEventTimes.addAll(other.mLastEventTimes);
286 mLastEvents.addAll(other.mLastEvents);
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700287 }
288
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800289 public void setPeriodicSyncTime(int index, long when) {
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700290 // The list is initialized lazily when scheduling occurs so we need to make sure
291 // we initialize elements < index to zero (zero is ignore for scheduling purposes)
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800292 ensurePeriodicSyncTimeSize(index);
293 periodicSyncTimes.set(index, when);
294 }
295
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700296 public long getPeriodicSyncTime(int index) {
297 if (periodicSyncTimes != null && index < periodicSyncTimes.size()) {
298 return periodicSyncTimes.get(index);
299 } else {
300 return 0;
301 }
302 }
303
304 public void removePeriodicSyncTime(int index) {
305 if (periodicSyncTimes != null && index < periodicSyncTimes.size()) {
306 periodicSyncTimes.remove(index);
307 }
308 }
309
Makoto Onuki15e7a252017-06-08 17:12:05 -0700310 /** */
311 public void addEvent(String message) {
312 if (mLastEventTimes.size() >= MAX_EVENT_COUNT) {
313 mLastEventTimes.remove(MAX_EVENT_COUNT - 1);
314 mLastEvents.remove(MAX_EVENT_COUNT - 1);
315 }
316 mLastEventTimes.add(0, System.currentTimeMillis());
317 mLastEvents.add(0, message);
318 }
319
320 /** */
321 public int getEventCount() {
322 return mLastEventTimes.size();
323 }
324
325 /** */
326 public long getEventTime(int i) {
327 return mLastEventTimes.get(i);
328 }
329
330 /** */
331 public String getEvent(int i) {
332 return mLastEvents.get(i);
333 }
334
Georgi Nikolovdbe846b2013-06-25 14:09:56 -0700335 public static final Creator<SyncStatusInfo> CREATOR = new Creator<SyncStatusInfo>() {
336 public SyncStatusInfo createFromParcel(Parcel in) {
337 return new SyncStatusInfo(in);
338 }
339
340 public SyncStatusInfo[] newArray(int size) {
341 return new SyncStatusInfo[size];
342 }
343 };
344
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800345 private void ensurePeriodicSyncTimeSize(int index) {
346 if (periodicSyncTimes == null) {
347 periodicSyncTimes = new ArrayList<Long>(0);
348 }
349
350 final int requiredSize = index + 1;
351 if (periodicSyncTimes.size() < requiredSize) {
352 for (int i = periodicSyncTimes.size(); i < requiredSize; i++) {
353 periodicSyncTimes.add((long) 0);
354 }
355 }
356 }
Makoto Onuki94986212018-04-11 16:24:46 -0700357
358 /**
359 * If the last reset was not not today, move today's stats to yesterday's and clear today's.
360 */
361 public void maybeResetTodayStats(boolean clockValid, boolean force) {
362 final long now = System.currentTimeMillis();
363
364 if (!force) {
365 // Last reset was the same day, nothing to do.
366 if (areSameDates(now, lastTodayResetTime)) {
367 return;
368 }
369
370 // Hack -- on devices with no RTC, until the NTP kicks in, the device won't have the
371 // correct time. So if the time goes back, don't reset, unless we're sure the current
372 // time is correct.
373 if (now < lastTodayResetTime && !clockValid) {
374 return;
375 }
376 }
377
378 lastTodayResetTime = now;
379
380 todayStats.copyTo(yesterdayStats);
381 todayStats.clear();
382 }
383
384 private static boolean areSameDates(long time1, long time2) {
385 final Calendar c1 = new GregorianCalendar();
386 final Calendar c2 = new GregorianCalendar();
387
388 c1.setTimeInMillis(time1);
389 c2.setTimeInMillis(time2);
390
391 return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR)
392 && c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);
393 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700394}