Merge "Use pending.xml to persist sync ops." into klp-dev

This commit is contained in:
Matthew Williams
2013-08-16 23:10:57 +00:00
committed by Android (Google) Code Review
3 changed files with 234 additions and 227 deletions

View File

@@ -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;

View File

@@ -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");

View File

@@ -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));
} }
/** /**