diff options
6 files changed, 437 insertions, 88 deletions
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl index c5001166d77a..dc1766611c3b 100644 --- a/core/java/android/content/IContentService.aidl +++ b/core/java/android/content/IContentService.aidl @@ -183,4 +183,6 @@ interface IContentService { void putCache(in String packageName, in Uri key, in Bundle value, int userId); Bundle getCache(in String packageName, in Uri key, int userId); + + void resetTodayStats(); } diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java index abf9cc91dbda..ded11cfd82ef 100644 --- a/core/java/android/content/SyncStatusInfo.java +++ b/core/java/android/content/SyncStatusInfo.java @@ -21,23 +21,97 @@ import android.os.Parcelable; import android.util.Log; import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; /** @hide */ public class SyncStatusInfo implements Parcelable { private static final String TAG = "Sync"; - static final int VERSION = 4; + static final int VERSION = 5; private static final int MAX_EVENT_COUNT = 10; public final int authorityId; - public long totalElapsedTime; - public int numSyncs; - public int numSourcePoll; - public int numSourceServer; - public int numSourceLocal; - public int numSourceUser; - public int numSourcePeriodic; + + /** + * # of syncs for each sync source, etc. + */ + public static class Stats { + public long totalElapsedTime; + public int numSyncs; + public int numSourcePoll; + public int numSourceOther; + public int numSourceLocal; + public int numSourceUser; + public int numSourcePeriodic; + public int numSourceFeed; + public int numFailures; + public int numCancels; + + /** Copy all the stats to another instance. */ + public void copyTo(Stats to) { + to.totalElapsedTime = totalElapsedTime; + to.numSyncs = numSyncs; + to.numSourcePoll = numSourcePoll; + to.numSourceOther = numSourceOther; + to.numSourceLocal = numSourceLocal; + to.numSourceUser = numSourceUser; + to.numSourcePeriodic = numSourcePeriodic; + to.numSourceFeed = numSourceFeed; + to.numFailures = numFailures; + to.numCancels = numCancels; + } + + /** Clear all the stats. */ + public void clear() { + totalElapsedTime = 0; + numSyncs = 0; + numSourcePoll = 0; + numSourceOther = 0; + numSourceLocal = 0; + numSourceUser = 0; + numSourcePeriodic = 0; + numSourceFeed = 0; + numFailures = 0; + numCancels = 0; + } + + /** Write all the stats to a parcel. */ + public void writeToParcel(Parcel parcel) { + parcel.writeLong(totalElapsedTime); + parcel.writeInt(numSyncs); + parcel.writeInt(numSourcePoll); + parcel.writeInt(numSourceOther); + parcel.writeInt(numSourceLocal); + parcel.writeInt(numSourceUser); + parcel.writeInt(numSourcePeriodic); + parcel.writeInt(numSourceFeed); + parcel.writeInt(numFailures); + parcel.writeInt(numCancels); + } + + /** Read all the stats from a parcel. */ + public void readFromParcel(Parcel parcel) { + totalElapsedTime = parcel.readLong(); + numSyncs = parcel.readInt(); + numSourcePoll = parcel.readInt(); + numSourceOther = parcel.readInt(); + numSourceLocal = parcel.readInt(); + numSourceUser = parcel.readInt(); + numSourcePeriodic = parcel.readInt(); + numSourceFeed = parcel.readInt(); + numFailures = parcel.readInt(); + numCancels = parcel.readInt(); + } + } + + public long lastTodayResetTime; + + public final Stats totalStats = new Stats(); + public final Stats todayStats = new Stats(); + public final Stats yesterdayStats = new Stats(); + public long lastSuccessTime; public int lastSuccessSource; public long lastFailureTime; @@ -75,12 +149,15 @@ public class SyncStatusInfo implements Parcelable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(VERSION); parcel.writeInt(authorityId); - parcel.writeLong(totalElapsedTime); - parcel.writeInt(numSyncs); - parcel.writeInt(numSourcePoll); - parcel.writeInt(numSourceServer); - parcel.writeInt(numSourceLocal); - parcel.writeInt(numSourceUser); + + // Note we can't use Stats.writeToParcel() here; see the below constructor for the reason. + parcel.writeLong(totalStats.totalElapsedTime); + parcel.writeInt(totalStats.numSyncs); + parcel.writeInt(totalStats.numSourcePoll); + parcel.writeInt(totalStats.numSourceOther); + parcel.writeInt(totalStats.numSourceLocal); + parcel.writeInt(totalStats.numSourceUser); + parcel.writeLong(lastSuccessTime); parcel.writeInt(lastSuccessSource); parcel.writeLong(lastFailureTime); @@ -102,7 +179,18 @@ public class SyncStatusInfo implements Parcelable { parcel.writeLong(mLastEventTimes.get(i)); parcel.writeString(mLastEvents.get(i)); } - parcel.writeInt(numSourcePeriodic); + // Version 4 + parcel.writeInt(totalStats.numSourcePeriodic); + + // Version 5 + parcel.writeInt(totalStats.numSourceFeed); + parcel.writeInt(totalStats.numFailures); + parcel.writeInt(totalStats.numCancels); + + parcel.writeLong(lastTodayResetTime); + + todayStats.writeToParcel(parcel); + yesterdayStats.writeToParcel(parcel); } public SyncStatusInfo(Parcel parcel) { @@ -111,12 +199,15 @@ public class SyncStatusInfo implements Parcelable { Log.w("SyncStatusInfo", "Unknown version: " + version); } authorityId = parcel.readInt(); - totalElapsedTime = parcel.readLong(); - numSyncs = parcel.readInt(); - numSourcePoll = parcel.readInt(); - numSourceServer = parcel.readInt(); - numSourceLocal = parcel.readInt(); - numSourceUser = parcel.readInt(); + + // Note we can't use Stats.writeToParcel() here because the data is persisted and we need + // to be able to read from the old format too. + totalStats.totalElapsedTime = parcel.readLong(); + totalStats.numSyncs = parcel.readInt(); + totalStats.numSourcePoll = parcel.readInt(); + totalStats.numSourceOther = parcel.readInt(); + totalStats.numSourceLocal = parcel.readInt(); + totalStats.numSourceUser = parcel.readInt(); lastSuccessTime = parcel.readLong(); lastSuccessSource = parcel.readInt(); lastFailureTime = parcel.readLong(); @@ -149,25 +240,37 @@ public class SyncStatusInfo implements Parcelable { } if (version < 4) { // Before version 4, numSourcePeriodic wasn't persisted. - numSourcePeriodic = numSyncs - numSourceLocal - numSourcePoll - numSourceServer - - numSourceUser; - if (numSourcePeriodic < 0) { // Sanity check. - numSourcePeriodic = 0; + totalStats.numSourcePeriodic = + totalStats.numSyncs - totalStats.numSourceLocal - totalStats.numSourcePoll + - totalStats.numSourceOther + - totalStats.numSourceUser; + if (totalStats.numSourcePeriodic < 0) { // Sanity check. + totalStats.numSourcePeriodic = 0; } } else { - numSourcePeriodic = parcel.readInt(); + totalStats.numSourcePeriodic = parcel.readInt(); + } + if (version >= 5) { + totalStats.numSourceFeed = parcel.readInt(); + totalStats.numFailures = parcel.readInt(); + totalStats.numCancels = parcel.readInt(); + + lastTodayResetTime = parcel.readLong(); + + todayStats.readFromParcel(parcel); + yesterdayStats.readFromParcel(parcel); } } public SyncStatusInfo(SyncStatusInfo other) { authorityId = other.authorityId; - totalElapsedTime = other.totalElapsedTime; - numSyncs = other.numSyncs; - numSourcePoll = other.numSourcePoll; - numSourceServer = other.numSourceServer; - numSourceLocal = other.numSourceLocal; - numSourceUser = other.numSourceUser; - numSourcePeriodic = other.numSourcePeriodic; + + other.totalStats.copyTo(totalStats); + other.todayStats.copyTo(todayStats); + other.yesterdayStats.copyTo(yesterdayStats); + + lastTodayResetTime = other.lastTodayResetTime; + lastSuccessTime = other.lastSuccessTime; lastSuccessSource = other.lastSuccessSource; lastFailureTime = other.lastFailureTime; @@ -251,4 +354,41 @@ public class SyncStatusInfo implements Parcelable { } } } + + /** + * If the last reset was not not today, move today's stats to yesterday's and clear today's. + */ + public void maybeResetTodayStats(boolean clockValid, boolean force) { + final long now = System.currentTimeMillis(); + + if (!force) { + // Last reset was the same day, nothing to do. + if (areSameDates(now, lastTodayResetTime)) { + return; + } + + // Hack -- on devices with no RTC, until the NTP kicks in, the device won't have the + // correct time. So if the time goes back, don't reset, unless we're sure the current + // time is correct. + if (now < lastTodayResetTime && !clockValid) { + return; + } + } + + lastTodayResetTime = now; + + todayStats.copyTo(yesterdayStats); + todayStats.clear(); + } + + private static boolean areSameDates(long time1, long time2) { + final Calendar c1 = new GregorianCalendar(); + final Calendar c2 = new GregorianCalendar(); + + c1.setTimeInMillis(time1); + c2.setTimeInMillis(time2); + + return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) + && c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR); + } }
\ No newline at end of file diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index e3d0bddc835a..e840a29d0937 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -51,6 +51,8 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Process; import android.os.RemoteException; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; @@ -1577,4 +1579,32 @@ public final class ContentService extends IContentService.Stub { } } } + + private void enforceShell(String method) { + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { + throw new SecurityException("Non-shell user attempted to call " + method); + } + } + + @Override + public void resetTodayStats() { + enforceShell("resetTodayStats"); + + if (mSyncManager != null) { + final long token = Binder.clearCallingIdentity(); + try { + mSyncManager.resetTodayStats(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { + (new ContentShellCommand(this)).exec(this, in, out, err, args, callback, resultReceiver); + } } diff --git a/services/core/java/com/android/server/content/ContentShellCommand.java b/services/core/java/com/android/server/content/ContentShellCommand.java new file mode 100644 index 000000000000..6c2991f87890 --- /dev/null +++ b/services/core/java/com/android/server/content/ContentShellCommand.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.content; + +import android.content.IContentService; +import android.content.Intent; +import android.os.RemoteException; +import android.os.ShellCommand; + +import java.io.PrintWriter; + +public class ContentShellCommand extends ShellCommand { + final IContentService mInterface; + + ContentShellCommand(IContentService service) { + mInterface = service; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + + final PrintWriter pw = getOutPrintWriter(); + try { + switch(cmd) { + case "reset-today-stats": + return runResetTodayStats(); + default: + return handleDefaultCommands(cmd); + } + } catch (RemoteException e) { + pw.println("Remote exception: " + e); + } + return -1; + } + + private int runResetTodayStats() throws RemoteException { + mInterface.resetTodayStats(); + return 0; + } + + @Override + public void onHelp() { + final PrintWriter pw = getOutPrintWriter(); + pw.println("Content service commands:"); + pw.println(" help"); + pw.println(" Print this help text."); + pw.println(""); + pw.println(" reset-today-stats"); + pw.println(" Reset 1-day sync stats."); + pw.println(); + } +} diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index a312fe1dcc3b..decae1865e47 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -48,6 +48,7 @@ import android.content.SyncAdaptersCache; import android.content.SyncInfo; import android.content.SyncResult; import android.content.SyncStatusInfo; +import android.content.SyncStatusInfo.Stats; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -95,6 +96,7 @@ import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.function.QuadConsumer; import com.android.server.DeviceIdleController; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -122,6 +124,7 @@ import java.util.Map; import java.util.Objects; import java.util.Random; import java.util.Set; +import java.util.function.Function; import java.util.function.Predicate; /** @@ -242,7 +245,7 @@ public class SyncManager { /** Track whether the device has already been provisioned. */ private volatile boolean mProvisioned; - protected SyncAdaptersCache mSyncAdapters; + protected final SyncAdaptersCache mSyncAdapters; private final Random mRand; @@ -423,6 +426,17 @@ public class SyncManager { } }; + private final BroadcastReceiver mOtherIntentsReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) { + mSyncStorageEngine.setClockValid(); + return; + } + } + }; + private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -631,6 +645,9 @@ public class SyncManager { mContext.registerReceiverAsUser( mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); + intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED); + context.registerReceiver(mOtherIntentsReceiver, intentFilter); + if (!factoryTest) { mNotificationMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); @@ -947,9 +964,13 @@ public class SyncManager { } else if (requestedAuthority == null) { source = SyncStorageEngine.SOURCE_POLL; } else { - // This isn't strictly server, since arbitrary callers can (and do) request - // a non-forced two-way sync on a specific url. - source = SyncStorageEngine.SOURCE_SERVER; + if (extras.containsKey("feed")) { + source = SyncStorageEngine.SOURCE_FEED; + } else{ + // This isn't strictly server, since arbitrary callers can (and do) request + // a non-forced two-way sync on a specific url. + source = SyncStorageEngine.SOURCE_OTHER; + } } for (AccountAndUser account : accounts) { @@ -2134,6 +2155,7 @@ public class SyncManager { pw.print("Memory low: "); pw.println(mStorageIsLow); pw.print("Device idle: "); pw.println(mDeviceIsIdle); pw.print("Reported active: "); pw.println(mReportedSyncActive); + pw.print("Clock valid: "); pw.println(mSyncStorageEngine.isClockValid()); final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts(); @@ -2181,26 +2203,35 @@ public class SyncManager { final ArrayList<Pair<EndPoint, SyncStatusInfo>> statuses = new ArrayList<>(); + mSyncStorageEngine.resetTodayStats(/* force=*/ false); + for (AccountAndUser account : accounts) { pw.printf("Account %s u%d %s\n", account.account.name, account.userId, account.account.type); pw.println("======================================================================="); - final PrintTable table = new PrintTable(13); + final PrintTable table = new PrintTable(16); table.set(0, 0, "Authority", // 0 "Syncable", // 1 "Enabled", // 2 - "Delay", // 3 - "Loc", // 4 - "Poll", // 5 - "Per", // 6 - "Serv", // 7 - "User", // 8 - "Tot", // 9 - "Time", // 10 - "Last Sync", // 11 - "Backoff" // 12 + + "Stats", // 3 "Total", "Today" or "Yesterday". + + "Loc", // 4 # of syncs with local sources. (including failures/cancels. ) + "Poll", // 5 "poll" syncs. + "Per", // 6 Periodic syncs. + "Feed", // 7 Syncs with a "feed" extra. (subscribedfeeds?) + "User", // 8 User-initiated + "Othr", // 9 Other sources. + + "Tot", // 10 Total syncs (including failures / cancels) + "Fail", // 11 (Failure) + "Can", // 12 (Cancel) + + "Time", // 13 Total time + "Last Sync", // 14 + "Backoff" // 15 ); final List<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> sorted = @@ -2234,37 +2265,50 @@ public class SyncManager { } table.set(row, 0, authority, settings.syncable, settings.enabled); - sb.setLength(0); - table.set(row, 4, - status.numSourceLocal, - status.numSourcePoll, - status.numSourcePeriodic, - status.numSourceServer, - status.numSourceUser, - status.numSyncs, - formatDurationHMS(sb, status.totalElapsedTime)); + QuadConsumer<String, Stats, Function<Integer, String>, Integer> c = + (label, stats, filter, r) -> { + sb.setLength(0); + table.set(r, 3, + label, + filter.apply(stats.numSourceLocal), + filter.apply(stats.numSourcePoll), + filter.apply(stats.numSourcePeriodic), + filter.apply(stats.numSourceFeed), + filter.apply(stats.numSourceUser), + filter.apply(stats.numSourceOther), + filter.apply(stats.numSyncs), + filter.apply(stats.numFailures), + filter.apply(stats.numCancels), + formatDurationHMS(sb, stats.totalElapsedTime)); + }; + c.accept("Total", status.totalStats, (i) -> Integer.toString(i), row); + c.accept("Today", status.todayStats, this::zeroToEmpty, row + 1); + c.accept("Yestr", status.yesterdayStats, this::zeroToEmpty, row + 2); + + final int LAST_SYNC = 14; + final int BACKOFF = LAST_SYNC + 1; int row1 = row; if (settings.delayUntil > now) { - table.set(row1++, 12, "D: " + (settings.delayUntil - now) / 1000); + table.set(row1++, BACKOFF, "D: " + (settings.delayUntil - now) / 1000); if (settings.backoffTime > now) { - table.set(row1++, 12, "B: " + (settings.backoffTime - now) / 1000); - table.set(row1++, 12, settings.backoffDelay / 1000); + table.set(row1++, BACKOFF, "B: " + (settings.backoffTime - now) / 1000); + table.set(row1++, BACKOFF, settings.backoffDelay / 1000); } } row1 = row; if (status.lastSuccessTime != 0) { - table.set(row1++, 11, SyncStorageEngine.SOURCES[status.lastSuccessSource] + table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastSuccessSource] + " " + "SUCCESS"); - table.set(row1++, 11, formatTime(status.lastSuccessTime)); + table.set(row1++, LAST_SYNC, formatTime(status.lastSuccessTime)); } if (status.lastFailureTime != 0) { - table.set(row1++, 11, SyncStorageEngine.SOURCES[status.lastFailureSource] + table.set(row1++, LAST_SYNC, SyncStorageEngine.SOURCES[status.lastFailureSource] + " " + "FAILURE"); - table.set(row1++, 11, formatTime(status.lastFailureTime)); + table.set(row1++, LAST_SYNC, formatTime(status.lastFailureTime)); //noinspection UnusedAssignment - table.set(row1++, 11, status.lastFailureMesg); + table.set(row1++, LAST_SYNC, status.lastFailureMesg); } } table.writeTo(pw); @@ -2274,6 +2318,7 @@ public class SyncManager { pw.println(); pw.println("Per Adapter History"); + pw.println("(SERVER is now split up to FEED and OTHER)"); for (int i = 0; i < statuses.size(); i++) { final Pair<EndPoint, SyncStatusInfo> event = statuses.get(i); @@ -2299,6 +2344,10 @@ public class SyncManager { } } + private String zeroToEmpty(int value) { + return (value != 0) ? Integer.toString(value) : ""; + } + private void dumpTimeSec(PrintWriter pw, long time) { pw.print(time/1000); pw.print('.'); pw.print((time/100)%10); pw.print('s'); @@ -2459,6 +2508,7 @@ public class SyncManager { pw.println(); pw.println("Recent Sync History"); + pw.println("(SERVER is now split up to FEED and OTHER)"); final String format = " %-" + maxAccount + "s %-" + maxAuthority + "s %s\n"; final Map<String, Long> lastTimeMap = Maps.newHashMap(); final PackageManager pm = mContext.getPackageManager(); @@ -2525,6 +2575,7 @@ public class SyncManager { } pw.println(); pw.println("Recent Sync History Extras"); + pw.println("(SERVER is now split up to FEED and OTHER)"); for (int i = 0; i < N; i++) { final SyncStorageEngine.SyncHistoryItem item = items.get(i); final Bundle extras = item.extras; @@ -3104,6 +3155,10 @@ public class SyncManager { final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (isLoggable) Slog.v(TAG, op.toString()); + // At this point, we know the device has been connected to the server, so + // assume the clock is correct. + mSyncStorageEngine.setClockValid(); + mSyncJobService.markSyncStarted(op.jobId); if (mStorageIsLow) { @@ -4015,4 +4070,8 @@ public class SyncManager { Slog.wtf(TAG, message); mLogger.log("WTF: ", message); } + + public void resetTodayStats() { + mSyncStorageEngine.resetTodayStats(/*force=*/ true); + } } diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index 8dd229c32809..f54a9a0c006a 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -108,11 +108,12 @@ public class SyncStorageEngine { /** Enum value for a sync stop event. */ public static final int EVENT_STOP = 1; - /** Enum value for a server-initiated sync. */ - public static final int SOURCE_SERVER = 0; + /** Enum value for a sync with other sources. */ + public static final int SOURCE_OTHER = 0; /** Enum value for a local-initiated sync. */ public static final int SOURCE_LOCAL = 1; + /** Enum value for a poll-based sync (e.g., upon connection to network) */ public static final int SOURCE_POLL = 2; @@ -122,16 +123,18 @@ public class SyncStorageEngine { /** Enum value for a periodic sync. */ public static final int SOURCE_PERIODIC = 4; + /** Enum a sync with a "feed" extra */ + public static final int SOURCE_FEED = 5; + public static final long NOT_IN_BACKOFF_MODE = -1; - // TODO: i18n -- grab these out of resources. /** String names for the sync source types. */ - public static final String[] SOURCES = { "SERVER", + public static final String[] SOURCES = { "OTHER", "LOCAL", "POLL", "USER", "PERIODIC", - "SERVICE"}; + "FEED"}; // The MESG column will contain one of these or one of the Error types. public static final String MESG_SUCCESS = "success"; @@ -153,6 +156,8 @@ public class SyncStorageEngine { private static HashMap<String, String> sAuthorityRenames; private static PeriodicSyncAddedListener mPeriodicSyncAddedListener; + private volatile boolean mIsClockValid; + static { sAuthorityRenames = new HashMap<String, String>(); sAuthorityRenames.put("contacts", "com.android.contacts"); @@ -1174,23 +1179,36 @@ public class SyncStorageEngine { SyncStatusInfo status = getOrCreateSyncStatusLocked(item.authorityId); - status.numSyncs++; - status.totalElapsedTime += elapsedTime; + status.maybeResetTodayStats(isClockValid(), /*force=*/ false); + + status.totalStats.numSyncs++; + status.todayStats.numSyncs++; + status.totalStats.totalElapsedTime += elapsedTime; + status.todayStats.totalElapsedTime += elapsedTime; switch (item.source) { case SOURCE_LOCAL: - status.numSourceLocal++; + status.totalStats.numSourceLocal++; + status.todayStats.numSourceLocal++; break; case SOURCE_POLL: - status.numSourcePoll++; + status.totalStats.numSourcePoll++; + status.todayStats.numSourcePoll++; break; case SOURCE_USER: - status.numSourceUser++; + status.totalStats.numSourceUser++; + status.todayStats.numSourceUser++; break; - case SOURCE_SERVER: - status.numSourceServer++; + case SOURCE_OTHER: + status.totalStats.numSourceOther++; + status.todayStats.numSourceOther++; break; case SOURCE_PERIODIC: - status.numSourcePeriodic++; + status.totalStats.numSourcePeriodic++; + status.todayStats.numSourcePeriodic++; + break; + case SOURCE_FEED: + status.totalStats.numSourceFeed++; + status.todayStats.numSourceFeed++; break; } @@ -1225,6 +1243,9 @@ public class SyncStorageEngine { if (status.lastFailureTime == 0) { writeStatusNow = true; } + status.totalStats.numFailures++; + status.todayStats.numFailures++; + status.lastFailureTime = lastSyncTime; status.lastFailureSource = item.source; status.lastFailureMesg = resultMessage; @@ -1233,6 +1254,11 @@ public class SyncStorageEngine { } ds.failureCount++; ds.failureTime += elapsedTime; + } else { + // Cancel + status.totalStats.numCancels++; + status.todayStats.numCancels++; + writeStatusNow = true; } final StringBuilder event = new StringBuilder(); event.append("" + resultMessage + " Source=" + SyncStorageEngine.SOURCES[item.source] @@ -1969,9 +1995,8 @@ public class SyncStorageEngine { } /** - * Load sync engine state from the old syncmanager database, and then - * erase it. Note that we don't deal with pending operations, active - * sync, or history. + * TODO Remove it. It's super old code that was used to migrate the information from a sqlite + * database that we used a long time ago, and is no longer relevant. */ private void readAndDeleteLegacyAccountInfoLocked() { // Look for old database to initialize from. @@ -2049,13 +2074,13 @@ public class SyncStorageEngine { st = new SyncStatusInfo(authority.ident); mSyncStatus.put(authority.ident, st); } - st.totalElapsedTime = getLongColumn(c, "totalElapsedTime"); - st.numSyncs = getIntColumn(c, "numSyncs"); - st.numSourceLocal = getIntColumn(c, "numSourceLocal"); - st.numSourcePoll = getIntColumn(c, "numSourcePoll"); - st.numSourceServer = getIntColumn(c, "numSourceServer"); - st.numSourceUser = getIntColumn(c, "numSourceUser"); - st.numSourcePeriodic = 0; + st.totalStats.totalElapsedTime = getLongColumn(c, "totalElapsedTime"); + st.totalStats.numSyncs = getIntColumn(c, "numSyncs"); + st.totalStats.numSourceLocal = getIntColumn(c, "numSourceLocal"); + st.totalStats.numSourcePoll = getIntColumn(c, "numSourcePoll"); + st.totalStats.numSourceOther = getIntColumn(c, "numSourceServer"); + st.totalStats.numSourceUser = getIntColumn(c, "numSourceUser"); + st.totalStats.numSourcePeriodic = 0; st.lastSuccessSource = getIntColumn(c, "lastSuccessSource"); st.lastSuccessTime = getLongColumn(c, "lastSuccessTime"); st.lastFailureSource = getIntColumn(c, "lastFailureSource"); @@ -2296,4 +2321,29 @@ public class SyncStorageEngine { public void queueBackup() { BackupManager.dataChanged("android"); } + + public void setClockValid() { + if (!mIsClockValid) { + mIsClockValid = true; + Slog.w(TAG, "Clock is valid now."); + } + } + + public boolean isClockValid() { + return mIsClockValid; + } + + public void resetTodayStats(boolean force) { + if (force) { + Log.w(TAG, "Force resetting today stats."); + } + synchronized (mAuthorities) { + final int N = mSyncStatus.size(); + for (int i = 0; i < N; i++) { + SyncStatusInfo cur = mSyncStatus.valueAt(i); + cur.maybeResetTodayStats(isClockValid(), force); + } + writeStatusLocked(); + } + } } |