Merge "Use pending.xml to persist sync ops." into klp-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
0c5b96b1cd
@@ -2889,11 +2889,12 @@ public class SyncManager {
|
|||||||
// determine if we need to set or cancel the alarm
|
// determine if we need to set or cancel the alarm
|
||||||
boolean shouldSet = false;
|
boolean shouldSet = false;
|
||||||
boolean shouldCancel = false;
|
boolean shouldCancel = false;
|
||||||
final boolean alarmIsActive = mAlarmScheduleTime != null;
|
final boolean alarmIsActive = (mAlarmScheduleTime != null) && (now < mAlarmScheduleTime);
|
||||||
final boolean needAlarm = alarmTime != Long.MAX_VALUE;
|
final boolean needAlarm = alarmTime != Long.MAX_VALUE;
|
||||||
if (needAlarm) {
|
if (needAlarm) {
|
||||||
// Need the alarm if it's currently not set, or if our time is before the currently
|
// Need the alarm if
|
||||||
// set time.
|
// - it's currently not set
|
||||||
|
// - if the alarm is set in the past.
|
||||||
if (!alarmIsActive || alarmTime < mAlarmScheduleTime) {
|
if (!alarmIsActive || alarmTime < mAlarmScheduleTime) {
|
||||||
shouldSet = true;
|
shouldSet = true;
|
||||||
}
|
}
|
||||||
@@ -2910,7 +2911,7 @@ public class SyncManager {
|
|||||||
+ " secs from now");
|
+ " secs from now");
|
||||||
}
|
}
|
||||||
mAlarmScheduleTime = alarmTime;
|
mAlarmScheduleTime = alarmTime;
|
||||||
mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime,
|
mAlarmService.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime,
|
||||||
mSyncAlarmIntent);
|
mSyncAlarmIntent);
|
||||||
} else if (shouldCancel) {
|
} else if (shouldCancel) {
|
||||||
mAlarmScheduleTime = null;
|
mAlarmScheduleTime = null;
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import org.xmlpull.v1.XmlSerializer;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -71,7 +72,7 @@ public class SyncStorageEngine extends Handler {
|
|||||||
|
|
||||||
private static final String TAG = "SyncManager";
|
private static final String TAG = "SyncManager";
|
||||||
private static final boolean DEBUG = true;
|
private static final boolean DEBUG = true;
|
||||||
private static final boolean DEBUG_FILE = true;
|
private static final String TAG_FILE = "SyncManagerFile";
|
||||||
|
|
||||||
private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
|
private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
|
||||||
private static final String XML_ATTR_LISTEN_FOR_TICKLES = "listen-for-tickles";
|
private static final String XML_ATTR_LISTEN_FOR_TICKLES = "listen-for-tickles";
|
||||||
@@ -420,9 +421,12 @@ public class SyncStorageEngine extends Handler {
|
|||||||
File systemDir = new File(dataDir, "system");
|
File systemDir = new File(dataDir, "system");
|
||||||
File syncDir = new File(systemDir, "sync");
|
File syncDir = new File(systemDir, "sync");
|
||||||
syncDir.mkdirs();
|
syncDir.mkdirs();
|
||||||
|
|
||||||
|
maybeDeleteLegacyPendingInfoLocked(syncDir);
|
||||||
|
|
||||||
mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
|
mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
|
||||||
mStatusFile = new AtomicFile(new File(syncDir, "status.bin"));
|
mStatusFile = new AtomicFile(new File(syncDir, "status.bin"));
|
||||||
mPendingFile = new AtomicFile(new File(syncDir, "pending.bin"));
|
mPendingFile = new AtomicFile(new File(syncDir, "pending.xml"));
|
||||||
mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"));
|
mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"));
|
||||||
|
|
||||||
readAccountInfoLocked();
|
readAccountInfoLocked();
|
||||||
@@ -676,7 +680,8 @@ public class SyncStorageEngine extends Handler {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
|
for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
|
||||||
if (providerName != null && !providerName.equals(authorityInfo.authority)) {
|
if (providerName != null
|
||||||
|
&& !providerName.equals(authorityInfo.authority)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (authorityInfo.backoffTime != nextSyncTime
|
if (authorityInfo.backoffTime != nextSyncTime
|
||||||
@@ -774,10 +779,12 @@ public class SyncStorageEngine extends Handler {
|
|||||||
}
|
}
|
||||||
synchronized (mAuthorities) {
|
synchronized (mAuthorities) {
|
||||||
if (toUpdate.period <= 0 && add) {
|
if (toUpdate.period <= 0 && add) {
|
||||||
Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + add);
|
Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-"
|
||||||
|
+ add);
|
||||||
}
|
}
|
||||||
if (toUpdate.extras == null) {
|
if (toUpdate.extras == null) {
|
||||||
Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-" + add);
|
Log.e(TAG, "null extras, should never happen in updateOrRemovePeriodicSync: add-"
|
||||||
|
+ add);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AuthorityInfo authority =
|
AuthorityInfo authority =
|
||||||
@@ -806,7 +813,7 @@ public class SyncStorageEngine extends Handler {
|
|||||||
if (!alreadyPresent) {
|
if (!alreadyPresent) {
|
||||||
authority.periodicSyncs.add(new PeriodicSync(toUpdate));
|
authority.periodicSyncs.add(new PeriodicSync(toUpdate));
|
||||||
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
|
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
|
||||||
status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0);
|
status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0L);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Remove any periodic syncs that match the authority and extras.
|
// Remove any periodic syncs that match the authority and extras.
|
||||||
@@ -824,7 +831,8 @@ public class SyncStorageEngine extends Handler {
|
|||||||
if (status != null) {
|
if (status != null) {
|
||||||
status.removePeriodicSyncTime(i);
|
status.removePeriodicSyncTime(i);
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "Tried removing sync status on remove periodic sync but did not find it.");
|
Log.e(TAG, "Tried removing sync status on remove periodic sync but"
|
||||||
|
+ "did not find it.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i++;
|
i++;
|
||||||
@@ -942,7 +950,7 @@ public class SyncStorageEngine extends Handler {
|
|||||||
op = new PendingOperation(op);
|
op = new PendingOperation(op);
|
||||||
op.authorityId = authority.ident;
|
op.authorityId = authority.ident;
|
||||||
mPendingOperations.add(op);
|
mPendingOperations.add(op);
|
||||||
writePendingOperationsLocked();
|
appendPendingOperationLocked(op);
|
||||||
|
|
||||||
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
|
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
|
||||||
status.pending = true;
|
status.pending = true;
|
||||||
@@ -1660,7 +1668,9 @@ public class SyncStorageEngine extends Handler {
|
|||||||
FileInputStream fis = null;
|
FileInputStream fis = null;
|
||||||
try {
|
try {
|
||||||
fis = mAccountInfoFile.openRead();
|
fis = mAccountInfoFile.openRead();
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile());
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile());
|
||||||
|
}
|
||||||
XmlPullParser parser = Xml.newPullParser();
|
XmlPullParser parser = Xml.newPullParser();
|
||||||
parser.setInput(fis, null);
|
parser.setInput(fis, null);
|
||||||
int eventType = parser.getEventType();
|
int eventType = parser.getEventType();
|
||||||
@@ -1744,6 +1754,20 @@ public class SyncStorageEngine extends Handler {
|
|||||||
maybeMigrateSettingsForRenamedAuthorities();
|
maybeMigrateSettingsForRenamedAuthorities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the old pending.bin is deleted, as it has been changed to pending.xml.
|
||||||
|
* pending.xml was used starting in KLP.
|
||||||
|
* @param syncDir directory where the sync files are located.
|
||||||
|
*/
|
||||||
|
private void maybeDeleteLegacyPendingInfoLocked(File syncDir) {
|
||||||
|
File file = new File(syncDir, "pending.bin");
|
||||||
|
if (!file.exists()) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* some authority names have changed. copy over their settings and delete the old ones
|
* some authority names have changed. copy over their settings and delete the old ones
|
||||||
* @return true if a change was made
|
* @return true if a change was made
|
||||||
@@ -1832,18 +1856,21 @@ public class SyncStorageEngine extends Handler {
|
|||||||
syncable = "unknown";
|
syncable = "unknown";
|
||||||
}
|
}
|
||||||
authority = mAuthorities.get(id);
|
authority = mAuthorities.get(id);
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Adding authority: account="
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
+ accountName + " auth=" + authorityName
|
Log.v(TAG, "Adding authority: account="
|
||||||
+ " user=" + userId
|
+ accountName + " auth=" + authorityName
|
||||||
+ " enabled=" + enabled
|
+ " user=" + userId
|
||||||
+ " syncable=" + syncable);
|
+ " enabled=" + enabled
|
||||||
|
+ " syncable=" + syncable);
|
||||||
|
}
|
||||||
if (authority == null) {
|
if (authority == null) {
|
||||||
if (DEBUG_FILE) {
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
Log.v(TAG, "Creating entry");
|
Log.v(TAG, "Creating entry");
|
||||||
}
|
}
|
||||||
if (accountName != null && accountType != null) {
|
if (accountName != null && accountType != null) {
|
||||||
authority = getOrCreateAuthorityLocked(
|
authority = getOrCreateAuthorityLocked(
|
||||||
new Account(accountName, accountType), userId, authorityName, id, false);
|
new Account(accountName, accountType), userId, authorityName, id,
|
||||||
|
false);
|
||||||
} else {
|
} else {
|
||||||
authority = getOrCreateAuthorityLocked(
|
authority = getOrCreateAuthorityLocked(
|
||||||
new ComponentName(packageName, className), userId, id, false);
|
new ComponentName(packageName, className), userId, id, false);
|
||||||
@@ -1943,7 +1970,9 @@ public class SyncStorageEngine extends Handler {
|
|||||||
* Write all account information to the account file.
|
* Write all account information to the account file.
|
||||||
*/
|
*/
|
||||||
private void writeAccountInfoLocked() {
|
private void writeAccountInfoLocked() {
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile());
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile());
|
||||||
|
}
|
||||||
FileOutputStream fos = null;
|
FileOutputStream fos = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -2041,7 +2070,9 @@ public class SyncStorageEngine extends Handler {
|
|||||||
final boolean hasType = db.getVersion() >= 11;
|
final boolean hasType = db.getVersion() >= 11;
|
||||||
|
|
||||||
// Copy in all of the status information, as well as accounts.
|
// Copy in all of the status information, as well as accounts.
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Reading legacy sync accounts db");
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG, "Reading legacy sync accounts db");
|
||||||
|
}
|
||||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||||
qb.setTables("stats, status");
|
qb.setTables("stats, status");
|
||||||
HashMap<String,String> map = new HashMap<String,String>();
|
HashMap<String,String> map = new HashMap<String,String>();
|
||||||
@@ -2151,7 +2182,9 @@ public class SyncStorageEngine extends Handler {
|
|||||||
* Read all sync status back in to the initial engine state.
|
* Read all sync status back in to the initial engine state.
|
||||||
*/
|
*/
|
||||||
private void readStatusLocked() {
|
private void readStatusLocked() {
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Reading " + mStatusFile.getBaseFile());
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG, "Reading " + mStatusFile.getBaseFile());
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
byte[] data = mStatusFile.readFully();
|
byte[] data = mStatusFile.readFully();
|
||||||
Parcel in = Parcel.obtain();
|
Parcel in = Parcel.obtain();
|
||||||
@@ -2163,8 +2196,10 @@ public class SyncStorageEngine extends Handler {
|
|||||||
SyncStatusInfo status = new SyncStatusInfo(in);
|
SyncStatusInfo status = new SyncStatusInfo(in);
|
||||||
if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
|
if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
|
||||||
status.pending = false;
|
status.pending = false;
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Adding status for id "
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
+ status.authorityId);
|
Log.v(TAG, "Adding status for id "
|
||||||
|
+ status.authorityId);
|
||||||
|
}
|
||||||
mSyncStatus.put(status.authorityId, status);
|
mSyncStatus.put(status.authorityId, status);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -2182,7 +2217,9 @@ public class SyncStorageEngine extends Handler {
|
|||||||
* Write all sync status to the sync status file.
|
* Write all sync status to the sync status file.
|
||||||
*/
|
*/
|
||||||
private void writeStatusLocked() {
|
private void writeStatusLocked() {
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatusFile.getBaseFile());
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG, "Writing new " + mStatusFile.getBaseFile());
|
||||||
|
}
|
||||||
|
|
||||||
// The file is being written, so we don't need to have a scheduled
|
// The file is being written, so we don't need to have a scheduled
|
||||||
// write until the next change.
|
// write until the next change.
|
||||||
@@ -2211,103 +2248,97 @@ public class SyncStorageEngine extends Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int PENDING_OPERATION_VERSION = 4;
|
public static final int PENDING_OPERATION_VERSION = 3;
|
||||||
|
|
||||||
/**
|
/** Read all pending operations back in to the initial engine state. */
|
||||||
* Read all pending operations back in to the initial engine state.
|
|
||||||
*/
|
|
||||||
private void readPendingOperationsLocked() {
|
private void readPendingOperationsLocked() {
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Reading " + mPendingFile.getBaseFile());
|
FileInputStream fis = null;
|
||||||
try {
|
if (!mPendingFile.getBaseFile().exists()) {
|
||||||
readPendingAsXml();
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
} catch (XmlPullParserException e) {
|
Log.v(TAG_FILE, "No pending operation file.");
|
||||||
Log.d(TAG, "Error parsing pending as xml, trying as parcel.");
|
return;
|
||||||
try {
|
|
||||||
readPendingAsParcelled();
|
|
||||||
} catch (java.io.IOException e1) {
|
|
||||||
Log.i(TAG, "No initial pending operations");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void readPendingAsXml() throws XmlPullParserException {
|
|
||||||
FileInputStream fis = null;
|
|
||||||
try {
|
try {
|
||||||
fis = mPendingFile.openRead();
|
fis = mPendingFile.openRead();
|
||||||
XmlPullParser parser = Xml.newPullParser();
|
XmlPullParser parser;
|
||||||
|
parser = Xml.newPullParser();
|
||||||
parser.setInput(fis, null);
|
parser.setInput(fis, null);
|
||||||
|
|
||||||
int eventType = parser.getEventType();
|
int eventType = parser.getEventType();
|
||||||
while (eventType != XmlPullParser.START_TAG &&
|
while (eventType != XmlPullParser.START_TAG &&
|
||||||
eventType != XmlPullParser.END_DOCUMENT) {
|
eventType != XmlPullParser.END_DOCUMENT) {
|
||||||
eventType = parser.next();
|
eventType = parser.next();
|
||||||
}
|
}
|
||||||
if (eventType == XmlPullParser.END_DOCUMENT) return;
|
if (eventType == XmlPullParser.END_DOCUMENT) return; // Nothing to read.
|
||||||
|
|
||||||
String tagName = parser.getName();
|
String tagName = parser.getName();
|
||||||
if ("pending".equals(tagName)) {
|
do {
|
||||||
int version = -1;
|
|
||||||
String versionString = parser.getAttributeValue(null, "version");
|
|
||||||
if (versionString == null ||
|
|
||||||
Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) {
|
|
||||||
Log.w(TAG, "Unknown pending operation version "
|
|
||||||
+ version + "; trying to read as binary.");
|
|
||||||
throw new XmlPullParserException("Unknown version.");
|
|
||||||
}
|
|
||||||
eventType = parser.next();
|
|
||||||
PendingOperation pop = null;
|
PendingOperation pop = null;
|
||||||
do {
|
if (eventType == XmlPullParser.START_TAG) {
|
||||||
if (eventType == XmlPullParser.START_TAG) {
|
try {
|
||||||
try {
|
tagName = parser.getName();
|
||||||
tagName = parser.getName();
|
if (parser.getDepth() == 1 && "op".equals(tagName)) {
|
||||||
if (parser.getDepth() == 2 && "op".equals(tagName)) {
|
// Verify version.
|
||||||
int authorityId = Integer.valueOf(parser.getAttributeValue(
|
String versionString =
|
||||||
null, XML_ATTR_AUTHORITYID));
|
parser.getAttributeValue(null, XML_ATTR_VERSION);
|
||||||
boolean expedited = Boolean.valueOf(parser.getAttributeValue(
|
if (versionString == null ||
|
||||||
null, XML_ATTR_EXPEDITED));
|
Integer.parseInt(versionString) != PENDING_OPERATION_VERSION) {
|
||||||
int syncSource = Integer.valueOf(parser.getAttributeValue(
|
Log.w(TAG, "Unknown pending operation version " + versionString);
|
||||||
null, XML_ATTR_SOURCE));
|
throw new java.io.IOException("Unknown version.");
|
||||||
int reason = Integer.valueOf(parser.getAttributeValue(
|
}
|
||||||
null, XML_ATTR_REASON));
|
int authorityId = Integer.valueOf(parser.getAttributeValue(
|
||||||
AuthorityInfo authority = mAuthorities.get(authorityId);
|
null, XML_ATTR_AUTHORITYID));
|
||||||
if (DEBUG_FILE) {
|
boolean expedited = Boolean.valueOf(parser.getAttributeValue(
|
||||||
Log.v(TAG, authorityId + " " + expedited + " " + syncSource + " " + reason);
|
null, XML_ATTR_EXPEDITED));
|
||||||
}
|
int syncSource = Integer.valueOf(parser.getAttributeValue(
|
||||||
if (authority != null) {
|
null, XML_ATTR_SOURCE));
|
||||||
pop = new PendingOperation(
|
int reason = Integer.valueOf(parser.getAttributeValue(
|
||||||
authority.account, authority.userId, reason, syncSource,
|
null, XML_ATTR_REASON));
|
||||||
authority.authority, new Bundle(), expedited);
|
AuthorityInfo authority = mAuthorities.get(authorityId);
|
||||||
pop.authorityId = authorityId;
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
pop.flatExtras = null; // No longer used.
|
Log.v(TAG_FILE, authorityId + " " + expedited + " " + syncSource + " "
|
||||||
mPendingOperations.add(pop);
|
+ reason);
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + pop.account
|
}
|
||||||
+ " auth=" + pop.authority
|
if (authority != null) {
|
||||||
|
pop = new PendingOperation(
|
||||||
|
authority.account, authority.userId, reason,
|
||||||
|
syncSource, authority.authority, new Bundle(),
|
||||||
|
expedited);
|
||||||
|
pop.flatExtras = null; // No longer used.
|
||||||
|
mPendingOperations.add(pop);
|
||||||
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG_FILE, "Adding pending op: "
|
||||||
|
+ pop.authority
|
||||||
+ " src=" + pop.syncSource
|
+ " src=" + pop.syncSource
|
||||||
+ " reason=" + pop.reason
|
+ " reason=" + pop.reason
|
||||||
+ " expedited=" + pop.expedited);
|
+ " expedited=" + pop.expedited);
|
||||||
} else {
|
|
||||||
// Skip non-existent authority;
|
|
||||||
pop = null;
|
|
||||||
if (DEBUG_FILE) {
|
|
||||||
Log.v(TAG, "No authority found for " + authorityId
|
|
||||||
+ ", skipping");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (parser.getDepth() == 3 &&
|
} else {
|
||||||
pop != null &&
|
// Skip non-existent authority.
|
||||||
"extra".equals(tagName)) {
|
pop = null;
|
||||||
parseExtra(parser, pop.extras);
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG_FILE, "No authority found for " + authorityId
|
||||||
|
+ ", skipping");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} else if (parser.getDepth() == 2 &&
|
||||||
Log.d(TAG, "Invalid data in xml file.", e);
|
pop != null &&
|
||||||
|
"extra".equals(tagName)) {
|
||||||
|
parseExtra(parser, pop.extras);
|
||||||
}
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.d(TAG, "Invalid data in xml file.", e);
|
||||||
}
|
}
|
||||||
eventType = parser.next();
|
}
|
||||||
} while(eventType != XmlPullParser.END_DOCUMENT);
|
eventType = parser.next();
|
||||||
}
|
} while(eventType != XmlPullParser.END_DOCUMENT);
|
||||||
} catch (java.io.IOException e) {
|
} catch (java.io.IOException e) {
|
||||||
if (fis == null) Log.i(TAG, "No initial pending operations.");
|
Log.w(TAG_FILE, "Error reading pending data.", e);
|
||||||
else Log.w(TAG, "Error reading pending data.", e);
|
} catch (XmlPullParserException e) {
|
||||||
return;
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.w(TAG_FILE, "Error parsing pending ops xml.", e);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (fis != null) {
|
if (fis != null) {
|
||||||
try {
|
try {
|
||||||
@@ -2316,57 +2347,96 @@ public class SyncStorageEngine extends Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String XML_ATTR_AUTHORITYID = "authority_id";
|
||||||
|
private static final String XML_ATTR_SOURCE = "source";
|
||||||
|
private static final String XML_ATTR_EXPEDITED = "expedited";
|
||||||
|
private static final String XML_ATTR_REASON = "reason";
|
||||||
|
private static final String XML_ATTR_VERSION = "version";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Old format of reading pending.bin as a parcelled file. Replaced in lieu of JSON because
|
* Write all currently pending ops to the pending ops file.
|
||||||
* persisting parcels is unsafe.
|
|
||||||
* @throws java.io.IOException
|
|
||||||
*/
|
*/
|
||||||
private void readPendingAsParcelled() throws java.io.IOException {
|
private void writePendingOperationsLocked() {
|
||||||
byte[] data = mPendingFile.readFully();
|
final int N = mPendingOperations.size();
|
||||||
Parcel in = Parcel.obtain();
|
FileOutputStream fos = null;
|
||||||
in.unmarshall(data, 0, data.length);
|
try {
|
||||||
in.setDataPosition(0);
|
if (N == 0) {
|
||||||
final int SIZE = in.dataSize();
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
while (in.dataPosition() < SIZE) {
|
Log.v(TAG_FILE, "Truncating " + mPendingFile.getBaseFile());
|
||||||
int version = in.readInt();
|
|
||||||
if (version != 3 && version != 1) {
|
|
||||||
Log.w(TAG, "Unknown pending operation version "
|
|
||||||
+ version + "; dropping all ops");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int authorityId = in.readInt();
|
|
||||||
int syncSource = in.readInt();
|
|
||||||
byte[] flatExtras = in.createByteArray();
|
|
||||||
boolean expedited;
|
|
||||||
if (version == PENDING_OPERATION_VERSION) {
|
|
||||||
expedited = in.readInt() != 0;
|
|
||||||
} else {
|
|
||||||
expedited = false;
|
|
||||||
}
|
|
||||||
int reason = in.readInt();
|
|
||||||
AuthorityInfo authority = mAuthorities.get(authorityId);
|
|
||||||
if (authority != null) {
|
|
||||||
Bundle extras;
|
|
||||||
if (flatExtras != null) {
|
|
||||||
extras = unflattenBundle(flatExtras);
|
|
||||||
} else {
|
|
||||||
// if we are unable to parse the extras for whatever reason convert this
|
|
||||||
// to a regular sync by creating an empty extras
|
|
||||||
extras = new Bundle();
|
|
||||||
}
|
}
|
||||||
PendingOperation op = new PendingOperation(
|
mPendingFile.truncate();
|
||||||
authority.account, authority.userId, reason, syncSource,
|
return;
|
||||||
authority.authority, extras, expedited);
|
|
||||||
op.authorityId = authorityId;
|
|
||||||
op.flatExtras = flatExtras;
|
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + op.account
|
|
||||||
+ " auth=" + op.authority
|
|
||||||
+ " src=" + op.syncSource
|
|
||||||
+ " reason=" + op.reason
|
|
||||||
+ " expedited=" + op.expedited
|
|
||||||
+ " extras=" + op.extras);
|
|
||||||
mPendingOperations.add(op);
|
|
||||||
}
|
}
|
||||||
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG_FILE, "Writing new " + mPendingFile.getBaseFile());
|
||||||
|
}
|
||||||
|
fos = mPendingFile.startWrite();
|
||||||
|
XmlSerializer out = new FastXmlSerializer();
|
||||||
|
out.setOutput(fos, "utf-8");
|
||||||
|
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
PendingOperation pop = mPendingOperations.get(i);
|
||||||
|
writePendingOperationLocked(pop, out);
|
||||||
|
}
|
||||||
|
out.endDocument();
|
||||||
|
mPendingFile.finishWrite(fos);
|
||||||
|
} catch (java.io.IOException e1) {
|
||||||
|
Log.w(TAG, "Error writing pending operations", e1);
|
||||||
|
if (fos != null) {
|
||||||
|
mPendingFile.failWrite(fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Write all currently pending ops to the pending ops file. */
|
||||||
|
private void writePendingOperationLocked(PendingOperation pop, XmlSerializer out)
|
||||||
|
throws IOException {
|
||||||
|
// Pending operation.
|
||||||
|
out.startTag(null, "op");
|
||||||
|
|
||||||
|
out.attribute(null, XML_ATTR_VERSION, Integer.toString(PENDING_OPERATION_VERSION));
|
||||||
|
out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId));
|
||||||
|
out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource));
|
||||||
|
out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited));
|
||||||
|
out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason));
|
||||||
|
extrasToXml(out, pop.extras);
|
||||||
|
|
||||||
|
out.endTag(null, "op");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append the given operation to the pending ops file; if unable to,
|
||||||
|
* write all pending ops.
|
||||||
|
*/
|
||||||
|
private void appendPendingOperationLocked(PendingOperation op) {
|
||||||
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
|
||||||
|
}
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fos = mPendingFile.openAppend();
|
||||||
|
} catch (java.io.IOException e) {
|
||||||
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG, "Failed append; writing full file");
|
||||||
|
}
|
||||||
|
writePendingOperationsLocked();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
XmlSerializer out = new FastXmlSerializer();
|
||||||
|
out.setOutput(fos, "utf-8");
|
||||||
|
writePendingOperationLocked(op, out);
|
||||||
|
out.endDocument();
|
||||||
|
mPendingFile.finishWrite(fos);
|
||||||
|
} catch (java.io.IOException e1) {
|
||||||
|
Log.w(TAG, "Error writing appending operation", e1);
|
||||||
|
mPendingFile.failWrite(fos);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
fos.close();
|
||||||
|
} catch (IOException e) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2399,54 +2469,6 @@ public class SyncStorageEngine extends Handler {
|
|||||||
return bundle;
|
return bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String XML_ATTR_AUTHORITYID = "authority_id";
|
|
||||||
private static final String XML_ATTR_SOURCE = "source";
|
|
||||||
private static final String XML_ATTR_EXPEDITED = "expedited";
|
|
||||||
private static final String XML_ATTR_REASON = "reason";
|
|
||||||
/**
|
|
||||||
* Write all currently pending ops to the pending ops file. TODO: Change this from xml
|
|
||||||
* so that we can append to this file as before.
|
|
||||||
*/
|
|
||||||
private void writePendingOperationsLocked() {
|
|
||||||
final int N = mPendingOperations.size();
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
|
||||||
if (N == 0) {
|
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Truncating " + mPendingFile.getBaseFile());
|
|
||||||
mPendingFile.truncate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Writing new " + mPendingFile.getBaseFile());
|
|
||||||
fos = mPendingFile.startWrite();
|
|
||||||
XmlSerializer out = new FastXmlSerializer();
|
|
||||||
out.setOutput(fos, "utf-8");
|
|
||||||
out.startDocument(null, true);
|
|
||||||
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
|
|
||||||
|
|
||||||
out.startTag(null, "pending");
|
|
||||||
out.attribute(null, "version", Integer.toString(PENDING_OPERATION_VERSION));
|
|
||||||
|
|
||||||
for (int i = 0; i < N; i++) {
|
|
||||||
PendingOperation pop = mPendingOperations.get(i);
|
|
||||||
out.startTag(null, "op");
|
|
||||||
out.attribute(null, XML_ATTR_AUTHORITYID, Integer.toString(pop.authorityId));
|
|
||||||
out.attribute(null, XML_ATTR_SOURCE, Integer.toString(pop.syncSource));
|
|
||||||
out.attribute(null, XML_ATTR_EXPEDITED, Boolean.toString(pop.expedited));
|
|
||||||
out.attribute(null, XML_ATTR_REASON, Integer.toString(pop.reason));
|
|
||||||
extrasToXml(out, pop.extras);
|
|
||||||
out.endTag(null, "op");
|
|
||||||
}
|
|
||||||
out.endTag(null, "pending");
|
|
||||||
out.endDocument();
|
|
||||||
mPendingFile.finishWrite(fos);
|
|
||||||
} catch (java.io.IOException e1) {
|
|
||||||
Log.w(TAG, "Error writing pending operations", e1);
|
|
||||||
if (fos != null) {
|
|
||||||
mPendingFile.failWrite(fos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void extrasToXml(XmlSerializer out, Bundle extras) throws java.io.IOException {
|
private void extrasToXml(XmlSerializer out, Bundle extras) throws java.io.IOException {
|
||||||
for (String key : extras.keySet()) {
|
for (String key : extras.keySet()) {
|
||||||
out.startTag(null, "extra");
|
out.startTag(null, "extra");
|
||||||
@@ -2479,35 +2501,6 @@ public class SyncStorageEngine extends Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Update the pending ops file, if e
|
|
||||||
// */
|
|
||||||
// private void appendPendingOperationLocked(PendingOperation op) {
|
|
||||||
// if (DEBUG_FILE) Log.v(TAG, "Appending to " + mPendingFile.getBaseFile());
|
|
||||||
// FileOutputStream fos = null;
|
|
||||||
// try {
|
|
||||||
// fos = mPendingFile.openAppend();
|
|
||||||
// } catch (java.io.IOException e) {
|
|
||||||
// if (DEBUG_FILE) Log.v(TAG, "Failed append; writing full file");
|
|
||||||
// writePendingOperationsLocked();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// try {
|
|
||||||
// Parcel out = Parcel.obtain();
|
|
||||||
// writePendingOperationLocked(op, out);
|
|
||||||
// fos.write(out.marshall());
|
|
||||||
// out.recycle();
|
|
||||||
// } catch (java.io.IOException e1) {
|
|
||||||
// Log.w(TAG, "Error writing pending operations", e1);
|
|
||||||
// } finally {
|
|
||||||
// try {
|
|
||||||
// fos.close();
|
|
||||||
// } catch (java.io.IOException e2) {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
private void requestSync(Account account, int userId, int reason, String authority,
|
private void requestSync(Account account, int userId, int reason, String authority,
|
||||||
Bundle extras) {
|
Bundle extras) {
|
||||||
// If this is happening in the system process, then call the syncrequest listener
|
// If this is happening in the system process, then call the syncrequest listener
|
||||||
@@ -2568,7 +2561,9 @@ public class SyncStorageEngine extends Handler {
|
|||||||
* Write all sync statistics to the sync status file.
|
* Write all sync statistics to the sync status file.
|
||||||
*/
|
*/
|
||||||
private void writeStatisticsLocked() {
|
private void writeStatisticsLocked() {
|
||||||
if (DEBUG_FILE) Log.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
|
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
|
||||||
|
Log.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
|
||||||
|
}
|
||||||
|
|
||||||
// The file is being written, so we don't need to have a scheduled
|
// The file is being written, so we don't need to have a scheduled
|
||||||
// write until the next change.
|
// write until the next change.
|
||||||
@@ -2611,7 +2606,7 @@ public class SyncStorageEngine extends Handler {
|
|||||||
sb.append("Pending Ops: ").append(mPendingOperations.size()).append(" operation(s)\n");
|
sb.append("Pending Ops: ").append(mPendingOperations.size()).append(" operation(s)\n");
|
||||||
for (PendingOperation pop : mPendingOperations) {
|
for (PendingOperation pop : mPendingOperations) {
|
||||||
sb.append("(" + pop.account)
|
sb.append("(" + pop.account)
|
||||||
.append(", " + pop.userId)
|
.append(", u" + pop.userId)
|
||||||
.append(", " + pop.authority)
|
.append(", " + pop.authority)
|
||||||
.append(", " + pop.extras)
|
.append(", " + pop.extras)
|
||||||
.append(")\n");
|
.append(")\n");
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public class SyncStorageEngineTest extends AndroidTestCase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that we handle the case of a history row being old enough to purge before the
|
* Test that we handle the case of a history row being old enough to purge before the
|
||||||
* correcponding sync is finished. This can happen if the clock changes while we are syncing.
|
* corresponding sync is finished. This can happen if the clock changes while we are syncing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// TODO: this test causes AidlTest to fail. Omit for now
|
// TODO: this test causes AidlTest to fail. Omit for now
|
||||||
@@ -104,6 +104,17 @@ public class SyncStorageEngineTest extends AndroidTestCase {
|
|||||||
engine.clearAndReadState();
|
engine.clearAndReadState();
|
||||||
|
|
||||||
assert(engine.getPendingOperationCount() == 1);
|
assert(engine.getPendingOperationCount() == 1);
|
||||||
|
List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations();
|
||||||
|
SyncStorageEngine.PendingOperation popRetrieved = pops.get(0);
|
||||||
|
assertEquals(pop.account, popRetrieved.account);
|
||||||
|
assertEquals(pop.reason, popRetrieved.reason);
|
||||||
|
assertEquals(pop.userId, popRetrieved.userId);
|
||||||
|
assertEquals(pop.syncSource, popRetrieved.syncSource);
|
||||||
|
assertEquals(pop.authority, popRetrieved.authority);
|
||||||
|
assertEquals(pop.expedited, popRetrieved.expedited);
|
||||||
|
assertEquals(pop.serviceName, popRetrieved.serviceName);
|
||||||
|
assert(android.content.PeriodicSync.syncExtrasEquals(pop.extras, popRetrieved.extras));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user