Merge "Update SyncStorageEngine to use protos."
This commit is contained in:
committed by
Android (Google) Code Review
commit
fd74d7645a
@@ -20,6 +20,9 @@ import android.annotation.UnsupportedAppUsage;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
@@ -139,10 +142,10 @@ public class SyncStatusInfo implements Parcelable {
|
||||
public final long[] perSourceLastSuccessTimes = new long[SOURCE_COUNT];
|
||||
public final long[] perSourceLastFailureTimes = new long[SOURCE_COUNT];
|
||||
|
||||
// Warning: It is up to the external caller to ensure there are
|
||||
// no race conditions when accessing this list
|
||||
@UnsupportedAppUsage
|
||||
private ArrayList<Long> periodicSyncTimes;
|
||||
// Warning: It is up to the external caller to ensure there are
|
||||
// no race conditions when accessing this list
|
||||
@UnsupportedAppUsage
|
||||
private ArrayList<Long> periodicSyncTimes;
|
||||
|
||||
private final ArrayList<Long> mLastEventTimes = new ArrayList<>();
|
||||
private final ArrayList<String> mLastEvents = new ArrayList<>();
|
||||
@@ -292,9 +295,28 @@ public class SyncStatusInfo implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all data from the given SyncStatusInfo object.
|
||||
*
|
||||
* @param other the SyncStatusInfo object to copy data from
|
||||
*/
|
||||
public SyncStatusInfo(SyncStatusInfo other) {
|
||||
authorityId = other.authorityId;
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all data from the given SyncStatusInfo object except for its authority id.
|
||||
*
|
||||
* @param authorityId the new authority id
|
||||
* @param other the SyncStatusInfo object to copy data from
|
||||
*/
|
||||
public SyncStatusInfo(int authorityId, SyncStatusInfo other) {
|
||||
this.authorityId = authorityId;
|
||||
copyFrom(other);
|
||||
}
|
||||
|
||||
private void copyFrom(SyncStatusInfo other) {
|
||||
other.totalStats.copyTo(totalStats);
|
||||
other.todayStats.copyTo(todayStats);
|
||||
other.yesterdayStats.copyTo(yesterdayStats);
|
||||
@@ -323,6 +345,14 @@ public class SyncStatusInfo implements Parcelable {
|
||||
System.arraycopy(from, 0, to, 0, to.length);
|
||||
}
|
||||
|
||||
public int getPeriodicSyncTimesSize() {
|
||||
return periodicSyncTimes == null ? 0 : periodicSyncTimes.size();
|
||||
}
|
||||
|
||||
public void addPeriodicSyncTime(long time) {
|
||||
periodicSyncTimes = ArrayUtils.add(periodicSyncTimes, time);
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public void setPeriodicSyncTime(int index, long when) {
|
||||
// The list is initialized lazily when scheduling occurs so we need to make sure
|
||||
@@ -347,6 +377,24 @@ public class SyncStatusInfo implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates {@code mLastEventTimes} and {@code mLastEvents} with the given list. <br>
|
||||
* <i>Note: This method is mainly used to repopulate the event info from disk and it will clear
|
||||
* both {@code mLastEventTimes} and {@code mLastEvents} before populating.</i>
|
||||
*
|
||||
* @param lastEventInformation the list to populate with
|
||||
*/
|
||||
public void populateLastEventsInformation(ArrayList<Pair<Long, String>> lastEventInformation) {
|
||||
mLastEventTimes.clear();
|
||||
mLastEvents.clear();
|
||||
final int size = lastEventInformation.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final Pair<Long, String> lastEventInfo = lastEventInformation.get(i);
|
||||
mLastEventTimes.add(lastEventInfo.first);
|
||||
mLastEvents.add(lastEventInfo.second);
|
||||
}
|
||||
}
|
||||
|
||||
/** */
|
||||
public void addEvent(String message) {
|
||||
if (mLastEventTimes.size() >= MAX_EVENT_COUNT) {
|
||||
|
||||
86
core/proto/android/server/syncstorageengine.proto
Normal file
86
core/proto/android/server/syncstorageengine.proto
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
package com.android.server.content;
|
||||
import "frameworks/base/core/proto/android/privacy.proto";
|
||||
|
||||
option java_multiple_files = true;
|
||||
|
||||
/**
|
||||
* Stores relevant information from a DayStats object in SyncStorageEngine.
|
||||
*/
|
||||
message SyncStatisticsProto {
|
||||
|
||||
message DayStats {
|
||||
optional int32 day = 1; // day of the year - defined by SyncStorageEngine#getCurrentDayLocked()
|
||||
optional int32 success_count = 2;
|
||||
optional int64 success_time = 3; // time since epoch
|
||||
optional int32 failure_count = 4;
|
||||
optional int64 failure_time = 5; // time since epoch
|
||||
}
|
||||
|
||||
repeated DayStats stats = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores relevant information from a SyncStatusInfo object.
|
||||
*/
|
||||
message SyncStatusProto {
|
||||
|
||||
message StatusInfo {
|
||||
|
||||
message Stats {
|
||||
optional int64 total_elapsed_time = 1; // time since epoch
|
||||
optional int32 num_syncs = 2;
|
||||
optional int32 num_failures = 3;
|
||||
optional int32 num_cancels = 4;
|
||||
optional int32 num_source_other = 5;
|
||||
optional int32 num_source_local = 6;
|
||||
optional int32 num_source_poll = 7;
|
||||
optional int32 num_source_user = 8;
|
||||
optional int32 num_source_periodic = 9;
|
||||
optional int32 num_source_feed = 10;
|
||||
}
|
||||
|
||||
message LastEventInfo {
|
||||
optional int64 last_event_time = 1; // time since epoch
|
||||
optional string last_event = 2;
|
||||
}
|
||||
|
||||
// Note: version doesn't need to be stored in proto because of how protos store information but
|
||||
// leaving field number 1 open in case we find a usage for it in the future.
|
||||
optional int32 authority_id = 2;
|
||||
optional int64 last_success_time = 3; // time since epoch
|
||||
optional int32 last_success_source = 4;
|
||||
optional int64 last_failure_time = 5; // time since epoch
|
||||
optional int32 last_failure_source = 6;
|
||||
optional string last_failure_message = 7;
|
||||
optional int64 initial_failure_time = 8; // time since epoch
|
||||
optional bool pending = 9;
|
||||
optional bool initialize = 10;
|
||||
repeated int64 periodic_sync_times = 11; // times since epoch
|
||||
repeated LastEventInfo last_event_info = 12;
|
||||
optional int64 last_today_reset_time = 13; // time since epoch
|
||||
optional Stats total_stats = 14;
|
||||
optional Stats today_stats = 15;
|
||||
optional Stats yesterday_stats = 16;
|
||||
repeated int64 per_source_last_success_times = 17; // times since epoch
|
||||
repeated int64 per_source_last_failure_times = 18; // times since epoch
|
||||
}
|
||||
|
||||
repeated StatusInfo status = 1;
|
||||
}
|
||||
@@ -51,6 +51,8 @@ import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.Xml;
|
||||
import android.util.proto.ProtoInputStream;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
@@ -64,6 +66,9 @@ import org.xmlpull.v1.XmlSerializer;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
@@ -428,7 +433,8 @@ public class SyncStorageEngine {
|
||||
}
|
||||
|
||||
// Primary list of all syncable authorities. Also our global lock.
|
||||
private final SparseArray<AuthorityInfo> mAuthorities =
|
||||
@VisibleForTesting
|
||||
final SparseArray<AuthorityInfo> mAuthorities =
|
||||
new SparseArray<AuthorityInfo>();
|
||||
|
||||
private final HashMap<AccountAndUser, AccountInfo> mAccounts
|
||||
@@ -437,7 +443,8 @@ public class SyncStorageEngine {
|
||||
private final SparseArray<ArrayList<SyncInfo>> mCurrentSyncs
|
||||
= new SparseArray<ArrayList<SyncInfo>>();
|
||||
|
||||
private final SparseArray<SyncStatusInfo> mSyncStatus =
|
||||
@VisibleForTesting
|
||||
final SparseArray<SyncStatusInfo> mSyncStatus =
|
||||
new SparseArray<SyncStatusInfo>();
|
||||
|
||||
private final ArrayList<SyncHistoryItem> mSyncHistory =
|
||||
@@ -453,7 +460,8 @@ public class SyncStorageEngine {
|
||||
private int mNextAuthorityId = 0;
|
||||
|
||||
// We keep 4 weeks of stats.
|
||||
private final DayStats[] mDayStats = new DayStats[7*4];
|
||||
@VisibleForTesting
|
||||
final DayStats[] mDayStats = new DayStats[7*4];
|
||||
private final Calendar mCal;
|
||||
private int mYear;
|
||||
private int mYearInDays;
|
||||
@@ -464,6 +472,18 @@ public class SyncStorageEngine {
|
||||
|
||||
private int mSyncRandomOffset;
|
||||
|
||||
// STOPSHIP: b/143656271 this should be true on launch
|
||||
private static final boolean DELETE_LEGACY_PARCEL_FILES = false;
|
||||
private static final String LEGACY_STATUS_FILE_NAME = "status.bin";
|
||||
private static final String LEGACY_STATISTICS_FILE_NAME = "stats.bin";
|
||||
|
||||
private static final String SYNC_DIR_NAME = "sync";
|
||||
private static final String ACCOUNT_INFO_FILE_NAME = "accounts.xml";
|
||||
private static final String STATUS_FILE_NAME = "status";
|
||||
private static final String STATISTICS_FILE_NAME = "stats";
|
||||
|
||||
private File mSyncDir;
|
||||
|
||||
/**
|
||||
* This file contains the core engine state: all accounts and the
|
||||
* settings for them. It must never be lost, and should be changed
|
||||
@@ -508,14 +528,15 @@ public class SyncStorageEngine {
|
||||
com.android.internal.R.bool.config_syncstorageengine_masterSyncAutomatically);
|
||||
|
||||
File systemDir = new File(dataDir, "system");
|
||||
File syncDir = new File(systemDir, "sync");
|
||||
syncDir.mkdirs();
|
||||
mSyncDir = new File(systemDir, SYNC_DIR_NAME);
|
||||
mSyncDir.mkdirs();
|
||||
|
||||
maybeDeleteLegacyPendingInfoLocked(syncDir);
|
||||
maybeDeleteLegacyPendingInfoLocked(mSyncDir);
|
||||
|
||||
mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"), "sync-accounts");
|
||||
mStatusFile = new AtomicFile(new File(syncDir, "status.bin"), "sync-status");
|
||||
mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"), "sync-stats");
|
||||
mAccountInfoFile = new AtomicFile(new File(mSyncDir, ACCOUNT_INFO_FILE_NAME),
|
||||
"sync-accounts");
|
||||
mStatusFile = new AtomicFile(new File(mSyncDir, STATUS_FILE_NAME), "sync-status");
|
||||
mStatisticsFile = new AtomicFile(new File(mSyncDir, STATISTICS_FILE_NAME), "sync-stats");
|
||||
|
||||
readAccountInfoLocked();
|
||||
readStatusLocked();
|
||||
@@ -2017,15 +2038,10 @@ public class SyncStorageEngine {
|
||||
public static final int STATUS_FILE_END = 0;
|
||||
public static final int STATUS_FILE_ITEM = 100;
|
||||
|
||||
/**
|
||||
* Read all sync status back in to the initial engine state.
|
||||
*/
|
||||
private void readStatusLocked() {
|
||||
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||
Slog.v(TAG_FILE, "Reading " + mStatusFile.getBaseFile());
|
||||
}
|
||||
private void readStatusParcelLocked(File parcel) {
|
||||
try {
|
||||
byte[] data = mStatusFile.readFully();
|
||||
final AtomicFile parcelFile = new AtomicFile(parcel);
|
||||
byte[] data = parcelFile.readFully();
|
||||
Parcel in = Parcel.obtain();
|
||||
in.unmarshall(data, 0, data.length);
|
||||
in.setDataPosition(0);
|
||||
@@ -2036,9 +2052,6 @@ public class SyncStorageEngine {
|
||||
SyncStatusInfo status = new SyncStatusInfo(in);
|
||||
if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
|
||||
status.pending = false;
|
||||
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||
Slog.v(TAG_FILE, "Adding status for id " + status.authorityId);
|
||||
}
|
||||
mSyncStatus.put(status.authorityId, status);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -2050,15 +2063,247 @@ public class SyncStorageEngine {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (java.io.IOException e) {
|
||||
} catch (IOException e) {
|
||||
Slog.i(TAG, "No initial status");
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeStatusIfNeededLocked() {
|
||||
final File parcelStatus = new File(mSyncDir, LEGACY_STATUS_FILE_NAME);
|
||||
if (parcelStatus.exists() && !mStatusFile.exists()) {
|
||||
readStatusParcelLocked(parcelStatus);
|
||||
writeStatusLocked();
|
||||
}
|
||||
|
||||
// if upgrade to proto was successful, delete parcel file
|
||||
if (DELETE_LEGACY_PARCEL_FILES && mStatusFile.exists()) {
|
||||
parcelStatus.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all sync status back in to the initial engine state.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void readStatusLocked() {
|
||||
upgradeStatusIfNeededLocked();
|
||||
|
||||
if (!mStatusFile.exists()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
try (FileInputStream in = mStatusFile.openRead()) {
|
||||
readStatusInfoLocked(in);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Unable to read status info file.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void readStatusInfoLocked(InputStream in) throws IOException {
|
||||
final ProtoInputStream proto = new ProtoInputStream(in);
|
||||
while (true) {
|
||||
switch (proto.nextField()) {
|
||||
case (int) SyncStatusProto.STATUS:
|
||||
final long token = proto.start(SyncStatusProto.STATUS);
|
||||
final SyncStatusInfo status = readSyncStatusInfoLocked(proto);
|
||||
proto.end(token);
|
||||
if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
|
||||
status.pending = false;
|
||||
mSyncStatus.put(status.authorityId, status);
|
||||
}
|
||||
break;
|
||||
case ProtoInputStream.NO_MORE_FIELDS:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SyncStatusInfo readSyncStatusInfoLocked(ProtoInputStream proto) throws IOException {
|
||||
SyncStatusInfo status;
|
||||
if (proto.nextField(SyncStatusProto.StatusInfo.AUTHORITY_ID)) {
|
||||
//fast-path; this should work for most cases since the authority id is written first
|
||||
status = new SyncStatusInfo(proto.readInt(SyncStatusProto.StatusInfo.AUTHORITY_ID));
|
||||
} else {
|
||||
// placeholder to read other data; assume the default authority id as 0
|
||||
status = new SyncStatusInfo(0);
|
||||
}
|
||||
|
||||
int successTimesCount = 0;
|
||||
int failureTimesCount = 0;
|
||||
ArrayList<Pair<Long, String>> lastEventInformation = new ArrayList<>();
|
||||
while (true) {
|
||||
switch (proto.nextField()) {
|
||||
case (int) SyncStatusProto.StatusInfo.AUTHORITY_ID:
|
||||
// fast-path failed for some reason, rebuild the status from placeholder object
|
||||
Slog.w(TAG, "Failed to read the authority id via fast-path; "
|
||||
+ "some data might not have been read.");
|
||||
status = new SyncStatusInfo(
|
||||
proto.readInt(SyncStatusProto.StatusInfo.AUTHORITY_ID), status);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME:
|
||||
status.lastSuccessTime = proto.readLong(
|
||||
SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE:
|
||||
status.lastSuccessSource = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_TIME:
|
||||
status.lastFailureTime = proto.readLong(
|
||||
SyncStatusProto.StatusInfo.LAST_FAILURE_TIME);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE:
|
||||
status.lastFailureSource = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE:
|
||||
status.lastFailureMesg = proto.readString(
|
||||
SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME:
|
||||
status.initialFailureTime = proto.readLong(
|
||||
SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.PENDING:
|
||||
status.pending = proto.readBoolean(SyncStatusProto.StatusInfo.PENDING);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.INITIALIZE:
|
||||
status.initialize = proto.readBoolean(SyncStatusProto.StatusInfo.INITIALIZE);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES:
|
||||
status.addPeriodicSyncTime(
|
||||
proto.readLong(SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES));
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.LAST_EVENT_INFO:
|
||||
final long eventToken = proto.start(SyncStatusProto.StatusInfo.LAST_EVENT_INFO);
|
||||
final Pair<Long, String> lastEventInfo = parseLastEventInfoLocked(proto);
|
||||
if (lastEventInfo != null) {
|
||||
lastEventInformation.add(lastEventInfo);
|
||||
}
|
||||
proto.end(eventToken);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME:
|
||||
status.lastTodayResetTime = proto.readLong(
|
||||
SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.TOTAL_STATS:
|
||||
final long totalStatsToken = proto.start(
|
||||
SyncStatusProto.StatusInfo.TOTAL_STATS);
|
||||
readSyncStatusStatsLocked(proto, status.totalStats);
|
||||
proto.end(totalStatsToken);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.TODAY_STATS:
|
||||
final long todayStatsToken = proto.start(
|
||||
SyncStatusProto.StatusInfo.TODAY_STATS);
|
||||
readSyncStatusStatsLocked(proto, status.todayStats);
|
||||
proto.end(todayStatsToken);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.YESTERDAY_STATS:
|
||||
final long yesterdayStatsToken = proto.start(
|
||||
SyncStatusProto.StatusInfo.YESTERDAY_STATS);
|
||||
readSyncStatusStatsLocked(proto, status.yesterdayStats);
|
||||
proto.end(yesterdayStatsToken);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES:
|
||||
final long successTime = proto.readLong(
|
||||
SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES);
|
||||
if (successTimesCount == status.perSourceLastSuccessTimes.length) {
|
||||
Slog.w(TAG, "Attempted to read more per source last success times "
|
||||
+ "than expected; data might be corrupted.");
|
||||
break;
|
||||
}
|
||||
status.perSourceLastSuccessTimes[successTimesCount] = successTime;
|
||||
successTimesCount++;
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES:
|
||||
final long failureTime = proto.readLong(
|
||||
SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES);
|
||||
if (failureTimesCount == status.perSourceLastFailureTimes.length) {
|
||||
Slog.w(TAG, "Attempted to read more per source last failure times "
|
||||
+ "than expected; data might be corrupted.");
|
||||
break;
|
||||
}
|
||||
status.perSourceLastFailureTimes[failureTimesCount] = failureTime;
|
||||
failureTimesCount++;
|
||||
break;
|
||||
case ProtoInputStream.NO_MORE_FIELDS:
|
||||
status.populateLastEventsInformation(lastEventInformation);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<Long, String> parseLastEventInfoLocked(ProtoInputStream proto) throws IOException {
|
||||
long time = 0;
|
||||
String message = null;
|
||||
while (true) {
|
||||
switch (proto.nextField()) {
|
||||
case (int) SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME:
|
||||
time = proto.readLong(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT:
|
||||
message = proto.readString(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT);
|
||||
break;
|
||||
case ProtoInputStream.NO_MORE_FIELDS:
|
||||
return message == null ? null : new Pair<>(time, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readSyncStatusStatsLocked(ProtoInputStream proto, SyncStatusInfo.Stats stats)
|
||||
throws IOException {
|
||||
while (true) {
|
||||
switch (proto.nextField()) {
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME:
|
||||
stats.totalElapsedTime = proto.readLong(
|
||||
SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_SYNCS:
|
||||
stats.numSyncs = proto.readInt(SyncStatusProto.StatusInfo.Stats.NUM_SYNCS);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_FAILURES:
|
||||
stats.numFailures = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.Stats.NUM_FAILURES);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_CANCELS:
|
||||
stats.numCancels = proto.readInt(SyncStatusProto.StatusInfo.Stats.NUM_CANCELS);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER:
|
||||
stats.numSourceOther = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL:
|
||||
stats.numSourceLocal = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL:
|
||||
stats.numSourcePoll = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER:
|
||||
stats.numSourceUser = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC:
|
||||
stats.numSourcePeriodic = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC);
|
||||
break;
|
||||
case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED:
|
||||
stats.numSourceFeed = proto.readInt(
|
||||
SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED);
|
||||
break;
|
||||
case ProtoInputStream.NO_MORE_FIELDS:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all sync status to the sync status file.
|
||||
*/
|
||||
private void writeStatusLocked() {
|
||||
@VisibleForTesting
|
||||
void writeStatusLocked() {
|
||||
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||
Slog.v(TAG_FILE, "Writing new " + mStatusFile.getBaseFile());
|
||||
}
|
||||
@@ -2070,26 +2315,87 @@ public class SyncStorageEngine {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = mStatusFile.startWrite();
|
||||
Parcel out = Parcel.obtain();
|
||||
final int N = mSyncStatus.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
SyncStatusInfo status = mSyncStatus.valueAt(i);
|
||||
out.writeInt(STATUS_FILE_ITEM);
|
||||
status.writeToParcel(out, 0);
|
||||
}
|
||||
out.writeInt(STATUS_FILE_END);
|
||||
fos.write(out.marshall());
|
||||
out.recycle();
|
||||
|
||||
writeStatusInfoLocked(fos);
|
||||
mStatusFile.finishWrite(fos);
|
||||
} catch (java.io.IOException e1) {
|
||||
Slog.w(TAG, "Error writing status", e1);
|
||||
if (fos != null) {
|
||||
mStatusFile.failWrite(fos);
|
||||
}
|
||||
fos = null;
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
Slog.e(TAG, "Unable to write sync status to proto.", e);
|
||||
} finally {
|
||||
// when fos is null (successful write), this is a no-op.
|
||||
mStatusFile.failWrite(fos);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeStatusInfoLocked(OutputStream out) {
|
||||
final ProtoOutputStream proto = new ProtoOutputStream(out);
|
||||
final int size = mSyncStatus.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
final SyncStatusInfo info = mSyncStatus.valueAt(i);
|
||||
final long token = proto.start(SyncStatusProto.STATUS);
|
||||
// authority id should be written first to take advantage of the fast path in read
|
||||
proto.write(SyncStatusProto.StatusInfo.AUTHORITY_ID, info.authorityId);
|
||||
proto.write(SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME, info.lastSuccessTime);
|
||||
proto.write(SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE, info.lastSuccessSource);
|
||||
proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_TIME, info.lastFailureTime);
|
||||
proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE, info.lastFailureSource);
|
||||
proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE, info.lastFailureMesg);
|
||||
proto.write(SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME, info.initialFailureTime);
|
||||
proto.write(SyncStatusProto.StatusInfo.PENDING, info.pending);
|
||||
proto.write(SyncStatusProto.StatusInfo.INITIALIZE, info.initialize);
|
||||
final int periodicSyncTimesSize = info.getPeriodicSyncTimesSize();
|
||||
for (int j = 0; j < periodicSyncTimesSize; j++) {
|
||||
proto.write(SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES,
|
||||
info.getPeriodicSyncTime(j));
|
||||
}
|
||||
final int lastEventsSize = info.getEventCount();
|
||||
for (int j = 0; j < lastEventsSize; j++) {
|
||||
final long eventToken = proto.start(SyncStatusProto.StatusInfo.LAST_EVENT_INFO);
|
||||
proto.write(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME,
|
||||
info.getEventTime(j));
|
||||
proto.write(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT, info.getEvent(j));
|
||||
proto.end(eventToken);
|
||||
}
|
||||
proto.write(SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME, info.lastTodayResetTime);
|
||||
|
||||
final long totalStatsToken = proto.start(SyncStatusProto.StatusInfo.TOTAL_STATS);
|
||||
writeStatusStatsLocked(proto, info.totalStats);
|
||||
proto.end(totalStatsToken);
|
||||
final long todayStatsToken = proto.start(SyncStatusProto.StatusInfo.TODAY_STATS);
|
||||
writeStatusStatsLocked(proto, info.todayStats);
|
||||
proto.end(todayStatsToken);
|
||||
final long yesterdayStatsToken = proto.start(
|
||||
SyncStatusProto.StatusInfo.YESTERDAY_STATS);
|
||||
writeStatusStatsLocked(proto, info.yesterdayStats);
|
||||
proto.end(yesterdayStatsToken);
|
||||
|
||||
final int lastSuccessTimesSize = info.perSourceLastSuccessTimes.length;
|
||||
for (int j = 0; j < lastSuccessTimesSize; j++) {
|
||||
proto.write(SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES,
|
||||
info.perSourceLastSuccessTimes[j]);
|
||||
}
|
||||
final int lastFailureTimesSize = info.perSourceLastFailureTimes.length;
|
||||
for (int j = 0; j < lastFailureTimesSize; j++) {
|
||||
proto.write(SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES,
|
||||
info.perSourceLastFailureTimes[j]);
|
||||
}
|
||||
proto.end(token);
|
||||
}
|
||||
proto.flush();
|
||||
}
|
||||
|
||||
private void writeStatusStatsLocked(ProtoOutputStream proto, SyncStatusInfo.Stats stats) {
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME, stats.totalElapsedTime);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SYNCS, stats.numSyncs);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_FAILURES, stats.numFailures);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_CANCELS, stats.numCancels);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER, stats.numSourceOther);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL, stats.numSourceLocal);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL, stats.numSourcePoll);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER, stats.numSourceUser);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC, stats.numSourcePeriodic);
|
||||
proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED, stats.numSourceFeed);
|
||||
}
|
||||
|
||||
private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras,
|
||||
@SyncExemption int syncExemptionFlag, int callingUid, int callingPid) {
|
||||
if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
|
||||
@@ -2126,20 +2432,17 @@ public class SyncStorageEngine {
|
||||
public static final int STATISTICS_FILE_ITEM_OLD = 100;
|
||||
public static final int STATISTICS_FILE_ITEM = 101;
|
||||
|
||||
/**
|
||||
* Read all sync statistics back in to the initial engine state.
|
||||
*/
|
||||
private void readStatisticsLocked() {
|
||||
private void readStatsParcelLocked(File parcel) {
|
||||
try {
|
||||
byte[] data = mStatisticsFile.readFully();
|
||||
final AtomicFile parcelFile = new AtomicFile(parcel);
|
||||
byte[] data = parcelFile.readFully();
|
||||
Parcel in = Parcel.obtain();
|
||||
in.unmarshall(data, 0, data.length);
|
||||
in.setDataPosition(0);
|
||||
int token;
|
||||
int index = 0;
|
||||
while ((token=in.readInt()) != STATISTICS_FILE_END) {
|
||||
if (token == STATISTICS_FILE_ITEM
|
||||
|| token == STATISTICS_FILE_ITEM_OLD) {
|
||||
if (token == STATISTICS_FILE_ITEM || token == STATISTICS_FILE_ITEM_OLD) {
|
||||
int day = in.readInt();
|
||||
if (token == STATISTICS_FILE_ITEM_OLD) {
|
||||
day = day - 2009 + 14245; // Magic!
|
||||
@@ -2159,15 +2462,110 @@ public class SyncStorageEngine {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (java.io.IOException e) {
|
||||
} catch (IOException e) {
|
||||
Slog.i(TAG, "No initial statistics");
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeStatisticsIfNeededLocked() {
|
||||
final File parcelStats = new File(mSyncDir, LEGACY_STATISTICS_FILE_NAME);
|
||||
if (parcelStats.exists() && !mStatisticsFile.exists()) {
|
||||
readStatsParcelLocked(parcelStats);
|
||||
writeStatisticsLocked();
|
||||
}
|
||||
|
||||
// if upgrade to proto was successful, delete parcel file
|
||||
if (DELETE_LEGACY_PARCEL_FILES && mStatisticsFile.exists()) {
|
||||
parcelStats.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all sync statistics back in to the initial engine state.
|
||||
*/
|
||||
private void readStatisticsLocked() {
|
||||
upgradeStatisticsIfNeededLocked();
|
||||
|
||||
if (!mStatisticsFile.exists()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
try (FileInputStream in = mStatisticsFile.openRead()) {
|
||||
readDayStatsLocked(in);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Unable to read day stats file.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void readDayStatsLocked(InputStream in) throws IOException {
|
||||
final ProtoInputStream proto = new ProtoInputStream(in);
|
||||
int statsCount = 0;
|
||||
while (true) {
|
||||
switch (proto.nextField()) {
|
||||
case (int) SyncStatisticsProto.STATS:
|
||||
final long token = proto.start(SyncStatisticsProto.STATS);
|
||||
final DayStats stats = readIndividualDayStatsLocked(proto);
|
||||
proto.end(token);
|
||||
mDayStats[statsCount] = stats;
|
||||
statsCount++;
|
||||
if (statsCount == mDayStats.length) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ProtoInputStream.NO_MORE_FIELDS:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DayStats readIndividualDayStatsLocked(ProtoInputStream proto) throws IOException {
|
||||
DayStats stats;
|
||||
if (proto.nextField(SyncStatisticsProto.DayStats.DAY)) {
|
||||
// fast-path; this should work for most cases since the day is written first
|
||||
stats = new DayStats(proto.readInt(SyncStatisticsProto.DayStats.DAY));
|
||||
} else {
|
||||
// placeholder to read other data; assume the default day as 0
|
||||
stats = new DayStats(0);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
switch (proto.nextField()) {
|
||||
case (int) SyncStatisticsProto.DayStats.DAY:
|
||||
// fast-path failed for some reason, rebuild stats from placeholder object
|
||||
Slog.w(TAG, "Failed to read the day via fast-path; some data "
|
||||
+ "might not have been read.");
|
||||
final DayStats temp = new DayStats(
|
||||
proto.readInt(SyncStatisticsProto.DayStats.DAY));
|
||||
temp.successCount = stats.successCount;
|
||||
temp.successTime = stats.successTime;
|
||||
temp.failureCount = stats.failureCount;
|
||||
temp.failureTime = stats.failureTime;
|
||||
stats = temp;
|
||||
break;
|
||||
case (int) SyncStatisticsProto.DayStats.SUCCESS_COUNT:
|
||||
stats.successCount = proto.readInt(SyncStatisticsProto.DayStats.SUCCESS_COUNT);
|
||||
break;
|
||||
case (int) SyncStatisticsProto.DayStats.SUCCESS_TIME:
|
||||
stats.successTime = proto.readLong(SyncStatisticsProto.DayStats.SUCCESS_TIME);
|
||||
break;
|
||||
case (int) SyncStatisticsProto.DayStats.FAILURE_COUNT:
|
||||
stats.failureCount = proto.readInt(SyncStatisticsProto.DayStats.FAILURE_COUNT);
|
||||
break;
|
||||
case (int) SyncStatisticsProto.DayStats.FAILURE_TIME:
|
||||
stats.failureTime = proto.readLong(SyncStatisticsProto.DayStats.FAILURE_TIME);
|
||||
break;
|
||||
case ProtoInputStream.NO_MORE_FIELDS:
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write all sync statistics to the sync status file.
|
||||
*/
|
||||
private void writeStatisticsLocked() {
|
||||
@VisibleForTesting
|
||||
void writeStatisticsLocked() {
|
||||
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||
Slog.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
|
||||
}
|
||||
@@ -2179,33 +2577,38 @@ public class SyncStorageEngine {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = mStatisticsFile.startWrite();
|
||||
Parcel out = Parcel.obtain();
|
||||
final int N = mDayStats.length;
|
||||
for (int i=0; i<N; i++) {
|
||||
DayStats ds = mDayStats[i];
|
||||
if (ds == null) {
|
||||
break;
|
||||
}
|
||||
out.writeInt(STATISTICS_FILE_ITEM);
|
||||
out.writeInt(ds.day);
|
||||
out.writeInt(ds.successCount);
|
||||
out.writeLong(ds.successTime);
|
||||
out.writeInt(ds.failureCount);
|
||||
out.writeLong(ds.failureTime);
|
||||
}
|
||||
out.writeInt(STATISTICS_FILE_END);
|
||||
fos.write(out.marshall());
|
||||
out.recycle();
|
||||
|
||||
writeDayStatsLocked(fos);
|
||||
mStatisticsFile.finishWrite(fos);
|
||||
} catch (java.io.IOException e1) {
|
||||
Slog.w(TAG, "Error writing stats", e1);
|
||||
if (fos != null) {
|
||||
mStatisticsFile.failWrite(fos);
|
||||
}
|
||||
fos = null;
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
Slog.e(TAG, "Unable to write day stats to proto.", e);
|
||||
} finally {
|
||||
// when fos is null (successful write), this is a no-op.
|
||||
mStatisticsFile.failWrite(fos);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDayStatsLocked(OutputStream out)
|
||||
throws IOException, IllegalArgumentException {
|
||||
final ProtoOutputStream proto = new ProtoOutputStream(out);
|
||||
final int size = mDayStats.length;
|
||||
for (int i = 0; i < size; i++) {
|
||||
final DayStats stats = mDayStats[i];
|
||||
if (stats == null) {
|
||||
break;
|
||||
}
|
||||
final long token = proto.start(SyncStatisticsProto.STATS);
|
||||
// day should be written first to take advantage of the fast path in read
|
||||
proto.write(SyncStatisticsProto.DayStats.DAY, stats.day);
|
||||
proto.write(SyncStatisticsProto.DayStats.SUCCESS_COUNT, stats.successCount);
|
||||
proto.write(SyncStatisticsProto.DayStats.SUCCESS_TIME, stats.successTime);
|
||||
proto.write(SyncStatisticsProto.DayStats.FAILURE_COUNT, stats.failureCount);
|
||||
proto.write(SyncStatisticsProto.DayStats.FAILURE_TIME, stats.failureTime);
|
||||
proto.end(token);
|
||||
}
|
||||
proto.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the BackupManager know that account sync settings have changed. This will trigger
|
||||
* {@link com.android.server.backup.SystemBackupAgent} to run.
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SyncStatusInfo;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Tests for {@link SyncStorageEngine}.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SyncStorageEngineTest {
|
||||
|
||||
private Context mContext;
|
||||
private SyncStorageEngine mSyncStorageEngine;
|
||||
|
||||
private static final int NUM_SYNC_STATUS = 100;
|
||||
private static final int NUM_PERIODIC_SYNC_TIMES = 20;
|
||||
private static final int NUM_EVENTS = 10;
|
||||
private static final int NUM_SOURCES = 6;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mSyncStorageEngine = SyncStorageEngine.newTestInstance(mContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatisticsReadWrite() {
|
||||
populateDayStats(mSyncStorageEngine.mDayStats);
|
||||
mSyncStorageEngine.writeStatisticsLocked();
|
||||
|
||||
final SyncStorageEngine other = SyncStorageEngine.newTestInstance(mContext);
|
||||
verifyDayStats(mSyncStorageEngine.mDayStats, other.getDayStatistics());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatusReadWrite() {
|
||||
populateStatus(mSyncStorageEngine.mSyncStatus);
|
||||
mSyncStorageEngine.writeStatusLocked();
|
||||
|
||||
final SyncStorageEngine other = SyncStorageEngine.newTestInstance(mContext);
|
||||
for (int i = 0; i < NUM_SYNC_STATUS; i++) {
|
||||
other.mAuthorities.put(i, null);
|
||||
}
|
||||
other.readStatusLocked();
|
||||
verifyStatus(mSyncStorageEngine.mSyncStatus, other.mSyncStatus);
|
||||
}
|
||||
|
||||
private void populateDayStats(SyncStorageEngine.DayStats[] dayStats) {
|
||||
final Random r = new Random(1);
|
||||
for (int i = 0; i < dayStats.length; i++) {
|
||||
final SyncStorageEngine.DayStats ds = new SyncStorageEngine.DayStats(i);
|
||||
ds.successCount = r.nextInt();
|
||||
ds.successTime = r.nextLong();
|
||||
ds.failureCount = r.nextInt();
|
||||
ds.failureTime = r.nextLong();
|
||||
dayStats[i] = ds;
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyDayStats(SyncStorageEngine.DayStats[] dayStats,
|
||||
SyncStorageEngine.DayStats[] dayStatsOther) {
|
||||
assertEquals(dayStatsOther.length, dayStats.length);
|
||||
for (int i = 0; i < dayStatsOther.length; i++) {
|
||||
final SyncStorageEngine.DayStats ds = dayStats[i];
|
||||
final SyncStorageEngine.DayStats dsOther = dayStatsOther[i];
|
||||
assertEquals(dsOther.day, ds.day);
|
||||
assertEquals(dsOther.successCount, ds.successCount);
|
||||
assertEquals(dsOther.successTime, ds.successTime);
|
||||
assertEquals(dsOther.failureCount, ds.failureCount);
|
||||
assertEquals(dsOther.failureTime, ds.failureTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateStatus(SparseArray<SyncStatusInfo> syncStatus) {
|
||||
final Random r = new Random(1);
|
||||
for (int i = 0; i < NUM_SYNC_STATUS; i++) {
|
||||
final SyncStatusInfo ss = new SyncStatusInfo(i);
|
||||
ss.lastSuccessTime = r.nextLong();
|
||||
ss.lastSuccessSource = r.nextInt();
|
||||
ss.lastFailureTime = r.nextLong();
|
||||
ss.lastFailureSource = r.nextInt();
|
||||
ss.lastFailureMesg = "fail_msg_" + r.nextInt();
|
||||
ss.initialFailureTime = r.nextLong();
|
||||
ss.initialize = r.nextBoolean();
|
||||
for (int j = 0; j < NUM_PERIODIC_SYNC_TIMES; j++) {
|
||||
ss.addPeriodicSyncTime(r.nextLong());
|
||||
}
|
||||
final ArrayList<Pair<Long, String>> lastEventInfos = new ArrayList<>();
|
||||
for (int j = 0; j < NUM_EVENTS; j++) {
|
||||
lastEventInfos.add(new Pair<>(r.nextLong(), "event_" + r.nextInt()));
|
||||
}
|
||||
ss.populateLastEventsInformation(lastEventInfos);
|
||||
ss.lastTodayResetTime = r.nextLong();
|
||||
populateStats(ss.totalStats, r);
|
||||
populateStats(ss.todayStats, r);
|
||||
populateStats(ss.yesterdayStats, r);
|
||||
for (int j = 0; j < NUM_SOURCES; j++) {
|
||||
ss.perSourceLastSuccessTimes[j] = r.nextLong();
|
||||
}
|
||||
for (int j = 0; j < NUM_SOURCES; j++) {
|
||||
ss.perSourceLastFailureTimes[j] = r.nextLong();
|
||||
}
|
||||
syncStatus.put(i, ss);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateStats(SyncStatusInfo.Stats stats, Random r) {
|
||||
stats.totalElapsedTime = r.nextLong();
|
||||
stats.numSyncs = r.nextInt();
|
||||
stats.numFailures = r.nextInt();
|
||||
stats.numCancels = r.nextInt();
|
||||
stats.numSourceOther = r.nextInt();
|
||||
stats.numSourceLocal = r.nextInt();
|
||||
stats.numSourcePoll = r.nextInt();
|
||||
stats.numSourceUser = r.nextInt();
|
||||
stats.numSourcePeriodic = r.nextInt();
|
||||
stats.numSourceFeed = r.nextInt();
|
||||
}
|
||||
|
||||
private void verifyStatus(SparseArray<SyncStatusInfo> syncStatus,
|
||||
SparseArray<SyncStatusInfo> syncStatusOther) {
|
||||
assertEquals(syncStatusOther.size(), syncStatus.size());
|
||||
for (int i = 0; i < NUM_SYNC_STATUS; i++) {
|
||||
final SyncStatusInfo ss = syncStatus.valueAt(i);
|
||||
final SyncStatusInfo ssOther = syncStatusOther.valueAt(i);
|
||||
assertEquals(ssOther.authorityId, ss.authorityId);
|
||||
assertEquals(ssOther.lastSuccessTime, ss.lastSuccessTime);
|
||||
assertEquals(ssOther.lastSuccessSource, ss.lastSuccessSource);
|
||||
assertEquals(ssOther.lastFailureTime, ss.lastFailureTime);
|
||||
assertEquals(ssOther.lastFailureSource, ss.lastFailureSource);
|
||||
assertEquals(ssOther.lastFailureMesg, ss.lastFailureMesg);
|
||||
assertFalse(ssOther.pending); // pending is always set to false when read
|
||||
assertEquals(ssOther.initialize, ss.initialize);
|
||||
assertEquals(ssOther.getPeriodicSyncTimesSize(), NUM_PERIODIC_SYNC_TIMES);
|
||||
for (int j = 0; j < NUM_PERIODIC_SYNC_TIMES; j++) {
|
||||
assertEquals(ssOther.getPeriodicSyncTime(j), ss.getPeriodicSyncTime(j));
|
||||
}
|
||||
assertEquals(ssOther.getEventCount(), NUM_EVENTS);
|
||||
for (int j = 0; j < NUM_EVENTS; j++) {
|
||||
assertEquals(ssOther.getEventTime(j), ss.getEventTime(j));
|
||||
assertEquals(ssOther.getEvent(j), ss.getEvent(j));
|
||||
}
|
||||
assertEquals(ssOther.lastTodayResetTime, ss.lastTodayResetTime);
|
||||
verifyStats(ss.totalStats, ssOther.totalStats);
|
||||
verifyStats(ss.todayStats, ssOther.todayStats);
|
||||
verifyStats(ss.yesterdayStats, ssOther.yesterdayStats);
|
||||
assertEquals(ssOther.perSourceLastSuccessTimes.length, NUM_SOURCES);
|
||||
for (int j = 0; j < NUM_SOURCES; j++) {
|
||||
assertEquals(ssOther.perSourceLastSuccessTimes[j], ss.perSourceLastSuccessTimes[j]);
|
||||
}
|
||||
assertEquals(ssOther.perSourceLastFailureTimes.length, NUM_SOURCES);
|
||||
for (int j = 0; j < NUM_SOURCES; j++) {
|
||||
assertEquals(ssOther.perSourceLastFailureTimes[j], ss.perSourceLastFailureTimes[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyStats(SyncStatusInfo.Stats stats, SyncStatusInfo.Stats statsOther) {
|
||||
assertEquals(statsOther.totalElapsedTime, stats.totalElapsedTime);
|
||||
assertEquals(statsOther.numSyncs, stats.numSyncs);
|
||||
assertEquals(statsOther.numFailures, stats.numFailures);
|
||||
assertEquals(statsOther.numCancels, stats.numCancels);
|
||||
assertEquals(statsOther.numSourceOther, stats.numSourceOther);
|
||||
assertEquals(statsOther.numSourceLocal, stats.numSourceLocal);
|
||||
assertEquals(statsOther.numSourcePoll, stats.numSourcePoll);
|
||||
assertEquals(statsOther.numSourceUser, stats.numSourceUser);
|
||||
assertEquals(statsOther.numSourcePeriodic, stats.numSourcePeriodic);
|
||||
assertEquals(statsOther.numSourceFeed, stats.numSourceFeed);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user