Merge "Add 1-day sync stats in syncmanager dumpsys." into pi-dev
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user