summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/input/EventHub.cpp31
-rw-r--r--services/input/EventHub.h2
-rw-r--r--services/input/InputReader.h2
-rw-r--r--services/java/com/android/server/BackupManagerService.java1
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java265
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java20
-rw-r--r--services/java/com/android/server/am/ProcessList.java135
-rw-r--r--services/java/com/android/server/content/ContentService.java305
-rw-r--r--services/java/com/android/server/content/SyncManager.java1013
-rw-r--r--services/java/com/android/server/content/SyncOperation.java214
-rw-r--r--services/java/com/android/server/content/SyncQueue.java134
-rw-r--r--services/java/com/android/server/content/SyncStorageEngine.java1317
-rw-r--r--services/java/com/android/server/firewall/IntentFirewall.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java343
14 files changed, 2529 insertions, 1263 deletions
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 4d70d5f..cd313c4 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -49,6 +49,7 @@
#include <sys/ioctl.h>
#include <sys/limits.h>
#include <sys/sha1.h>
+#include <sys/utsname.h>
/* this macro is used to tell if "bit" is set in "array"
* it selects a byte from the array, and does a boolean AND
@@ -93,6 +94,14 @@ static String8 sha1(const String8& in) {
return out;
}
+static void getLinuxRelease(int* major, int* minor) {
+ struct utsname info;
+ if (uname(&info) || sscanf(info.release, "%d.%d", major, minor) <= 0) {
+ *major = 0, *minor = 0;
+ ALOGE("Could not get linux version: %s", strerror(errno));
+ }
+}
+
static void setDescriptor(InputDeviceIdentifier& identifier) {
// Compute a device descriptor that uniquely identifies the device.
// The descriptor is assumed to be a stable identifier. Its value should not
@@ -236,6 +245,11 @@ EventHub::EventHub(void) :
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
+
+ int major, minor;
+ getLinuxRelease(&major, &minor);
+ // EPOLLWAKEUP was introduced in kernel 3.5
+ mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
EventHub::~EventHub(void) {
@@ -1244,7 +1258,7 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
// Register with epoll.
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
- eventItem.events = EPOLLIN;
+ eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
@@ -1252,9 +1266,14 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
return -1;
}
- // Enable wake-lock behavior on kernels that support it.
- // TODO: Only need this for devices that can really wake the system.
- bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1);
+ String8 wakeMechanism("EPOLLWAKEUP");
+ if (!mUsingEpollWakeup) {
+ if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) {
+ wakeMechanism = "<none>";
+ } else {
+ wakeMechanism = "EVIOCSSUSPENDBLOCK";
+ }
+ }
// Tell the kernel that we want to use the monotonic clock for reporting timestamps
// associated with input events. This is important because the input system
@@ -1276,14 +1295,14 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
- "usingSuspendBlockIoctl=%s, usingClockIoctl=%s",
+ "wakeMechanism=%s, usingClockIoctl=%s",
deviceId, fd, devicePath, device->identifier.name.string(),
device->classes,
device->configurationFile.string(),
device->keyMap.keyLayoutFile.string(),
device->keyMap.keyCharacterMapFile.string(),
toString(mBuiltInKeyboardId == deviceId),
- toString(usingSuspendBlockIoctl), toString(usingClockIoctl));
+ wakeMechanism.string(), toString(usingClockIoctl));
addDeviceLocked(device);
return 0;
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index ae28f01..e54b9fc 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -440,6 +440,8 @@ private:
size_t mPendingEventCount;
size_t mPendingEventIndex;
bool mPendingINotify;
+
+ bool mUsingEpollWakeup;
};
}; // namespace android
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index a8bb636..e6f45b6 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -574,8 +574,8 @@ public:
private:
InputReaderContext* mContext;
int32_t mId;
- int32_t mControllerNumber;
int32_t mGeneration;
+ int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
String8 mAlias;
uint32_t mClasses;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index a04ee14..455d5e9 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -2117,6 +2117,7 @@ class BackupManagerService extends IBackupManager.Stub {
mSavedStateName = new File(mStateDir, packageName);
mBackupDataName = new File(mDataDir, packageName + ".data");
mNewStateName = new File(mStateDir, packageName + ".new");
+ if (MORE_DEBUG) Slog.d(TAG, "data file: " + mBackupDataName);
mSavedState = null;
mBackupData = null;
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 83e69d6..b1c625f 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -44,6 +44,7 @@ import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.input.InputManager;
import android.net.Uri;
+import android.opengl.Matrix;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -51,6 +52,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -139,6 +141,51 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private static final int MAX_POOL_SIZE = 10;
+ /** Matrix and offset used for converting color to grayscale. */
+ private static final float[] GRAYSCALE_MATRIX = new float[] {
+ .2126f, .2126f, .2126f, 0,
+ .7152f, .7152f, .7152f, 0,
+ .0722f, .0722f, .0722f, 0,
+ 0, 0, 0, 1
+ };
+
+ /** Matrix and offset used for standard display inversion. */
+ private static final float[] INVERSION_MATRIX_STANDARD = new float[] {
+ -1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, -1, 0,
+ 1, 1, 1, 1
+ };
+
+ /** Matrix and offset used for hue-only display inversion. */
+ private static final float[] INVERSION_MATRIX_HUE_ONLY = new float[] {
+ 0, .5f, .5f, 0,
+ .5f, 0, .5f, 0,
+ .5f, .5f, 0, 0,
+ 0, 0, 0, 1
+ };
+
+ /** Matrix and offset used for value-only display inversion. */
+ private static final float[] INVERSION_MATRIX_VALUE_ONLY = new float[] {
+ 0, -.5f, -.5f, 0,
+ -.5f, 0, -.5f, 0,
+ -.5f, -.5f, 0, 0,
+ 1, 1, 1, 1
+ };
+
+ /** Default contrast for display contrast enhancement. */
+ private static final float DEFAULT_DISPLAY_CONTRAST = 2;
+
+ /** Default brightness for display contrast enhancement. */
+ private static final float DEFAULT_DISPLAY_BRIGHTNESS = 0;
+
+ /** Default inversion mode for display color inversion. */
+ private static final int DEFAULT_DISPLAY_INVERSION = AccessibilityManager.INVERSION_STANDARD;
+
+ /** Default inversion mode for display color correction. */
+ private static final int DEFAULT_DISPLAY_DALTONIZER =
+ AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY;
+
private static int sIdCounter = 0;
private static int sNextWindowId;
@@ -1297,6 +1344,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
updateFilterKeyEventsLocked(userState);
updateTouchExplorationLocked(userState);
updateEnhancedWebAccessibilityLocked(userState);
+ updateDisplayColorAdjustmentSettingsLocked(userState);
scheduleUpdateInputFilter(userState);
scheduleUpdateClientsIfNeededLocked(userState);
}
@@ -1355,6 +1403,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+ somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
return somthingChanged;
}
@@ -1403,6 +1452,124 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return false;
}
+ private boolean readDisplayColorAdjustmentSettingsLocked(UserState userState) {
+ final ContentResolver cr = mContext.getContentResolver();
+ final int userId = userState.mUserId;
+
+ boolean hasColorTransform = Settings.Secure.getIntForUser(
+ cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
+
+ if (!hasColorTransform) {
+ hasColorTransform |= Settings.Secure.getIntForUser(
+ cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, userId) == 1;
+ }
+
+ if (!hasColorTransform) {
+ hasColorTransform |= Settings.Secure.getIntForUser(
+ cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) == 1;
+ }
+
+ if (userState.mHasDisplayColorAdjustment != hasColorTransform) {
+ userState.mHasDisplayColorAdjustment = hasColorTransform;
+ return true;
+ }
+
+ // If adjustment is enabled, always assume there was a transform change.
+ return hasColorTransform;
+ }
+
+ private void updateDisplayColorAdjustmentSettingsLocked(UserState userState) {
+ final ContentResolver cr = mContext.getContentResolver();
+ final int userId = userState.mUserId;
+ float[] colorMatrix = new float[16];
+ float[] outputMatrix = new float[16];
+ boolean hasColorTransform = false;
+
+ Matrix.setIdentityM(colorMatrix, 0);
+
+ final boolean inversionEnabled = Settings.Secure.getIntForUser(
+ cr, Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, userId) == 1;
+ if (inversionEnabled) {
+ final int inversionMode = Settings.Secure.getIntForUser(cr,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION, DEFAULT_DISPLAY_INVERSION,
+ userId);
+ final float[] inversionMatrix;
+ switch (inversionMode) {
+ case AccessibilityManager.INVERSION_HUE_ONLY:
+ inversionMatrix = INVERSION_MATRIX_HUE_ONLY;
+ break;
+ case AccessibilityManager.INVERSION_VALUE_ONLY:
+ inversionMatrix = INVERSION_MATRIX_VALUE_ONLY;
+ break;
+ default:
+ inversionMatrix = INVERSION_MATRIX_STANDARD;
+ }
+
+ Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, inversionMatrix, 0);
+
+ final float[] temp = colorMatrix;
+ colorMatrix = outputMatrix;
+ outputMatrix = colorMatrix;
+
+ hasColorTransform = true;
+ }
+
+ final boolean contrastEnabled = Settings.Secure.getIntForUser(
+ cr, Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED, 0, userId) == 1;
+ if (contrastEnabled) {
+ final float contrast = Settings.Secure.getFloatForUser(cr,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST, DEFAULT_DISPLAY_CONTRAST,
+ userId);
+ final float brightness = Settings.Secure.getFloatForUser(cr,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS, DEFAULT_DISPLAY_BRIGHTNESS,
+ userId);
+ final float off = brightness * contrast - 0.5f * contrast + 0.5f;
+ final float[] contrastMatrix = {
+ contrast, 0, 0, 0,
+ 0, contrast, 0, 0,
+ 0, 0, contrast, 0,
+ off, off, off, 1
+ };
+
+ Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, contrastMatrix, 0);
+
+ final float[] temp = colorMatrix;
+ colorMatrix = outputMatrix;
+ outputMatrix = colorMatrix;
+
+ hasColorTransform = true;
+ }
+
+ final boolean daltonizerEnabled = Settings.Secure.getIntForUser(
+ cr, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0, userId) != 0;
+ if (daltonizerEnabled) {
+ final int daltonizerMode = Settings.Secure.getIntForUser(cr,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, DEFAULT_DISPLAY_DALTONIZER,
+ userId);
+ // Monochromacy isn't supported by the native Daltonizer.
+ if (daltonizerMode == AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY) {
+ Matrix.multiplyMM(outputMatrix, 0, colorMatrix, 0, GRAYSCALE_MATRIX, 0);
+
+ final float[] temp = colorMatrix;
+ colorMatrix = outputMatrix;
+ outputMatrix = temp;
+
+ hasColorTransform = true;
+ nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+ } else {
+ nativeSetDaltonizerMode(daltonizerMode);
+ }
+ } else {
+ nativeSetDaltonizerMode(AccessibilityManager.DALTONIZER_DISABLED);
+ }
+
+ if (hasColorTransform) {
+ nativeSetColorTransform(colorMatrix);
+ } else {
+ nativeSetColorTransform(null);
+ }
+ }
+
private void updateTouchExplorationLocked(UserState userState) {
boolean enabled = false;
final int serviceCount = userState.mBoundServices.size();
@@ -1524,6 +1691,56 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
+ /**
+ * Sets the surface flinger's Daltonization mode. This adjusts the color
+ * space to correct for or simulate various types of color blindness.
+ *
+ * @param mode new Daltonization mode
+ */
+ private static void nativeSetDaltonizerMode(int mode) {
+ try {
+ final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+ if (flinger != null) {
+ final Parcel data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ data.writeInt(mode);
+ flinger.transact(1014, data, null, 0);
+ data.recycle();
+ }
+ } catch (RemoteException ex) {
+ Slog.e(LOG_TAG, "Failed to set Daltonizer mode", ex);
+ }
+ }
+
+ /**
+ * Sets the surface flinger's color transformation as a 4x4 matrix. If the
+ * matrix is null, color transformations are disabled.
+ *
+ * @param m the float array that holds the transformation matrix, or null to
+ * disable transformation
+ */
+ private static void nativeSetColorTransform(float[] m) {
+ try {
+ final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
+ if (flinger != null) {
+ final Parcel data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ if (m != null) {
+ data.writeInt(1);
+ for (int i = 0; i < 16; i++) {
+ data.writeFloat(m[i]);
+ }
+ } else {
+ data.writeInt(0);
+ }
+ flinger.transact(1015, data, null, 0);
+ data.recycle();
+ }
+ } catch (RemoteException ex) {
+ Slog.e(LOG_TAG, "Failed to set color transform", ex);
+ }
+ }
+
private class AccessibilityConnectionWrapper implements DeathRecipient {
private final int mWindowId;
private final int mUserId;
@@ -2947,6 +3164,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
public boolean mIsEnhancedWebAccessibilityEnabled;
public boolean mIsDisplayMagnificationEnabled;
public boolean mIsFilterKeyEventsEnabled;
+ public boolean mHasDisplayColorAdjustment;
private Service mUiAutomationService;
private IAccessibilityServiceClient mUiAutomationServiceClient;
@@ -3038,6 +3256,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
.getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
+ private final Uri mDisplayContrastEnabledUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST_ENABLED);
+ private final Uri mDisplayContrastUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_CONTRAST);
+ private final Uri mDisplayBrightnessUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_BRIGHTNESS);
+
+ private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ private final Uri mDisplayInversionUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION);
+
+ private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
+ private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER);
+
public AccessibilityContentObserver(Handler handler) {
super(handler);
}
@@ -3056,6 +3291,20 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mDisplayContrastEnabledUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mDisplayContrastUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mDisplayBrightnessUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mDisplayInversionUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
+ mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL);
}
@Override
@@ -3120,6 +3369,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
}
}
}
+ } else if (mDisplayContrastEnabledUri.equals(uri)
+ || mDisplayInversionEnabledUri.equals(uri)
+ || mDisplayDaltonizerEnabledUri.equals(uri)
+ || mDisplayContrastUri.equals(uri)
+ || mDisplayBrightnessUri.equals(uri)
+ || mDisplayInversionUri.equals(uri)
+ || mDisplayDaltonizerUri.equals(uri)) {
+ synchronized (mLock) {
+ // We will update when the automation service dies.
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readDisplayColorAdjustmentSettingsLocked(userState)) {
+ updateDisplayColorAdjustmentSettingsLocked(userState);
+ }
+ }
+ }
}
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 37c9d10..b4243b25d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3455,9 +3455,13 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
private final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
+ int pid = app.pid;
cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
if (!restarting) {
removeLruProcessLocked(app);
+ if (pid > 0) {
+ ProcessList.remove(pid);
+ }
}
if (mProfileProc == app) {
@@ -12084,6 +12088,7 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean restarting, boolean allowRestart, int index) {
if (index >= 0) {
removeLruProcessLocked(app);
+ ProcessList.remove(app.pid);
}
mProcessesToGc.remove(app);
@@ -14930,16 +14935,13 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (app.curAdj != app.setAdj) {
- if (Process.setOomAdj(app.pid, app.curAdj)) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
- TAG, "Set " + app.pid + " " + app.processName +
- " adj " + app.curAdj + ": " + app.adjType);
- app.setAdj = app.curAdj;
- } else {
- success = false;
- Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
- }
+ ProcessList.setOomAdj(app.pid, app.curAdj);
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
+ TAG, "Set " + app.pid + " " + app.processName +
+ " adj " + app.curAdj + ": " + app.adjType);
+ app.setAdj = app.curAdj;
}
+
if (app.setSchedGroup != app.curSchedGroup) {
app.setSchedGroup = app.curSchedGroup;
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index d3777c7..f5920c8 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -18,6 +18,8 @@ package com.android.server.am;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
import android.app.ActivityManager;
import com.android.internal.util.MemInfoReader;
@@ -26,6 +28,8 @@ import com.android.server.wm.WindowManagerService;
import android.content.res.Resources;
import android.graphics.Point;
import android.os.SystemProperties;
+import android.net.LocalSocketAddress;
+import android.net.LocalSocket;
import android.util.Slog;
import android.view.Display;
@@ -141,6 +145,16 @@ final class ProcessList {
// Threshold of number of cached+empty where we consider memory critical.
static final int TRIM_LOW_THRESHOLD = 5;
+ // Low Memory Killer Daemon command codes.
+ // These must be kept in sync with the definitions in lmkd.c
+ //
+ // LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)
+ // LMK_PROCPRIO <pid> <prio>
+ // LMK_PROCREMOVE <pid>
+ static final byte LMK_TARGET = 0;
+ static final byte LMK_PROCPRIO = 1;
+ static final byte LMK_PROCREMOVE = 2;
+
// These are the various interesting memory levels that we will give to
// the OOM killer. Note that the OOM killer only supports 6 slots, so we
// can't give it a different value for every possible kind of process.
@@ -150,18 +164,18 @@ final class ProcessList {
};
// These are the low-end OOM level limits. This is appropriate for an
// HVGA or smaller phone with less than 512MB. Values are in KB.
- private final long[] mOomMinFreeLow = new long[] {
+ private final int[] mOomMinFreeLow = new int[] {
8192, 12288, 16384,
24576, 28672, 32768
};
// These are the high-end OOM level limits. This is appropriate for a
// 1280x800 or larger screen with around 1GB RAM. Values are in KB.
- private final long[] mOomMinFreeHigh = new long[] {
+ private final int[] mOomMinFreeHigh = new int[] {
49152, 61440, 73728,
86016, 98304, 122880
};
// The actual OOM killer memory levels we are using.
- private final long[] mOomMinFree = new long[mOomAdj.length];
+ private final int[] mOomMinFree = new int[mOomAdj.length];
private final long mTotalMemMb;
@@ -169,6 +183,9 @@ final class ProcessList {
private boolean mHaveDisplaySize;
+ private static LocalSocket sLmkdSocket;
+ private static OutputStream sLmkdOutputStream;
+
ProcessList() {
MemInfoReader minfo = new MemInfoReader();
minfo.readMemInfo();
@@ -202,9 +219,6 @@ final class ProcessList {
+ " dh=" + displayHeight);
}
- StringBuilder adjString = new StringBuilder();
- StringBuilder memString = new StringBuilder();
-
float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
if (scale < 0) scale = 0;
else if (scale > 1) scale = 1;
@@ -217,20 +231,20 @@ final class ProcessList {
}
for (int i=0; i<mOomAdj.length; i++) {
- long low = mOomMinFreeLow[i];
- long high = mOomMinFreeHigh[i];
- mOomMinFree[i] = (long)(low + ((high-low)*scale));
+ int low = mOomMinFreeLow[i];
+ int high = mOomMinFreeHigh[i];
+ mOomMinFree[i] = (int)(low + ((high-low)*scale));
}
if (minfree_abs >= 0) {
for (int i=0; i<mOomAdj.length; i++) {
- mOomMinFree[i] = (long)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
+ mOomMinFree[i] = (int)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
}
}
if (minfree_adj != 0) {
for (int i=0; i<mOomAdj.length; i++) {
- mOomMinFree[i] += (long)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
+ mOomMinFree[i] += (int)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
if (mOomMinFree[i] < 0) {
mOomMinFree[i] = 0;
}
@@ -242,15 +256,6 @@ final class ProcessList {
// before killing background processes.
mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3;
- for (int i=0; i<mOomAdj.length; i++) {
- if (i > 0) {
- adjString.append(',');
- memString.append(',');
- }
- adjString.append(mOomAdj[i]);
- memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
- }
-
// Ask the kernel to try to keep enough memory free to allocate 3 full
// screen 32bpp buffers without entering direct reclaim.
int reserve = displayWidth * displayHeight * 4 * 3 / 1024;
@@ -268,10 +273,15 @@ final class ProcessList {
}
}
- //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
if (write) {
- writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
- writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
+ ByteBuffer buf = ByteBuffer.allocate(4 * (2*mOomAdj.length + 1));
+ buf.putInt(LMK_TARGET);
+ for (int i=0; i<mOomAdj.length; i++) {
+ buf.putInt((mOomMinFree[i]*1024)/PAGE_SIZE);
+ buf.putInt(mOomAdj[i]);
+ }
+
+ writeLmkd(buf);
SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve));
}
// GB: 2048,3072,4096,6144,7168,8192
@@ -506,19 +516,78 @@ final class ProcessList {
return mCachedRestoreLevel;
}
- private void writeFile(String path, String data) {
- FileOutputStream fos = null;
+ /**
+ * Set the out-of-memory badness adjustment for a process.
+ *
+ * @param pid The process identifier to set.
+ * @param amt Adjustment value -- lmkd allows -16 to +15.
+ *
+ * {@hide}
+ */
+ public static final void setOomAdj(int pid, int amt) {
+ if (amt == UNKNOWN_ADJ)
+ return;
+
+ ByteBuffer buf = ByteBuffer.allocate(4 * 3);
+ buf.putInt(LMK_PROCPRIO);
+ buf.putInt(pid);
+ buf.putInt(amt);
+ writeLmkd(buf);
+ }
+
+ /*
+ * {@hide}
+ */
+ public static final void remove(int pid) {
+ ByteBuffer buf = ByteBuffer.allocate(4 * 2);
+ buf.putInt(LMK_PROCREMOVE);
+ buf.putInt(pid);
+ writeLmkd(buf);
+ }
+
+ private static boolean openLmkdSocket() {
try {
- fos = new FileOutputStream(path);
- fos.write(data.getBytes());
- } catch (IOException e) {
- Slog.w(ActivityManagerService.TAG, "Unable to write " + path);
- } finally {
- if (fos != null) {
+ sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
+ sLmkdSocket.connect(
+ new LocalSocketAddress("lmkd",
+ LocalSocketAddress.Namespace.RESERVED));
+ sLmkdOutputStream = sLmkdSocket.getOutputStream();
+ } catch (IOException ex) {
+ Slog.w(ActivityManagerService.TAG,
+ "lowmemorykiller daemon socket open failed");
+ sLmkdSocket = null;
+ return false;
+ }
+
+ return true;
+ }
+
+ private static void writeLmkd(ByteBuffer buf) {
+
+ for (int i = 0; i < 3; i++) {
+ if (sLmkdSocket == null) {
+ if (openLmkdSocket() == false) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ }
+ continue;
+ }
+ }
+
+ try {
+ sLmkdOutputStream.write(buf.array(), 0, buf.position());
+ return;
+ } catch (IOException ex) {
+ Slog.w(ActivityManagerService.TAG,
+ "Error writing to lowmemorykiller socket");
+
try {
- fos.close();
- } catch (IOException e) {
+ sLmkdSocket.close();
+ } catch (IOException ex2) {
}
+
+ sLmkdSocket = null;
}
}
}
diff --git a/services/java/com/android/server/content/ContentService.java b/services/java/com/android/server/content/ContentService.java
index 885ec9f..48b3259 100644
--- a/services/java/com/android/server/content/ContentService.java
+++ b/services/java/com/android/server/content/ContentService.java
@@ -19,11 +19,14 @@ package com.android.server.content;
import android.Manifest;
import android.accounts.Account;
import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IContentService;
import android.content.ISyncStatusObserver;
import android.content.PeriodicSync;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.content.SyncAdapterType;
import android.content.SyncInfo;
import android.content.SyncRequest;
@@ -314,7 +317,6 @@ public final class ContentService extends IContentService.Stub {
}
}
- @Override
public void requestSync(Account account, String authority, Bundle extras) {
ContentResolver.validateSyncExtrasBundle(extras);
int userId = UserHandle.getCallingUserId();
@@ -344,48 +346,56 @@ public final class ContentService extends IContentService.Stub {
* Depending on the request, we enqueue to suit in the SyncManager.
* @param request
*/
- @Override
public void sync(SyncRequest request) {
Bundle extras = request.getBundle();
ContentResolver.validateSyncExtrasBundle(extras);
- long flextime = request.getSyncFlexTime();
- long runAtTime = request.getSyncRunTime();
int userId = UserHandle.getCallingUserId();
- int uId = Binder.getCallingUid();
-
+ int callerUid = Binder.getCallingUid();
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
+ if (syncManager == null) return;
+
+ long flextime = request.getSyncFlexTime();
+ long runAtTime = request.getSyncRunTime();
+ if (request.isPeriodic()) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ SyncStorageEngine.EndPoint info;
+ if (!request.hasAuthority()) {
+ // Extra permissions checking for sync service.
+ verifySignatureForPackage(callerUid,
+ request.getService().getPackageName(), "sync");
+ info = new SyncStorageEngine.EndPoint(request.getService(), userId);
+ } else {
+ info = new SyncStorageEngine.EndPoint(
+ request.getAccount(), request.getProvider(), userId);
+ }
+ if (runAtTime < 60) {
+ Slog.w(TAG, "Requested poll frequency of " + runAtTime
+ + " seconds being rounded up to 60 seconds.");
+ runAtTime = 60;
+ }
+ // Schedule periodic sync.
+ getSyncManager().getSyncStorageEngine()
+ .updateOrAddPeriodicSync(info, runAtTime, flextime, extras);
+ } else {
+ long beforeRuntimeMillis = (flextime) * 1000;
+ long runtimeMillis = runAtTime * 1000;
if (request.hasAuthority()) {
- // Sync Adapter registered with the system - old API.
- final Account account = request.getAccount();
- final String provider = request.getProvider();
- if (request.isPeriodic()) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.WRITE_SYNC_SETTINGS,
- "no permission to write the sync settings");
- if (runAtTime < 60) {
- Slog.w(TAG, "Requested poll frequency of " + runAtTime
- + " seconds being rounded up to 60 seconds.");
- runAtTime = 60;
- }
- PeriodicSync syncToAdd =
- new PeriodicSync(account, provider, extras, runAtTime, flextime);
- getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
- } else {
- long beforeRuntimeMillis = (flextime) * 1000;
- long runtimeMillis = runAtTime * 1000;
- syncManager.scheduleSync(
- account, userId, uId, provider, extras,
- beforeRuntimeMillis, runtimeMillis,
- false /* onlyThoseWithUnknownSyncableState */);
- }
+ syncManager.scheduleSync(
+ request.getAccount(), userId, callerUid, request.getProvider(), extras,
+ beforeRuntimeMillis, runtimeMillis,
+ false /* onlyThoseWithUnknownSyncableState */);
} else {
- Log.w(TAG, "Unrecognised sync parameters, doing nothing.");
+ syncManager.scheduleSync(
+ request.getService(), userId, callerUid, extras,
+ beforeRuntimeMillis,
+ runtimeMillis); // Empty function.
}
}
} finally {
@@ -396,11 +406,13 @@ public final class ContentService extends IContentService.Stub {
/**
* Clear all scheduled sync operations that match the uri and cancel the active sync
* if they match the authority and account, if they are present.
- * @param account filter the pending and active syncs to cancel using this account
- * @param authority filter the pending and active syncs to cancel using this authority
+ *
+ * @param account filter the pending and active syncs to cancel using this account, or null.
+ * @param authority filter the pending and active syncs to cancel using this authority, or
+ * null.
+ * @param cname cancel syncs running on this service, or null for provider/account.
*/
- @Override
- public void cancelSync(Account account, String authority) {
+ public void cancelSync(Account account, String authority, ComponentName cname) {
int userId = UserHandle.getCallingUserId();
// This makes it so that future permission checks will be in the context of this
@@ -409,9 +421,49 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.clearScheduledSyncOperations(account, userId, authority);
- syncManager.cancelActiveSync(account, userId, authority);
+ SyncStorageEngine.EndPoint info;
+ if (cname == null) {
+ info = new SyncStorageEngine.EndPoint(account, authority, userId);
+ } else {
+ info = new SyncStorageEngine.EndPoint(cname, userId);
+ }
+ syncManager.clearScheduledSyncOperations(info);
+ syncManager.cancelActiveSync(info, null /* all syncs for this adapter */);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public void cancelRequest(SyncRequest request) {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager == null) return;
+ int userId = UserHandle.getCallingUserId();
+ int callerUid = Binder.getCallingUid();
+
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncStorageEngine.EndPoint info;
+ Bundle extras = new Bundle(request.getBundle());
+ if (request.hasAuthority()) {
+ Account account = request.getAccount();
+ String provider = request.getProvider();
+ info = new SyncStorageEngine.EndPoint(account, provider, userId);
+ } else {
+ // Only allowed to manipulate syncs for a service which you own.
+ ComponentName service = request.getService();
+ verifySignatureForPackage(callerUid, service.getPackageName(), "cancel");
+ info = new SyncStorageEngine.EndPoint(service, userId);
}
+ if (request.isPeriodic()) {
+ // Remove periodic sync.
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ getSyncManager().getSyncStorageEngine().removePeriodicSync(info, extras);
+ }
+ // Cancel active syncs and clear pending syncs from the queue.
+ syncManager.cancelScheduledSyncOperation(info, extras);
+ syncManager.cancelActiveSync(info, extras);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -445,8 +497,8 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getSyncAutomatically(
- account, userId, providerName);
+ return syncManager.getSyncStorageEngine()
+ .getSyncAutomatically(account, userId, providerName);
}
} finally {
restoreCallingIdentity(identityToken);
@@ -464,18 +516,15 @@ public final class ContentService extends IContentService.Stub {
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
- syncManager.getSyncStorageEngine().setSyncAutomatically(
- account, userId, providerName, sync);
+ syncManager.getSyncStorageEngine()
+ .setSyncAutomatically(account, userId, providerName, sync);
}
} finally {
restoreCallingIdentity(identityToken);
}
}
- /**
- * Old API. Schedule periodic sync with default flex time.
- */
- @Override
+ /** Old API. Schedule periodic sync with default flex time. */
public void addPeriodicSync(Account account, String authority, Bundle extras,
long pollFrequency) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
@@ -487,21 +536,22 @@ public final class ContentService extends IContentService.Stub {
+ " seconds being rounded up to 60 seconds.");
pollFrequency = 60;
}
+ long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
long identityToken = clearCallingIdentity();
try {
- // Add default flex time to this sync.
- PeriodicSync syncToAdd =
- new PeriodicSync(account, authority, extras,
- pollFrequency,
- SyncStorageEngine.calculateDefaultFlexTime(pollFrequency));
- getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
+ SyncStorageEngine.EndPoint info =
+ new SyncStorageEngine.EndPoint(account, authority, userId);
+ getSyncManager().getSyncStorageEngine()
+ .updateOrAddPeriodicSync(info,
+ pollFrequency,
+ defaultFlex,
+ extras);
} finally {
restoreCallingIdentity(identityToken);
}
}
- @Override
public void removePeriodicSync(Account account, String authority, Bundle extras) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
@@ -509,32 +559,34 @@ public final class ContentService extends IContentService.Stub {
long identityToken = clearCallingIdentity();
try {
- PeriodicSync syncToRemove = new PeriodicSync(account, authority, extras,
- 0 /* Not read for removal */, 0 /* Not read for removal */);
- getSyncManager().getSyncStorageEngine().removePeriodicSync(syncToRemove, userId);
+ getSyncManager().getSyncStorageEngine()
+ .removePeriodicSync(
+ new SyncStorageEngine.EndPoint(account, authority, userId),
+ extras);
} finally {
restoreCallingIdentity(identityToken);
}
}
- /**
- * TODO: Implement.
- * @param request Sync to remove.
- */
- public void removeSync(SyncRequest request) {
-
- }
-
- @Override
- public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
+ public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
+ ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
int userId = UserHandle.getCallingUserId();
+ int callerUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
try {
- return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
- account, userId, providerName);
+ if (cname == null) {
+ return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
+ new SyncStorageEngine.EndPoint(account, providerName, userId));
+ } else if (account == null && providerName == null) {
+ verifySignatureForPackage(callerUid, cname.getPackageName(), "getPeriodicSyncs");
+ return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
+ new SyncStorageEngine.EndPoint(cname, userId));
+ } else {
+ throw new IllegalArgumentException("Invalid authority specified");
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -558,7 +610,6 @@ public final class ContentService extends IContentService.Stub {
return -1;
}
- @Override
public void setIsSyncable(Account account, String providerName, int syncable) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
@@ -576,6 +627,45 @@ public final class ContentService extends IContentService.Stub {
}
}
+ public void setServiceActive(ComponentName cname, boolean active) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
+ "no permission to write the sync settings");
+ verifySignatureForPackage(Binder.getCallingUid(), cname.getPackageName(),
+ "setServiceActive");
+
+ int userId = UserHandle.getCallingUserId();
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ syncManager.getSyncStorageEngine().setIsTargetServiceActive(
+ cname, userId, active);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
+ public boolean isServiceActive(ComponentName cname) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
+ "no permission to read the sync settings");
+ verifySignatureForPackage(Binder.getCallingUid(), cname.getPackageName(),
+ "isServiceActive");
+
+ int userId = UserHandle.getCallingUserId();
+ long identityToken = clearCallingIdentity();
+ try {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ return syncManager.getSyncStorageEngine()
+ .getIsTargetServiceActive(cname, userId);
+ }
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ return false;
+ }
+
@Override
public boolean getMasterSyncAutomatically() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
@@ -611,17 +701,24 @@ public final class ContentService extends IContentService.Stub {
}
}
- public boolean isSyncActive(Account account, String authority) {
+ public boolean isSyncActive(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
int userId = UserHandle.getCallingUserId();
-
+ int callingUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
+ if (syncManager == null) {
+ return false;
+ }
+ if (cname == null) {
+ return syncManager.getSyncStorageEngine().isSyncActive(
+ new SyncStorageEngine.EndPoint(account, authority, userId));
+ } else if (account == null && authority == null) {
+ verifySignatureForPackage(callingUid, cname.getPackageName(), "isSyncActive");
return syncManager.getSyncStorageEngine().isSyncActive(
- account, userId, authority);
+ new SyncStorageEngine.EndPoint(cname, userId));
}
} finally {
restoreCallingIdentity(identityToken);
@@ -642,39 +739,55 @@ public final class ContentService extends IContentService.Stub {
}
}
- public SyncStatusInfo getSyncStatus(Account account, String authority) {
+ public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
int userId = UserHandle.getCallingUserId();
-
+ int callerUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- return syncManager.getSyncStorageEngine().getStatusByAccountAndAuthority(
- account, userId, authority);
+ if (syncManager == null) {
+ return null;
}
+ SyncStorageEngine.EndPoint info;
+ if (cname == null) {
+ info = new SyncStorageEngine.EndPoint(account, authority, userId);
+ } else if (account == null && authority == null) {
+ verifySignatureForPackage(callerUid, cname.getPackageName(), "getSyncStatus");
+ info = new SyncStorageEngine.EndPoint(cname, userId);
+ } else {
+ throw new IllegalArgumentException("Must call sync status with valid authority");
+ }
+ return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
} finally {
restoreCallingIdentity(identityToken);
}
- return null;
}
- public boolean isSyncPending(Account account, String authority) {
+ public boolean isSyncPending(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
int userId = UserHandle.getCallingUserId();
-
+ int callerUid = Binder.getCallingUid();
long identityToken = clearCallingIdentity();
+ SyncManager syncManager = getSyncManager();
+ if (syncManager == null) return false;
+
try {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- return syncManager.getSyncStorageEngine().isSyncPending(account, userId, authority);
+ SyncStorageEngine.EndPoint info;
+ if (cname == null) {
+ info = new SyncStorageEngine.EndPoint(account, authority, userId);
+ } else if (account == null && authority == null) {
+ verifySignatureForPackage(callerUid, cname.getPackageName(), "isSyncPending");
+ info = new SyncStorageEngine.EndPoint(cname, userId);
+ } else {
+ throw new IllegalArgumentException("Invalid authority specified");
}
+ return syncManager.getSyncStorageEngine().isSyncPending(info);
} finally {
restoreCallingIdentity(identityToken);
}
- return false;
}
public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
@@ -708,6 +821,30 @@ public final class ContentService extends IContentService.Stub {
}
/**
+ * Helper to verify that the provided package name shares the same cert as the caller.
+ * @param callerUid uid of the calling process.
+ * @param packageName package to verify against package of calling application.
+ * @param tag a tag to use when throwing an exception if the signatures don't
+ * match. Cannot be null.
+ * @return true if the calling application and the provided package are signed with the same
+ * certificate.
+ */
+ private boolean verifySignatureForPackage(int callerUid, String packageName, String tag) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ int serviceUid = pm.getApplicationInfo(packageName, 0).uid;
+ if (pm.checkSignatures(callerUid, serviceUid) == PackageManager.SIGNATURE_MATCH) {
+ return true;
+ } else {
+ throw new SecurityException(tag + ": Caller certificate does not match that for - "
+ + packageName);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException(tag + ": " + packageName + " package not found.");
+ }
+ }
+
+ /**
* Hide this class since it is not part of api,
* but current unittest framework requires it to be public
* @hide
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index 2ae7bc7..5c0f902 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -31,6 +31,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.ISyncAdapter;
import android.content.ISyncContext;
+import android.content.ISyncServiceAdapter;
import android.content.ISyncStatusObserver;
import android.content.Intent;
import android.content.IntentFilter;
@@ -87,7 +88,6 @@ import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -98,7 +98,6 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
-import java.util.concurrent.CountDownLatch;
/**
* @hide
@@ -201,8 +200,9 @@ public class SyncManager {
Log.v(TAG, "Internal storage is low.");
}
mStorageIsLow = true;
- cancelActiveSync(null /* any account */, UserHandle.USER_ALL,
- null /* any authority */);
+ cancelActiveSync(
+ SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
+ null /* any sync */);
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Internal storage is ok.");
@@ -220,19 +220,6 @@ public class SyncManager {
}
};
- private BroadcastReceiver mBackgroundDataSettingChanged = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (getConnectivityManager().getBackgroundDataSetting()) {
- scheduleSync(null /* account */, UserHandle.USER_ALL,
- SyncOperation.REASON_BACKGROUND_DATA_SETTINGS_CHANGED,
- null /* authority */,
- new Bundle(), 0 /* delay */, 0 /* delay */,
- false /* onlyThoseWithUnknownSyncableState */);
- }
- }
- };
-
private BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -277,16 +264,16 @@ public class SyncManager {
doDatabaseCleanup();
}
+ AccountAndUser[] accounts = mRunningAccounts;
for (ActiveSyncContext currentSyncContext : mActiveSyncContexts) {
- if (!containsAccountAndUser(mRunningAccounts,
- currentSyncContext.mSyncOperation.account,
- currentSyncContext.mSyncOperation.userId)) {
+ if (!containsAccountAndUser(accounts,
+ currentSyncContext.mSyncOperation.target.account,
+ currentSyncContext.mSyncOperation.target.userId)) {
Log.d(TAG, "canceling sync since the account is no longer running");
sendSyncFinishedOrCanceledMessage(currentSyncContext,
null /* no result since this is a cancel */);
}
}
-
// we must do this since we don't bother scheduling alarms when
// the accounts are not set yet
sendCheckAlarmsMessage();
@@ -315,9 +302,7 @@ public class SyncManager {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Reconnection detected: clearing all backoffs");
}
- synchronized(mSyncQueue) {
- mSyncStorageEngine.clearAllBackoffsLocked(mSyncQueue);
- }
+ mSyncStorageEngine.clearAllBackoffs(mSyncQueue);
}
sendCheckAlarmsMessage();
}
@@ -383,12 +368,17 @@ public class SyncManager {
mSyncStorageEngine = SyncStorageEngine.getSingleton();
mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
@Override
- public void onSyncRequest(Account account, int userId, int reason, String authority,
- Bundle extras) {
- scheduleSync(account, userId, reason, authority, extras,
- 0 /* no delay */,
- 0 /* no delay */,
- false);
+ public void onSyncRequest(SyncStorageEngine.EndPoint info, int reason, Bundle extras) {
+ if (info.target_provider) {
+ scheduleSync(info.account, info.userId, reason, info.provider, extras,
+ 0 /* no flex */,
+ 0 /* run immediately */,
+ false);
+ } else if (info.target_service) {
+ scheduleSync(info.service, info.userId, reason, extras,
+ 0 /* no flex */,
+ 0 /* run immediately */);
+ }
}
});
@@ -420,9 +410,6 @@ public class SyncManager {
context.registerReceiver(mBootCompletedReceiver, intentFilter);
}
- intentFilter = new IntentFilter(ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
- context.registerReceiver(mBackgroundDataSettingChanged, intentFilter);
-
intentFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
context.registerReceiver(mStorageIntentReceiver, intentFilter);
@@ -537,8 +524,75 @@ public class SyncManager {
private void ensureAlarmService() {
if (mAlarmService == null) {
- mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+ mAlarmService = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ }
+ }
+
+ /**
+ * Initiate a sync using the new anonymous service API.
+ * @param cname SyncService component bound to in order to perform the sync.
+ * @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
+ * then all users' accounts are considered.
+ * @param uid Linux uid of the application that is performing the sync.
+ * @param extras a Map of SyncAdapter-specific information to control
+ * syncs of a specific provider. Cannot be null.
+ * @param beforeRunTimeMillis milliseconds before <code>runtimeMillis</code> that this sync may
+ * be run.
+ * @param runtimeMillis milliseconds from now by which this sync must be run.
+ */
+ public void scheduleSync(ComponentName cname, int userId, int uid, Bundle extras,
+ long beforeRunTimeMillis, long runtimeMillis) {
+ boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+ if (isLoggable) {
+ Log.d(TAG, "one off sync for: " + cname + " " + extras.toString());
+ }
+
+ Boolean expedited = extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
+ if (expedited) {
+ runtimeMillis = -1; // this means schedule at the front of the queue
+ }
+
+ final boolean ignoreSettings =
+ extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
+ int source = SyncStorageEngine.SOURCE_SERVICE;
+ boolean isEnabled = mSyncStorageEngine.getIsTargetServiceActive(cname, userId);
+ // Only schedule this sync if
+ // - we've explicitly been told to ignore settings.
+ // - global sync is enabled for this user.
+ boolean syncAllowed =
+ ignoreSettings
+ || mSyncStorageEngine.getMasterSyncAutomatically(userId);
+ if (!syncAllowed) {
+ if (isLoggable) {
+ Log.d(TAG, "scheduleSync: sync of " + cname + " not allowed, dropping request.");
+ }
+ return;
+ }
+ if (!isEnabled) {
+ if (isLoggable) {
+ Log.d(TAG, "scheduleSync: " + cname + " is not enabled, dropping request");
+ }
+ return;
}
+ SyncStorageEngine.EndPoint info = new SyncStorageEngine.EndPoint(cname, userId);
+ Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(info);
+ long delayUntil = mSyncStorageEngine.getDelayUntilTime(info);
+ final long backoffTime = backoff != null ? backoff.first : 0;
+ if (isLoggable) {
+ Log.v(TAG, "schedule Sync:"
+ + ", delay until " + delayUntil
+ + ", run by " + runtimeMillis
+ + ", flex " + beforeRunTimeMillis
+ + ", source " + source
+ + ", sync service " + cname
+ + ", extras " + extras);
+ }
+ scheduleSyncOperation(
+ new SyncOperation(cname, userId, uid, source, extras,
+ runtimeMillis /* runtime */,
+ beforeRunTimeMillis /* flextime */,
+ backoffTime,
+ delayUntil));
}
/**
@@ -587,9 +641,6 @@ public class SyncManager {
long runtimeMillis, boolean onlyThoseWithUnkownSyncableState) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
- final boolean backgroundDataUsageAllowed = !mBootCompleted ||
- getConnectivityManager().getBackgroundDataSetting();
-
if (extras == null) {
extras = new Bundle();
}
@@ -606,8 +657,6 @@ public class SyncManager {
if (requestedAccount != null && userId != UserHandle.USER_ALL) {
accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
} else {
- // if the accounts aren't configured yet then we can't support an account-less
- // sync request
accounts = mRunningAccounts;
if (accounts.length == 0) {
if (isLoggable) {
@@ -682,12 +731,10 @@ public class SyncManager {
continue;
}
- // always allow if the isSyncable state is unknown
boolean syncAllowed =
- (isSyncable < 0)
+ (isSyncable < 0) // always allow if the isSyncable state is unknown
|| ignoreSettings
- || (backgroundDataUsageAllowed
- && mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
+ || (mSyncStorageEngine.getMasterSyncAutomatically(account.userId)
&& mSyncStorageEngine.getSyncAutomatically(account.account,
account.userId, authority));
if (!syncAllowed) {
@@ -697,11 +744,12 @@ public class SyncManager {
}
continue;
}
-
- Pair<Long, Long> backoff = mSyncStorageEngine
- .getBackoff(account.account, account.userId, authority);
- long delayUntil = mSyncStorageEngine.getDelayUntilTime(account.account,
- account.userId, authority);
+ SyncStorageEngine.EndPoint info =
+ new SyncStorageEngine.EndPoint(
+ account.account, authority, account.userId);
+ Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(info);
+ long delayUntil =
+ mSyncStorageEngine.getDelayUntilTime(info);
final long backoffTime = backoff != null ? backoff.first : 0;
if (isSyncable < 0) {
// Initialisation sync.
@@ -711,6 +759,7 @@ public class SyncManager {
Log.v(TAG, "schedule initialisation Sync:"
+ ", delay until " + delayUntil
+ ", run by " + 0
+ + ", flex " + 0
+ ", source " + source
+ ", account " + account
+ ", authority " + authority
@@ -786,13 +835,12 @@ public class SyncManager {
mSyncHandler.sendMessage(msg);
}
- private void sendCancelSyncsMessage(final Account account, final int userId,
- final String authority) {
+ private void sendCancelSyncsMessage(final SyncStorageEngine.EndPoint info, Bundle extras) {
if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "sending MESSAGE_CANCEL");
Message msg = mSyncHandler.obtainMessage();
msg.what = SyncHandler.MESSAGE_CANCEL;
- msg.obj = Pair.create(account, authority);
- msg.arg1 = userId;
+ msg.setData(extras);
+ msg.obj = info;
mSyncHandler.sendMessage(msg);
}
@@ -815,10 +863,11 @@ public class SyncManager {
}
private void clearBackoffSetting(SyncOperation op) {
- mSyncStorageEngine.setBackoff(op.account, op.userId, op.authority,
- SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
+ mSyncStorageEngine.setBackoff(op.target,
+ SyncStorageEngine.NOT_IN_BACKOFF_MODE,
+ SyncStorageEngine.NOT_IN_BACKOFF_MODE);
synchronized (mSyncQueue) {
- mSyncQueue.onBackoffChanged(op.account, op.userId, op.authority, 0);
+ mSyncQueue.onBackoffChanged(op.target, 0);
}
}
@@ -828,7 +877,7 @@ public class SyncManager {
final long now = SystemClock.elapsedRealtime();
final Pair<Long, Long> previousSettings =
- mSyncStorageEngine.getBackoff(op.account, op.userId, op.authority);
+ mSyncStorageEngine.getBackoff(op.target);
long newDelayInMs = -1;
if (previousSettings != null) {
// don't increase backoff before current backoff is expired. This will happen for op's
@@ -859,14 +908,12 @@ public class SyncManager {
final long backoff = now + newDelayInMs;
- mSyncStorageEngine.setBackoff(op.account, op.userId, op.authority,
- backoff, newDelayInMs);
-
+ mSyncStorageEngine.setBackoff(op.target, backoff, newDelayInMs);
op.backoff = backoff;
op.updateEffectiveRunTime();
synchronized (mSyncQueue) {
- mSyncQueue.onBackoffChanged(op.account, op.userId, op.authority, backoff);
+ mSyncQueue.onBackoffChanged(op.target, backoff);
}
}
@@ -879,20 +926,20 @@ public class SyncManager {
} else {
newDelayUntilTime = 0;
}
- mSyncStorageEngine
- .setDelayUntilTime(op.account, op.userId, op.authority, newDelayUntilTime);
+ mSyncStorageEngine.setDelayUntilTime(op.target, newDelayUntilTime);
synchronized (mSyncQueue) {
- mSyncQueue.onDelayUntilTimeChanged(op.account, op.authority, newDelayUntilTime);
+ mSyncQueue.onDelayUntilTimeChanged(op.target, newDelayUntilTime);
}
}
/**
- * Cancel the active sync if it matches the authority and account.
- * @param account limit the cancelations to syncs with this account, if non-null
- * @param authority limit the cancelations to syncs with this authority, if non-null
+ * Cancel the active sync if it matches the target.
+ * @param info object containing info about which syncs to cancel. The target can
+ * have null account/provider info to specify all accounts/providers.
+ * @param extras if non-null, specifies the exact sync to remove.
*/
- public void cancelActiveSync(Account account, int userId, String authority) {
- sendCancelSyncsMessage(account, userId, authority);
+ public void cancelActiveSync(SyncStorageEngine.EndPoint info, Bundle extras) {
+ sendCancelSyncsMessage(info, extras);
}
/**
@@ -921,24 +968,40 @@ public class SyncManager {
/**
* Remove scheduled sync operations.
- * @param account limit the removals to operations with this account, if non-null
- * @param authority limit the removals to operations with this authority, if non-null
+ * @param info limit the removals to operations that match this target. The target can
+ * have null account/provider info to specify all accounts/providers.
*/
- public void clearScheduledSyncOperations(Account account, int userId, String authority) {
+ public void clearScheduledSyncOperations(SyncStorageEngine.EndPoint info) {
synchronized (mSyncQueue) {
- mSyncQueue.remove(account, userId, authority);
+ mSyncQueue.remove(info, null /* all operations */);
}
- mSyncStorageEngine.setBackoff(account, userId, authority,
+ mSyncStorageEngine.setBackoff(info,
SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
}
+ /**
+ * Remove a specified sync, if it exists.
+ * @param info Authority for which the sync is to be removed.
+ * @param extras extras bundle to uniquely identify sync.
+ */
+ public void cancelScheduledSyncOperation(SyncStorageEngine.EndPoint info, Bundle extras) {
+ synchronized (mSyncQueue) {
+ mSyncQueue.remove(info, extras);
+ }
+ // Reset the back-off if there are no more syncs pending.
+ if (!mSyncStorageEngine.isSyncPending(info)) {
+ mSyncStorageEngine.setBackoff(info,
+ SyncStorageEngine.NOT_IN_BACKOFF_MODE, SyncStorageEngine.NOT_IN_BACKOFF_MODE);
+ }
+ }
+
void maybeRescheduleSync(SyncResult syncResult, SyncOperation operation) {
boolean isLoggable = Log.isLoggable(TAG, Log.DEBUG);
if (isLoggable) {
Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
}
- operation = new SyncOperation(operation);
+ operation = new SyncOperation(operation, 0L /* newRunTimeFromNow */);
// The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
// request. Retries of the request will always honor the backoff, so clear the
@@ -947,25 +1010,29 @@ public class SyncManager {
operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
}
- // If this sync aborted because the internal sync loop retried too many times then
- // don't reschedule. Otherwise we risk getting into a retry loop.
- // If the operation succeeded to some extent then retry immediately.
- // If this was a two-way sync then retry soft errors with an exponential backoff.
- // If this was an upward sync then schedule a two-way sync immediately.
- // Otherwise do not reschedule.
if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)) {
- Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
- + operation);
+ if (isLoggable) {
+ Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
+ + operation);
+ }
} else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)
&& !syncResult.syncAlreadyInProgress) {
+ // If this was an upward sync then schedule a two-way sync immediately.
operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
- Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
- + "encountered an error: " + operation);
+ if (isLoggable) {
+ Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
+ + "encountered an error: " + operation);
+ }
scheduleSyncOperation(operation);
} else if (syncResult.tooManyRetries) {
- Log.d(TAG, "not retrying sync operation because it retried too many times: "
- + operation);
+ // If this sync aborted because the internal sync loop retried too many times then
+ // don't reschedule. Otherwise we risk getting into a retry loop.
+ if (isLoggable) {
+ Log.d(TAG, "not retrying sync operation because it retried too many times: "
+ + operation);
+ }
} else if (syncResult.madeSomeProgress()) {
+ // If the operation succeeded to some extent then retry immediately.
if (isLoggable) {
Log.d(TAG, "retrying sync operation because even though it had an error "
+ "it achieved some success");
@@ -978,19 +1045,18 @@ public class SyncManager {
}
scheduleSyncOperation(
new SyncOperation(
- operation.account, operation.userId,
- operation.reason,
- operation.syncSource,
- operation.authority, operation.extras,
- DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000, operation.flexTime,
- operation.backoff, operation.delayUntil, operation.allowParallelSyncs));
+ operation,
+ DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000 /* newRunTimeFromNow */)
+ );
} else if (syncResult.hasSoftError()) {
+ // If this was a two-way sync then retry soft errors with an exponential backoff.
if (isLoggable) {
Log.d(TAG, "retrying sync operation because it encountered a soft error: "
+ operation);
}
scheduleSyncOperation(operation);
} else {
+ // Otherwise do not reschedule.
Log.d(TAG, "not retrying sync operation because the error is a hard error: "
+ operation);
}
@@ -1023,9 +1089,12 @@ public class SyncManager {
updateRunningAccounts();
cancelActiveSync(
- null /* any account */,
- userId,
- null /* any authority */);
+ new SyncStorageEngine.EndPoint(
+ null /* any account */,
+ null /* any authority */,
+ userId),
+ null /* any sync. */
+ );
}
private void onUserRemoved(int userId) {
@@ -1034,7 +1103,7 @@ public class SyncManager {
// Clean up the storage engine database
mSyncStorageEngine.doDatabaseCleanup(new Account[0], userId);
synchronized (mSyncQueue) {
- mSyncQueue.removeUser(userId);
+ mSyncQueue.removeUserLocked(userId);
}
}
@@ -1046,6 +1115,7 @@ public class SyncManager {
final SyncOperation mSyncOperation;
final long mHistoryRowId;
ISyncAdapter mSyncAdapter;
+ ISyncServiceAdapter mSyncServiceAdapter;
final long mStartTime;
long mTimeoutStartTime;
boolean mBound;
@@ -1071,10 +1141,10 @@ public class SyncManager {
mSyncOperation = syncOperation;
mHistoryRowId = historyRowId;
mSyncAdapter = null;
+ mSyncServiceAdapter = null;
mStartTime = SystemClock.elapsedRealtime();
mTimeoutStartTime = mStartTime;
- mSyncWakeLock = mSyncHandler.getSyncWakeLock(
- mSyncOperation.account, mSyncOperation.authority);
+ mSyncWakeLock = mSyncHandler.getSyncWakeLock(mSyncOperation);
mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterUid));
mSyncWakeLock.acquire();
}
@@ -1101,7 +1171,7 @@ public class SyncManager {
public void onServiceConnected(ComponentName name, IBinder service) {
Message msg = mSyncHandler.obtainMessage();
msg.what = SyncHandler.MESSAGE_SERVICE_CONNECTED;
- msg.obj = new ServiceConnectionData(this, ISyncAdapter.Stub.asInterface(service));
+ msg.obj = new ServiceConnectionData(this, service);
mSyncHandler.sendMessage(msg);
}
@@ -1112,13 +1182,13 @@ public class SyncManager {
mSyncHandler.sendMessage(msg);
}
- boolean bindToSyncAdapter(RegisteredServicesCache.ServiceInfo info, int userId) {
+ boolean bindToSyncAdapter(ComponentName serviceComponent, int userId) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.d(TAG, "bindToSyncAdapter: " + info.componentName + ", connection " + this);
+ Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
}
Intent intent = new Intent();
intent.setAction("android.content.SyncAdapter");
- intent.setComponent(info.componentName);
+ intent.setComponent(serviceComponent);
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.sync_binding_label);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
@@ -1128,7 +1198,7 @@ public class SyncManager {
final boolean bindResult = mContext.bindServiceAsUser(intent, this,
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
| Context.BIND_ALLOW_OOM_MANAGEMENT,
- new UserHandle(mSyncOperation.userId));
+ new UserHandle(mSyncOperation.target.userId));
if (!bindResult) {
mBound = false;
}
@@ -1151,7 +1221,6 @@ public class SyncManager {
mSyncWakeLock.setWorkSource(null);
}
- @Override
public String toString() {
StringBuilder sb = new StringBuilder();
toString(sb);
@@ -1290,11 +1359,13 @@ public class SyncManager {
int row = table.getNumRows();
Pair<AuthorityInfo, SyncStatusInfo> syncAuthoritySyncStatus =
mSyncStorageEngine.getCopyOfAuthorityWithSyncStatus(
- account.account, account.userId, syncAdapterType.type.authority);
+ new SyncStorageEngine.EndPoint(
+ account.account,
+ syncAdapterType.type.authority,
+ account.userId));
SyncStorageEngine.AuthorityInfo settings = syncAuthoritySyncStatus.first;
SyncStatusInfo status = syncAuthoritySyncStatus.second;
-
- String authority = settings.authority;
+ String authority = settings.target.provider;
if (authority.length() > 50) {
authority = authority.substring(authority.length() - 50);
}
@@ -1415,14 +1486,25 @@ public class SyncManager {
int maxAuthority = 0;
int maxAccount = 0;
for (SyncStorageEngine.SyncHistoryItem item : items) {
- SyncStorageEngine.AuthorityInfo authority
+ SyncStorageEngine.AuthorityInfo authorityInfo
= mSyncStorageEngine.getAuthority(item.authorityId);
final String authorityName;
final String accountKey;
- if (authority != null) {
- authorityName = authority.authority;
- accountKey = authority.account.name + "/" + authority.account.type
- + " u" + authority.userId;
+ if (authorityInfo != null) {
+ if (authorityInfo.target.target_provider) {
+ authorityName = authorityInfo.target.provider;
+ accountKey = authorityInfo.target.account.name + "/"
+ + authorityInfo.target.account.type
+ + " u" + authorityInfo.target.userId;
+ } else if (authorityInfo.target.target_service) {
+ authorityName = authorityInfo.target.service.getPackageName() + "/"
+ + authorityInfo.target.service.getClassName()
+ + " u" + authorityInfo.target.userId;
+ accountKey = "no account";
+ } else {
+ authorityName = "Unknown";
+ accountKey = "Unknown";
+ }
} else {
authorityName = "Unknown";
accountKey = "Unknown";
@@ -1543,14 +1625,25 @@ public class SyncManager {
final PackageManager pm = mContext.getPackageManager();
for (int i = 0; i < N; i++) {
SyncStorageEngine.SyncHistoryItem item = items.get(i);
- SyncStorageEngine.AuthorityInfo authority
+ SyncStorageEngine.AuthorityInfo authorityInfo
= mSyncStorageEngine.getAuthority(item.authorityId);
final String authorityName;
final String accountKey;
- if (authority != null) {
- authorityName = authority.authority;
- accountKey = authority.account.name + "/" + authority.account.type
- + " u" + authority.userId;
+ if (authorityInfo != null) {
+ if (authorityInfo.target.target_provider) {
+ authorityName = authorityInfo.target.provider;
+ accountKey = authorityInfo.target.account.name + "/"
+ + authorityInfo.target.account.type
+ + " u" + authorityInfo.target.userId;
+ } else if (authorityInfo.target.target_service) {
+ authorityName = authorityInfo.target.service.getPackageName() + "/"
+ + authorityInfo.target.service.getClassName()
+ + " u" + authorityInfo.target.userId;
+ accountKey = "none";
+ } else {
+ authorityName = "Unknown";
+ accountKey = "Unknown";
+ }
} else {
authorityName = "Unknown";
accountKey = "Unknown";
@@ -1609,14 +1702,25 @@ public class SyncManager {
if (extras == null || extras.size() == 0) {
continue;
}
- final SyncStorageEngine.AuthorityInfo authority
+ final SyncStorageEngine.AuthorityInfo authorityInfo
= mSyncStorageEngine.getAuthority(item.authorityId);
final String authorityName;
final String accountKey;
- if (authority != null) {
- authorityName = authority.authority;
- accountKey = authority.account.name + "/" + authority.account.type
- + " u" + authority.userId;
+ if (authorityInfo != null) {
+ if (authorityInfo.target.target_provider) {
+ authorityName = authorityInfo.target.provider;
+ accountKey = authorityInfo.target.account.name + "/"
+ + authorityInfo.target.account.type
+ + " u" + authorityInfo.target.userId;
+ } else if (authorityInfo.target.target_service) {
+ authorityName = authorityInfo.target.service.getPackageName() + "/"
+ + authorityInfo.target.service.getClassName()
+ + " u" + authorityInfo.target.userId;
+ accountKey = "none";
+ } else {
+ authorityName = "Unknown";
+ accountKey = "Unknown";
+ }
} else {
authorityName = "Unknown";
accountKey = "Unknown";
@@ -1760,10 +1864,11 @@ public class SyncManager {
class ServiceConnectionData {
public final ActiveSyncContext activeSyncContext;
- public final ISyncAdapter syncAdapter;
- ServiceConnectionData(ActiveSyncContext activeSyncContext, ISyncAdapter syncAdapter) {
+ public final IBinder adapter;
+
+ ServiceConnectionData(ActiveSyncContext activeSyncContext, IBinder adapter) {
this.activeSyncContext = activeSyncContext;
- this.syncAdapter = syncAdapter;
+ this.adapter = adapter;
}
}
@@ -1783,11 +1888,11 @@ public class SyncManager {
public final SyncNotificationInfo mSyncNotificationInfo = new SyncNotificationInfo();
private Long mAlarmScheduleTime = null;
public final SyncTimeTracker mSyncTimeTracker = new SyncTimeTracker();
- private final HashMap<Pair<Account, String>, PowerManager.WakeLock> mWakeLocks =
- Maps.newHashMap();
+ private final HashMap<String, PowerManager.WakeLock> mWakeLocks = Maps.newHashMap();
+
private List<Message> mBootQueue = new ArrayList<Message>();
- public void onBootCompleted() {
+ public void onBootCompleted() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Boot completed, clearing boot queue.");
}
@@ -1802,12 +1907,11 @@ public class SyncManager {
}
}
- private PowerManager.WakeLock getSyncWakeLock(Account account, String authority) {
- final Pair<Account, String> wakeLockKey = Pair.create(account, authority);
+ private PowerManager.WakeLock getSyncWakeLock(SyncOperation operation) {
+ final String wakeLockKey = operation.wakeLockKey();
PowerManager.WakeLock wakeLock = mWakeLocks.get(wakeLockKey);
if (wakeLock == null) {
- final String name = SYNC_WAKE_LOCK_PREFIX + "/" + authority + "/" + account.type
- + "/" + account.name;
+ final String name = SYNC_WAKE_LOCK_PREFIX + operation.wakeLockName();
wakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
wakeLock.setReferenceCounted(false);
mWakeLocks.put(wakeLockKey, wakeLock);
@@ -1860,7 +1964,6 @@ public class SyncManager {
super(looper);
}
- @Override
public void handleMessage(Message msg) {
if (tryEnqueueMessageUntilReadyToRun(msg)) {
return;
@@ -1880,12 +1983,13 @@ public class SyncManager {
earliestFuturePollTime = scheduleReadyPeriodicSyncs();
switch (msg.what) {
case SyncHandler.MESSAGE_CANCEL: {
- Pair<Account, String> payload = (Pair<Account, String>) msg.obj;
+ SyncStorageEngine.EndPoint payload = (SyncStorageEngine.EndPoint) msg.obj;
+ Bundle extras = msg.peekData();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CANCEL: "
- + payload.first + ", " + payload.second);
+ + payload + " bundle: " + extras);
}
- cancelActiveSyncLocked(payload.first, msg.arg1, payload.second);
+ cancelActiveSyncLocked(payload, extras);
nextPendingSyncTime = maybeStartNextSyncLocked();
break;
}
@@ -1894,35 +1998,38 @@ public class SyncManager {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "handleSyncHandlerMessage: MESSAGE_SYNC_FINISHED");
}
- SyncHandlerMessagePayload payload = (SyncHandlerMessagePayload)msg.obj;
+ SyncHandlerMessagePayload payload = (SyncHandlerMessagePayload) msg.obj;
if (!isSyncStillActive(payload.activeSyncContext)) {
Log.d(TAG, "handleSyncHandlerMessage: dropping since the "
+ "sync is no longer active: "
+ payload.activeSyncContext);
break;
}
- runSyncFinishedOrCanceledLocked(payload.syncResult, payload.activeSyncContext);
+ runSyncFinishedOrCanceledLocked(payload.syncResult,
+ payload.activeSyncContext);
// since a sync just finished check if it is time to start a new sync
nextPendingSyncTime = maybeStartNextSyncLocked();
break;
case SyncHandler.MESSAGE_SERVICE_CONNECTED: {
- ServiceConnectionData msgData = (ServiceConnectionData)msg.obj;
+ ServiceConnectionData msgData = (ServiceConnectionData) msg.obj;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_CONNECTED: "
+ msgData.activeSyncContext);
}
// check that this isn't an old message
if (isSyncStillActive(msgData.activeSyncContext)) {
- runBoundToSyncAdapter(msgData.activeSyncContext, msgData.syncAdapter);
+ runBoundToAdapter(
+ msgData.activeSyncContext,
+ msgData.adapter);
}
break;
}
case SyncHandler.MESSAGE_SERVICE_DISCONNECTED: {
final ActiveSyncContext currentSyncContext =
- ((ServiceConnectionData)msg.obj).activeSyncContext;
+ ((ServiceConnectionData) msg.obj).activeSyncContext;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "handleSyncHandlerMessage: MESSAGE_SERVICE_DISCONNECTED: "
+ currentSyncContext);
@@ -1931,12 +2038,15 @@ public class SyncManager {
if (isSyncStillActive(currentSyncContext)) {
// cancel the sync if we have a syncadapter, which means one is
// outstanding
- if (currentSyncContext.mSyncAdapter != null) {
- try {
+ try {
+ if (currentSyncContext.mSyncAdapter != null) {
currentSyncContext.mSyncAdapter.cancelSync(currentSyncContext);
- } catch (RemoteException e) {
- // we don't need to retry this in this case
+ } else if (currentSyncContext.mSyncServiceAdapter != null) {
+ currentSyncContext.mSyncServiceAdapter
+ .cancelSync(currentSyncContext);
}
+ } catch (RemoteException e) {
+ // We don't need to retry this in this case.
}
// pretend that the sync failed with an IOException,
@@ -1981,9 +2091,46 @@ public class SyncManager {
}
}
+ private boolean isDispatchable(SyncStorageEngine.EndPoint target) {
+ final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+ if (target.target_provider) {
+ // skip the sync if the account of this operation no longer exists
+ AccountAndUser[] accounts = mRunningAccounts;
+ if (!containsAccountAndUser(
+ accounts, target.account, target.userId)) {
+ return false;
+ }
+ if (!mSyncStorageEngine.getMasterSyncAutomatically(target.userId)
+ || !mSyncStorageEngine.getSyncAutomatically(
+ target.account,
+ target.userId,
+ target.provider)) {
+ if (isLoggable) {
+ Log.v(TAG, " Not scheduling periodic operation: sync turned off.");
+ }
+ return false;
+ }
+ if (getIsSyncable(target.account, target.userId, target.provider)
+ == 0) {
+ if (isLoggable) {
+ Log.v(TAG, " Not scheduling periodic operation: isSyncable == 0.");
+ }
+ return false;
+ }
+ } else if (target.target_service) {
+ if (mSyncStorageEngine.getIsTargetServiceActive(target.service, target.userId)) {
+ if (isLoggable) {
+ Log.v(TAG, " Not scheduling periodic operation: isEnabled == 0.");
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Turn any periodic sync operations that are ready to run into pending sync operations.
- * @return the desired start time of the earliest future periodic sync operation,
+ * @return the desired start time of the earliest future periodic sync operation,
* in milliseconds since boot
*/
private long scheduleReadyPeriodicSyncs() {
@@ -1991,14 +2138,7 @@ public class SyncManager {
if (isLoggable) {
Log.v(TAG, "scheduleReadyPeriodicSyncs");
}
- final boolean backgroundDataUsageAllowed =
- getConnectivityManager().getBackgroundDataSetting();
long earliestFuturePollTime = Long.MAX_VALUE;
- if (!backgroundDataUsageAllowed) {
- return earliestFuturePollTime;
- }
-
- AccountAndUser[] accounts = mRunningAccounts;
final long nowAbsolute = System.currentTimeMillis();
final long shiftedNowAbsolute = (0 < nowAbsolute - mSyncRandomOffsetMillis)
@@ -2009,37 +2149,24 @@ public class SyncManager {
for (Pair<AuthorityInfo, SyncStatusInfo> info : infos) {
final AuthorityInfo authorityInfo = info.first;
final SyncStatusInfo status = info.second;
- // skip the sync if the account of this operation no longer
- // exists
- if (!containsAccountAndUser(
- accounts, authorityInfo.account, authorityInfo.userId)) {
- continue;
- }
-
- if (!mSyncStorageEngine.getMasterSyncAutomatically(authorityInfo.userId)
- || !mSyncStorageEngine.getSyncAutomatically(
- authorityInfo.account, authorityInfo.userId,
- authorityInfo.authority)) {
- continue;
- }
-
- if (getIsSyncable(
- authorityInfo.account, authorityInfo.userId, authorityInfo.authority)
- == 0) {
+ if (!isDispatchable(authorityInfo.target)) {
continue;
}
for (int i = 0, N = authorityInfo.periodicSyncs.size(); i < N; i++) {
final PeriodicSync sync = authorityInfo.periodicSyncs.get(i);
final Bundle extras = sync.extras;
- final long periodInMillis = sync.period * 1000;
- final long flexInMillis = sync.flexTime * 1000;
+ final Long periodInMillis = sync.period * 1000;
+ final Long flexInMillis = sync.flexTime * 1000;
// Skip if the period is invalid.
if (periodInMillis <= 0) {
continue;
}
// Find when this periodic sync was last scheduled to run.
final long lastPollTimeAbsolute = status.getPeriodicSyncTime(i);
+ final long shiftedLastPollTimeAbsolute =
+ (0 < lastPollTimeAbsolute - mSyncRandomOffsetMillis) ?
+ (lastPollTimeAbsolute - mSyncRandomOffsetMillis) : 0;
long remainingMillis
= periodInMillis - (shiftedNowAbsolute % periodInMillis);
long timeSinceLastRunMillis
@@ -2050,12 +2177,13 @@ public class SyncManager {
boolean runEarly = remainingMillis <= flexInMillis
&& timeSinceLastRunMillis > periodInMillis - flexInMillis;
if (isLoggable) {
- Log.v(TAG, "sync: " + i + " for " + authorityInfo.authority + "."
+ Log.v(TAG, "sync: " + i + " for " + authorityInfo.target + "."
+ " period: " + (periodInMillis)
+ " flex: " + (flexInMillis)
+ " remaining: " + (remainingMillis)
+ " time_since_last: " + timeSinceLastRunMillis
+ " last poll absol: " + lastPollTimeAbsolute
+ + " last poll shifed: " + shiftedLastPollTimeAbsolute
+ " shifted now: " + shiftedNowAbsolute
+ " run_early: " + runEarly);
}
@@ -2069,41 +2197,49 @@ public class SyncManager {
* future, sync now and reinitialize. This can happen for
* example if the user changed the time, synced and changed
* back.
- * Case 3: If we failed to sync at the last scheduled
- * time.
+ * Case 3: If we failed to sync at the last scheduled time.
* Case 4: This sync is close enough to the time that we can schedule it.
*/
- if (runEarly // Case 4
- || remainingMillis == periodInMillis // Case 1
+ if (remainingMillis == periodInMillis // Case 1
|| lastPollTimeAbsolute > nowAbsolute // Case 2
- || timeSinceLastRunMillis >= periodInMillis) { // Case 3
+ || timeSinceLastRunMillis >= periodInMillis // Case 3
+ || runEarly) { // Case 4
// Sync now
-
- final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
- authorityInfo.account, authorityInfo.userId,
- authorityInfo.authority);
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
- syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(
- authorityInfo.authority, authorityInfo.account.type),
- authorityInfo.userId);
- if (syncAdapterInfo == null) {
- continue;
- }
+ SyncStorageEngine.EndPoint target = authorityInfo.target;
+ final Pair<Long, Long> backoff =
+ mSyncStorageEngine.getBackoff(target);
mSyncStorageEngine.setPeriodicSyncTime(authorityInfo.ident,
authorityInfo.periodicSyncs.get(i), nowAbsolute);
- scheduleSyncOperation(
- new SyncOperation(authorityInfo.account, authorityInfo.userId,
- SyncOperation.REASON_PERIODIC,
- SyncStorageEngine.SOURCE_PERIODIC,
- authorityInfo.authority, extras,
- 0 /* runtime */, 0 /* flex */,
- backoff != null ? backoff.first : 0,
- mSyncStorageEngine.getDelayUntilTime(
- authorityInfo.account, authorityInfo.userId,
- authorityInfo.authority),
- syncAdapterInfo.type.allowParallelSyncs()));
-
+
+ if (target.target_provider) {
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType>
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(
+ target.provider, target.account.type),
+ target.userId);
+ if (syncAdapterInfo == null) {
+ continue;
+ }
+ scheduleSyncOperation(
+ new SyncOperation(target.account, target.userId,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_PERIODIC,
+ target.provider, extras,
+ 0 /* runtime */, 0 /* flex */,
+ backoff != null ? backoff.first : 0,
+ mSyncStorageEngine.getDelayUntilTime(target),
+ syncAdapterInfo.type.allowParallelSyncs()));
+ } else if (target.target_service) {
+ scheduleSyncOperation(
+ new SyncOperation(target.service, target.userId,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_PERIODIC,
+ extras,
+ 0 /* runtime */,
+ 0 /* flex */,
+ backoff != null ? backoff.first : 0,
+ mSyncStorageEngine.getDelayUntilTime(target)));
+ }
}
// Compute when this periodic sync should next run.
long nextPollTimeAbsolute;
@@ -2150,8 +2286,7 @@ public class SyncManager {
// If the accounts aren't known yet then we aren't ready to run. We will be kicked
// when the account lookup request does complete.
- AccountAndUser[] accounts = mRunningAccounts;
- if (accounts == INITIAL_ACCOUNTS_ARRAY) {
+ if (mRunningAccounts == INITIAL_ACCOUNTS_ARRAY) {
if (isLoggable) {
Log.v(TAG, "maybeStartNextSync: accounts not known, skipping");
}
@@ -2161,9 +2296,6 @@ public class SyncManager {
// Otherwise consume SyncOperations from the head of the SyncQueue until one is
// found that is runnable (not disabled, etc). If that one is ready to run then
// start it, otherwise just get out.
- final boolean backgroundDataUsageAllowed =
- getConnectivityManager().getBackgroundDataSetting();
-
final long now = SystemClock.elapsedRealtime();
// will be set to the next time that a sync should be considered for running
@@ -2185,40 +2317,23 @@ public class SyncManager {
while (operationIterator.hasNext()) {
final SyncOperation op = operationIterator.next();
- // Drop the sync if the account of this operation no longer exists.
- if (!containsAccountAndUser(accounts, op.account, op.userId)) {
- operationIterator.remove();
- mSyncStorageEngine.deleteFromPending(op.pendingOperation);
+ // If the user is not running, skip the request.
+ if (!activityManager.isUserRunning(op.target.userId)) {
+ final UserInfo userInfo = mUserManager.getUserInfo(op.target.userId);
+ if (userInfo == null) {
+ removedUsers.add(op.target.userId);
+ }
if (isLoggable) {
- Log.v(TAG, " Dropping sync operation: account doesn't exist.");
+ Log.v(TAG, " Dropping all sync operations for + "
+ + op.target.userId + ": user not running.");
}
continue;
}
-
- // Drop this sync request if it isn't syncable.
- int syncableState = getIsSyncable(
- op.account, op.userId, op.authority);
- if (syncableState == 0) {
+ if (!isOperationValidLocked(op)) {
operationIterator.remove();
mSyncStorageEngine.deleteFromPending(op.pendingOperation);
- if (isLoggable) {
- Log.v(TAG, " Dropping sync operation: isSyncable == 0.");
- }
- continue;
- }
-
- // If the user is not running, drop the request.
- if (!activityManager.isUserRunning(op.userId)) {
- final UserInfo userInfo = mUserManager.getUserInfo(op.userId);
- if (userInfo == null) {
- removedUsers.add(op.userId);
- }
- if (isLoggable) {
- Log.v(TAG, " Dropping sync operation: user not running.");
- }
continue;
}
-
// If the next run time is in the future, even given the flexible scheduling,
// return the time.
if (op.effectiveRunTime - op.flexTime > now) {
@@ -2226,51 +2341,16 @@ public class SyncManager {
nextReadyToRunTime = op.effectiveRunTime;
}
if (isLoggable) {
- Log.v(TAG, " Dropping sync operation: Sync too far in future.");
+ Log.v(TAG, " Not running sync operation: Sync too far in future."
+ + "effective: " + op.effectiveRunTime + " flex: " + op.flexTime
+ + " now: " + now);
}
continue;
}
-
- // If the op isn't allowed on metered networks and we're on one, drop it.
- if (getConnectivityManager().isActiveNetworkMetered()
- && op.isMeteredDisallowed()) {
- operationIterator.remove();
- mSyncStorageEngine.deleteFromPending(op.pendingOperation);
- continue;
- }
-
- // TODO: change this behaviour for non-registered syncs.
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
- syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
-
- // only proceed if network is connected for requesting UID
- final boolean uidNetworkConnected;
- if (syncAdapterInfo != null) {
- final NetworkInfo networkInfo = getConnectivityManager()
- .getActiveNetworkInfoForUid(syncAdapterInfo.uid);
- uidNetworkConnected = networkInfo != null && networkInfo.isConnected();
- } else {
- uidNetworkConnected = false;
- }
-
- // skip the sync if it isn't manual, and auto sync or
- // background data usage is disabled or network is
- // disconnected for the target UID.
- if (!op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
- && (syncableState > 0)
- && (!mSyncStorageEngine.getMasterSyncAutomatically(op.userId)
- || !backgroundDataUsageAllowed
- || !uidNetworkConnected
- || !mSyncStorageEngine.getSyncAutomatically(
- op.account, op.userId, op.authority))) {
- operationIterator.remove();
- mSyncStorageEngine.deleteFromPending(op.pendingOperation);
- continue;
- }
-
+ // Add this sync to be run.
operations.add(op);
}
+
for (Integer user : removedUsers) {
// if it's still removed
if (mUserManager.getUserInfo(user) == null) {
@@ -2312,13 +2392,9 @@ public class SyncManager {
}
}
}
- if (activeOp.account.type.equals(candidate.account.type)
- && activeOp.authority.equals(candidate.authority)
- && activeOp.userId == candidate.userId
- && (!activeOp.allowParallelSyncs
- || activeOp.account.name.equals(candidate.account.name))) {
+ if (activeOp.isConflict(candidate)) {
conflict = activeSyncContext;
- // don't break out since we want to do a full count of the varieties
+ // don't break out since we want to do a full count of the varieties.
} else {
if (candidateIsInitialization == activeOp.isInitialization()
&& activeSyncContext.mStartTime + MAX_TIME_PER_SYNC < now) {
@@ -2368,8 +2444,8 @@ public class SyncManager {
// is null. Reschedule the active sync and start the candidate.
toReschedule = oldestNonExpeditedRegular;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "canceling and rescheduling sync since an expedited is ready to run, "
- + oldestNonExpeditedRegular);
+ Log.v(TAG, "canceling and rescheduling sync since an expedited is ready to"
+ + " run, " + oldestNonExpeditedRegular);
}
} else if (longRunning != null
&& (candidateIsInitialization
@@ -2398,7 +2474,114 @@ public class SyncManager {
}
return nextReadyToRunTime;
- }
+ }
+
+ /**
+ * Determine if a sync is no longer valid and should be dropped from the sync queue and its
+ * pending op deleted.
+ * @param op operation for which the sync is to be scheduled.
+ */
+ private boolean isOperationValidLocked(SyncOperation op) {
+ final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+ int targetUid;
+ int state;
+ final SyncStorageEngine.EndPoint target = op.target;
+ boolean syncEnabled = mSyncStorageEngine.getMasterSyncAutomatically(target.userId);
+ if (target.target_provider) {
+ // Drop the sync if the account of this operation no longer exists.
+ AccountAndUser[] accounts = mRunningAccounts;
+ if (!containsAccountAndUser(accounts, target.account, target.userId)) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: account doesn't exist.");
+ }
+ return false;
+ }
+ // Drop this sync request if it isn't syncable.
+ state = getIsSyncable(target.account, target.userId, target.provider);
+ if (state == 0) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: isSyncable == 0.");
+ }
+ return false;
+ }
+ syncEnabled = syncEnabled && mSyncStorageEngine.getSyncAutomatically(
+ target.account, target.userId, target.provider);
+
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(
+ target.provider, target.account.type), target.userId);
+ if (syncAdapterInfo != null) {
+ targetUid = syncAdapterInfo.uid;
+ } else {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: No sync adapter registered"
+ + "for: " + target);
+ }
+ return false;
+ }
+ } else if (target.target_service) {
+ state = mSyncStorageEngine.getIsTargetServiceActive(target.service, target.userId)
+ ? 1 : 0;
+ if (state == 0) {
+ // TODO: Change this to not drop disabled syncs - keep them in the pending queue.
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: isActive == 0.");
+ }
+ return false;
+ }
+ try {
+ targetUid = mContext.getPackageManager()
+ .getServiceInfo(target.service, 0)
+ .applicationInfo
+ .uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: No service registered for: "
+ + target.service);
+ }
+ return false;
+ }
+ } else {
+ Log.e(TAG, "Unknown target for Sync Op: " + target);
+ return false;
+ }
+
+ // We ignore system settings that specify the sync is invalid if:
+ // 1) It's manual - we try it anyway. When/if it fails it will be rescheduled.
+ // or
+ // 2) it's an initialisation sync - we just need to connect to it.
+ final boolean ignoreSystemConfiguration =
+ op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
+ || (state < 0);
+
+ // Sync not enabled.
+ if (!syncEnabled && !ignoreSystemConfiguration) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: disallowed by settings/network.");
+ }
+ return false;
+ }
+ // Network down.
+ final NetworkInfo networkInfo = getConnectivityManager()
+ .getActiveNetworkInfoForUid(targetUid);
+ final boolean uidNetworkConnected = networkInfo != null && networkInfo.isConnected();
+ if (!uidNetworkConnected && !ignoreSystemConfiguration) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: disallowed by settings/network.");
+ }
+ return false;
+ }
+ // Metered network.
+ if (op.isNotAllowedOnMetered() && getConnectivityManager().isActiveNetworkMetered()
+ && !ignoreSystemConfiguration) {
+ if (isLoggable) {
+ Log.v(TAG, " Dropping sync operation: not allowed on metered network.");
+ }
+ return false;
+ }
+ return true;
+ }
private boolean dispatchSyncOperation(SyncOperation op) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2408,27 +2591,48 @@ public class SyncManager {
Log.v(TAG, syncContext.toString());
}
}
-
- // connect to the sync adapter
- SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type);
- final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
- syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, op.userId);
- if (syncAdapterInfo == null) {
- Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
- + ", removing settings for it");
- mSyncStorageEngine.removeAuthority(op.account, op.userId, op.authority);
- return false;
+ // Connect to the sync adapter.
+ int targetUid;
+ ComponentName targetComponent;
+ final SyncStorageEngine.EndPoint info = op.target;
+ if (info.target_provider) {
+ SyncAdapterType syncAdapterType =
+ SyncAdapterType.newKey(info.provider, info.account.type);
+ final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+ syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, info.userId);
+ if (syncAdapterInfo == null) {
+ Log.d(TAG, "can't find a sync adapter for " + syncAdapterType
+ + ", removing settings for it");
+ mSyncStorageEngine.removeAuthority(info);
+ return false;
+ }
+ targetUid = syncAdapterInfo.uid;
+ targetComponent = syncAdapterInfo.componentName;
+ } else {
+ // TODO: Store the uid of the service as part of the authority info in order to
+ // avoid this call?
+ try {
+ targetUid = mContext.getPackageManager()
+ .getServiceInfo(info.service, 0)
+ .applicationInfo
+ .uid;
+ targetComponent = info.service;
+ } catch(PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Can't find a service for " + info.service
+ + ", removing settings for it");
+ mSyncStorageEngine.removeAuthority(info);
+ return false;
+ }
}
-
ActiveSyncContext activeSyncContext =
- new ActiveSyncContext(op, insertStartSyncEvent(op), syncAdapterInfo.uid);
+ new ActiveSyncContext(op, insertStartSyncEvent(op), targetUid);
activeSyncContext.mSyncInfo = mSyncStorageEngine.addActiveSync(activeSyncContext);
mActiveSyncContexts.add(activeSyncContext);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "dispatchSyncOperation: starting " + activeSyncContext);
}
- if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo, op.userId)) {
- Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);
+ if (!activeSyncContext.bindToSyncAdapter(targetComponent, info.userId)) {
+ Log.e(TAG, "Bind attempt failed - target: " + targetComponent);
closeActiveSyncContext(activeSyncContext);
return false;
}
@@ -2436,47 +2640,54 @@ public class SyncManager {
return true;
}
- private void runBoundToSyncAdapter(final ActiveSyncContext activeSyncContext,
- ISyncAdapter syncAdapter) {
- activeSyncContext.mSyncAdapter = syncAdapter;
+ private void runBoundToAdapter(final ActiveSyncContext activeSyncContext,
+ IBinder syncAdapter) {
final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
try {
activeSyncContext.mIsLinkedToDeath = true;
- syncAdapter.asBinder().linkToDeath(activeSyncContext, 0);
-
- syncAdapter.startSync(activeSyncContext, syncOperation.authority,
- syncOperation.account, syncOperation.extras);
+ syncAdapter.linkToDeath(activeSyncContext, 0);
+
+ if (syncOperation.target.target_provider) {
+ activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter);
+ activeSyncContext.mSyncAdapter
+ .startSync(activeSyncContext, syncOperation.target.provider,
+ syncOperation.target.account, syncOperation.extras);
+ } else if (syncOperation.target.target_service) {
+ activeSyncContext.mSyncServiceAdapter =
+ ISyncServiceAdapter.Stub.asInterface(syncAdapter);
+ activeSyncContext.mSyncServiceAdapter
+ .startSync(activeSyncContext, syncOperation.extras);
+ }
} catch (RemoteException remoteExc) {
Log.d(TAG, "maybeStartNextSync: caught a RemoteException, rescheduling", remoteExc);
closeActiveSyncContext(activeSyncContext);
increaseBackoffSetting(syncOperation);
- scheduleSyncOperation(new SyncOperation(syncOperation));
+ scheduleSyncOperation(
+ new SyncOperation(syncOperation, 0L /* newRunTimeFromNow */));
} catch (RuntimeException exc) {
closeActiveSyncContext(activeSyncContext);
Log.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
}
}
- private void cancelActiveSyncLocked(Account account, int userId, String authority) {
+ /**
+ * Cancel the sync for the provided target that matches the given bundle.
+ * @param info can have null fields to indicate all the active syncs for that field.
+ */
+ private void cancelActiveSyncLocked(SyncStorageEngine.EndPoint info, Bundle extras) {
ArrayList<ActiveSyncContext> activeSyncs =
new ArrayList<ActiveSyncContext>(mActiveSyncContexts);
for (ActiveSyncContext activeSyncContext : activeSyncs) {
if (activeSyncContext != null) {
- // if an account was specified then only cancel the sync if it matches
- if (account != null) {
- if (!account.equals(activeSyncContext.mSyncOperation.account)) {
- continue;
- }
- }
- // if an authority was specified then only cancel the sync if it matches
- if (authority != null) {
- if (!authority.equals(activeSyncContext.mSyncOperation.authority)) {
- continue;
- }
+ final SyncStorageEngine.EndPoint opInfo =
+ activeSyncContext.mSyncOperation.target;
+ if (!opInfo.matchesSpec(info)) {
+ continue;
}
- // check if the userid matches
- if (userId != UserHandle.USER_ALL
- && userId != activeSyncContext.mSyncOperation.userId) {
+ if (extras != null &&
+ !syncExtrasEquals(activeSyncContext.mSyncOperation.extras,
+ extras,
+ false /* no config settings */)) {
continue;
}
runSyncFinishedOrCanceledLocked(null /* no result since this is a cancel */,
@@ -2489,16 +2700,20 @@ public class SyncManager {
ActiveSyncContext activeSyncContext) {
boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
+ final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
+ final SyncStorageEngine.EndPoint info = syncOperation.target;
+
if (activeSyncContext.mIsLinkedToDeath) {
- activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
+ if (info.target_provider) {
+ activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
+ } else {
+ activeSyncContext.mSyncServiceAdapter.asBinder()
+ .unlinkToDeath(activeSyncContext, 0);
+ }
activeSyncContext.mIsLinkedToDeath = false;
}
closeActiveSyncContext(activeSyncContext);
-
- final SyncOperation syncOperation = activeSyncContext.mSyncOperation;
-
final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
-
String historyMessage;
int downstreamActivity;
int upstreamActivity;
@@ -2540,6 +2755,12 @@ public class SyncManager {
} catch (RemoteException e) {
// we don't need to retry this in this case
}
+ } else if (activeSyncContext.mSyncServiceAdapter != null) {
+ try {
+ activeSyncContext.mSyncServiceAdapter.cancelSync(activeSyncContext);
+ } catch (RemoteException e) {
+ // we don't need to retry this in this case
+ }
}
historyMessage = SyncStorageEngine.MESG_CANCELED;
downstreamActivity = 0;
@@ -2549,24 +2770,35 @@ public class SyncManager {
stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
upstreamActivity, downstreamActivity, elapsedTime);
- if (syncResult != null && syncResult.tooManyDeletions) {
- installHandleTooManyDeletesNotification(syncOperation.account,
- syncOperation.authority, syncResult.stats.numDeletes,
- syncOperation.userId);
+ // Check for full-resync and schedule it after closing off the last sync.
+ if (info.target_provider) {
+ if (syncResult != null && syncResult.tooManyDeletions) {
+ installHandleTooManyDeletesNotification(info.account,
+ info.provider, syncResult.stats.numDeletes,
+ info.userId);
+ } else {
+ mNotificationMgr.cancelAsUser(null,
+ info.account.hashCode() ^ info.provider.hashCode(),
+ new UserHandle(info.userId));
+ }
+ if (syncResult != null && syncResult.fullSyncRequested) {
+ scheduleSyncOperation(
+ new SyncOperation(info.account, info.userId,
+ syncOperation.reason,
+ syncOperation.syncSource, info.provider, new Bundle(),
+ 0 /* delay */, 0 /* flex */,
+ syncOperation.backoff, syncOperation.delayUntil,
+ syncOperation.allowParallelSyncs));
+ }
} else {
- mNotificationMgr.cancelAsUser(null,
- syncOperation.account.hashCode() ^ syncOperation.authority.hashCode(),
- new UserHandle(syncOperation.userId));
- }
-
- if (syncResult != null && syncResult.fullSyncRequested) {
- scheduleSyncOperation(
- new SyncOperation(syncOperation.account, syncOperation.userId,
- syncOperation.reason,
- syncOperation.syncSource, syncOperation.authority, new Bundle(),
- 0 /* delay */, 0 /* flex */,
- syncOperation.backoff, syncOperation.delayUntil,
- syncOperation.allowParallelSyncs));
+ if (syncResult != null && syncResult.fullSyncRequested) {
+ scheduleSyncOperation(
+ new SyncOperation(info.service, info.userId,
+ syncOperation.reason,
+ syncOperation.syncSource, new Bundle(),
+ 0 /* delay */, 0 /* flex */,
+ syncOperation.backoff, syncOperation.delayUntil));
+ }
}
// no need to schedule an alarm, as that will be done by our caller.
}
@@ -2575,7 +2807,7 @@ public class SyncManager {
activeSyncContext.close();
mActiveSyncContexts.remove(activeSyncContext);
mSyncStorageEngine.removeActiveSync(activeSyncContext.mSyncInfo,
- activeSyncContext.mSyncOperation.userId);
+ activeSyncContext.mSyncOperation.target.userId);
}
/**
@@ -2838,26 +3070,16 @@ public class SyncManager {
}
public long insertStartSyncEvent(SyncOperation syncOperation) {
- final int source = syncOperation.syncSource;
final long now = System.currentTimeMillis();
-
- EventLog.writeEvent(2720, syncOperation.authority,
- SyncStorageEngine.EVENT_START, source,
- syncOperation.account.name.hashCode());
-
- return mSyncStorageEngine.insertStartSyncEvent(
- syncOperation.account, syncOperation.userId, syncOperation.reason,
- syncOperation.authority,
- now, source, syncOperation.isInitialization(), syncOperation.extras
- );
+ EventLog.writeEvent(2720,
+ syncOperation.toEventLog(SyncStorageEngine.EVENT_START));
+ return mSyncStorageEngine.insertStartSyncEvent(syncOperation, now);
}
public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
int upstreamActivity, int downstreamActivity, long elapsedTime) {
- EventLog.writeEvent(2720, syncOperation.authority,
- SyncStorageEngine.EVENT_STOP, syncOperation.syncSource,
- syncOperation.account.name.hashCode());
-
+ EventLog.writeEvent(2720,
+ syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
resultMessage, downstreamActivity, upstreamActivity);
}
@@ -2872,6 +3094,83 @@ public class SyncManager {
return false;
}
+ /**
+ * Sync extra comparison function.
+ * @param b1 bundle to compare
+ * @param b2 other bundle to compare
+ * @param includeSyncSettings if false, ignore system settings in bundle.
+ */
+ public static boolean syncExtrasEquals(Bundle b1, Bundle b2, boolean includeSyncSettings) {
+ if (b1 == b2) {
+ return true;
+ }
+ // Exit early if we can.
+ if (includeSyncSettings && b1.size() != b2.size()) {
+ return false;
+ }
+ Bundle bigger = b1.size() > b2.size() ? b1 : b2;
+ Bundle smaller = b1.size() > b2.size() ? b2 : b1;
+ for (String key : bigger.keySet()) {
+ if (!includeSyncSettings && isSyncSetting(key)) {
+ continue;
+ }
+ if (!smaller.containsKey(key)) {
+ return false;
+ }
+ if (!bigger.get(key).equals(smaller.get(key))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * TODO: Get rid of this when we separate sync settings extras from dev specified extras.
+ * @return true if the provided key is used by the SyncManager in scheduling the sync.
+ */
+ private static boolean isSyncSetting(String key) {
+ if (key.equals(ContentResolver.SYNC_EXTRAS_EXPEDITED)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_MANUAL)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_UPLOAD)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_PRIORITY)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED)) {
+ return true;
+ }
+ if (key.equals(ContentResolver.SYNC_EXTRAS_INITIALIZE)) {
+ return true;
+ }
+ return false;
+ }
+
static class PrintTable {
private ArrayList<Object[]> mTable = Lists.newArrayList();
private final int mCols;
diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/java/com/android/server/content/SyncOperation.java
index 4856747..036b21f 100644
--- a/services/java/com/android/server/content/SyncOperation.java
+++ b/services/java/com/android/server/content/SyncOperation.java
@@ -20,10 +20,9 @@ import android.accounts.Account;
import android.content.pm.PackageManager;
import android.content.ComponentName;
import android.content.ContentResolver;
-import android.content.SyncRequest;
import android.os.Bundle;
import android.os.SystemClock;
-import android.util.Pair;
+import android.util.Log;
/**
* Value type that represents a sync operation.
@@ -32,10 +31,13 @@ import android.util.Pair;
* {@hide}
*/
public class SyncOperation implements Comparable {
+ public static final String TAG = "SyncManager";
+
public static final int REASON_BACKGROUND_DATA_SETTINGS_CHANGED = -1;
public static final int REASON_ACCOUNTS_UPDATED = -2;
public static final int REASON_SERVICE_CHANGED = -3;
public static final int REASON_PERIODIC = -4;
+ /** Sync started because it has just been set to isSyncable. */
public static final int REASON_IS_SYNCABLE = -5;
/** Sync started because it has just been set to sync automatically. */
public static final int REASON_SYNC_AUTO = -6;
@@ -54,19 +56,21 @@ public class SyncOperation implements Comparable {
"UserStart",
};
- /** Account info to identify a SyncAdapter registered with the system. */
- public final Account account;
- /** Authority info to identify a SyncAdapter registered with the system. */
- public final String authority;
- /** Service to which this operation will bind to perform the sync. */
- public final ComponentName service;
- public final int userId;
+ public static final int SYNC_TARGET_UNKNOWN = 0;
+ public static final int SYNC_TARGET_ADAPTER = 1;
+ public static final int SYNC_TARGET_SERVICE = 2;
+
+ /** Identifying info for the target for this operation. */
+ public final SyncStorageEngine.EndPoint target;
+ /** Why this sync was kicked off. {@link #REASON_NAMES} */
public final int reason;
+ /** Where this sync was initiated. */
public int syncSource;
public final boolean allowParallelSyncs;
public Bundle extras;
public final String key;
public boolean expedited;
+ /** Bare-bones version of this operation that is persisted across reboots. */
public SyncStorageEngine.PendingOperation pendingOperation;
/** Elapsed real time in millis at which to run this sync. */
public long latestRunTime;
@@ -79,25 +83,56 @@ public class SyncOperation implements Comparable {
* Depends on max(backoff, latestRunTime, and delayUntil).
*/
public long effectiveRunTime;
- /** Amount of time before {@link effectiveRunTime} from which this sync can run. */
+ /** Amount of time before {@link #effectiveRunTime} from which this sync can run. */
public long flexTime;
- public SyncOperation(Account account, int userId, int reason, int source, String authority,
+ public SyncOperation(Account account, int userId, int reason, int source, String provider,
Bundle extras, long runTimeFromNow, long flexTime, long backoff,
long delayUntil, boolean allowParallelSyncs) {
- this.service = null;
- this.account = account;
- this.authority = authority;
- this.userId = userId;
+ this.target = new SyncStorageEngine.EndPoint(account, provider, userId);
this.reason = reason;
- this.syncSource = source;
this.allowParallelSyncs = allowParallelSyncs;
+ this.key = initialiseOperation(this.target, source, extras, runTimeFromNow, flexTime,
+ backoff, delayUntil);
+ }
+
+ public SyncOperation(ComponentName service, int userId, int reason, int source,
+ Bundle extras, long runTimeFromNow, long flexTime, long backoff,
+ long delayUntil) {
+ this.target = new SyncStorageEngine.EndPoint(service, userId);
+ // Default to true for sync service. The service itself decides how to handle this.
+ this.allowParallelSyncs = true;
+ this.reason = reason;
+ this.key =
+ initialiseOperation(this.target,
+ source, extras, runTimeFromNow, flexTime, backoff, delayUntil);
+ }
+
+ /** Used to reschedule a sync at a new point in time. */
+ SyncOperation(SyncOperation other, long newRunTimeFromNow) {
+ this.target = other.target;
+ this.reason = other.reason;
+ this.expedited = other.expedited;
+ this.allowParallelSyncs = other.allowParallelSyncs;
+ // re-use old flex, but only
+ long newFlexTime = Math.min(other.flexTime, newRunTimeFromNow);
+ this.key =
+ initialiseOperation(this.target,
+ other.syncSource, other.extras,
+ newRunTimeFromNow /* runTimeFromNow*/,
+ newFlexTime /* flexTime */,
+ other.backoff,
+ 0L /* delayUntil */);
+ }
+
+ private String initialiseOperation(SyncStorageEngine.EndPoint info, int source, Bundle extras,
+ long runTimeFromNow, long flexTime, long backoff, long delayUntil) {
+ this.syncSource = source;
this.extras = new Bundle(extras);
cleanBundle(this.extras);
this.delayUntil = delayUntil;
this.backoff = backoff;
final long now = SystemClock.elapsedRealtime();
- // Checks the extras bundle. Must occur after we set the internal bundle.
if (runTimeFromNow < 0 || isExpedited()) {
this.expedited = true;
this.latestRunTime = now;
@@ -108,7 +143,11 @@ public class SyncOperation implements Comparable {
this.flexTime = flexTime;
}
updateEffectiveRunTime();
- this.key = toKey();
+ return toKey(info, this.extras);
+ }
+
+ public boolean matchesAuthority(SyncOperation other) {
+ return this.target.matchesSpec(other.target);
}
/**
@@ -126,10 +165,6 @@ public class SyncOperation implements Comparable {
removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_EXPEDITED);
removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS);
removeFalseExtra(bundle, ContentResolver.SYNC_EXTRAS_DISALLOW_METERED);
-
- // Remove Config data.
- bundle.remove(ContentResolver.SYNC_EXTRAS_EXPECTED_UPLOAD);
- bundle.remove(ContentResolver.SYNC_EXTRAS_EXPECTED_DOWNLOAD);
}
private void removeFalseExtra(Bundle bundle, String extraName) {
@@ -138,22 +173,24 @@ public class SyncOperation implements Comparable {
}
}
- /** Only used to immediately reschedule a sync. */
- SyncOperation(SyncOperation other) {
- this.service = other.service;
- this.account = other.account;
- this.authority = other.authority;
- this.userId = other.userId;
- this.reason = other.reason;
- this.syncSource = other.syncSource;
- this.extras = new Bundle(other.extras);
- this.expedited = other.expedited;
- this.latestRunTime = SystemClock.elapsedRealtime();
- this.flexTime = 0L;
- this.backoff = other.backoff;
- this.allowParallelSyncs = other.allowParallelSyncs;
- this.updateEffectiveRunTime();
- this.key = toKey();
+ /**
+ * Determine whether if this sync operation is running, the provided operation would conflict
+ * with it.
+ * Parallel syncs allow multiple accounts to be synced at the same time.
+ */
+ public boolean isConflict(SyncOperation toRun) {
+ final SyncStorageEngine.EndPoint other = toRun.target;
+ if (target.target_provider) {
+ return target.account.type.equals(other.account.type)
+ && target.provider.equals(other.provider)
+ && target.userId == other.userId
+ && (!allowParallelSyncs
+ || target.account.name.equals(other.account.name));
+ } else {
+ // Ops that target a service default to allow parallel syncs, which is handled by the
+ // service returning SYNC_IN_PROGRESS if they don't.
+ return target.service.equals(other.service) && !allowParallelSyncs;
+ }
}
@Override
@@ -162,18 +199,26 @@ public class SyncOperation implements Comparable {
}
public String dump(PackageManager pm, boolean useOneLine) {
- StringBuilder sb = new StringBuilder()
- .append(account.name)
+ StringBuilder sb = new StringBuilder();
+ if (target.target_provider) {
+ sb.append(target.account.name)
.append(" u")
- .append(userId).append(" (")
- .append(account.type)
+ .append(target.userId).append(" (")
+ .append(target.account.type)
.append(")")
.append(", ")
- .append(authority)
- .append(", ")
- .append(SyncStorageEngine.SOURCES[syncSource])
- .append(", latestRunTime ")
- .append(latestRunTime);
+ .append(target.provider)
+ .append(", ");
+ } else if (target.target_service) {
+ sb.append(target.service.getPackageName())
+ .append(" u")
+ .append(target.userId).append(" (")
+ .append(target.service.getClassName()).append(")")
+ .append(", ");
+ }
+ sb.append(SyncStorageEngine.SOURCES[syncSource])
+ .append(", currentRunTime ")
+ .append(effectiveRunTime);
if (expedited) {
sb.append(", EXPEDITED");
}
@@ -211,10 +256,6 @@ public class SyncOperation implements Comparable {
}
}
- public boolean isMeteredDisallowed() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, false);
- }
-
public boolean isInitialization() {
return extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
}
@@ -227,28 +268,39 @@ public class SyncOperation implements Comparable {
return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false);
}
+ public boolean isNotAllowedOnMetered() {
+ return extras.getBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, false);
+ }
+
/** Changed in V3. */
- private String toKey() {
+ public static String toKey(SyncStorageEngine.EndPoint info, Bundle extras) {
StringBuilder sb = new StringBuilder();
- if (service == null) {
- sb.append("authority: ").append(authority);
- sb.append(" account {name=" + account.name + ", user=" + userId + ", type=" + account.type
+ if (info.target_provider) {
+ sb.append("provider: ").append(info.provider);
+ sb.append(" account {name=" + info.account.name
+ + ", user="
+ + info.userId
+ + ", type="
+ + info.account.type
+ "}");
- } else {
+ } else if (info.target_service) {
sb.append("service {package=" )
- .append(service.getPackageName())
+ .append(info.service.getPackageName())
.append(" user=")
- .append(userId)
+ .append(info.userId)
.append(", class=")
- .append(service.getClassName())
+ .append(info.service.getClassName())
.append("}");
+ } else {
+ Log.v(TAG, "Converting SyncOperaton to key, invalid target: " + info.toString());
+ return "";
}
sb.append(" extras: ");
extrasToStringBuilder(extras, sb);
return sb.toString();
}
- public static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
+ private static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
sb.append("[");
for (String key : bundle.keySet()) {
sb.append(key).append("=").append(bundle.get(key)).append(" ");
@@ -256,6 +308,31 @@ public class SyncOperation implements Comparable {
sb.append("]");
}
+ public String wakeLockKey() {
+ if (target.target_provider) {
+ return target.account.name + "/" + target.account.type + ":" + target.provider;
+ } else if (target.target_service) {
+ return target.service.getPackageName() + "/" + target.service.getClassName();
+ } else {
+ Log.wtf(TAG, "Invalid target getting wakelock for operation - " + key);
+ return null;
+ }
+ }
+
+ public String wakeLockName() {
+ if (target.target_provider) {
+ return "/" + target.provider
+ + "/" + target.account.type
+ + "/" + target.account.name;
+ } else if (target.target_service) {
+ return "/" + target.service.getPackageName()
+ + "/" + target.service.getClassName();
+ } else {
+ Log.wtf(TAG, "Invalid target getting wakelock name for operation - " + key);
+ return null;
+ }
+ }
+
/**
* Update the effective run time of this Operation based on latestRunTime (specified at
* creation time of sync), delayUntil (specified by SyncAdapter), or backoff (specified by
@@ -291,4 +368,21 @@ public class SyncOperation implements Comparable {
return 0;
}
}
+
+ // TODO: Test this to make sure that casting to object doesn't lose the type info for EventLog.
+ public Object[] toEventLog(int event) {
+ Object[] logArray = new Object[4];
+ logArray[1] = event;
+ logArray[2] = syncSource;
+ if (target.target_provider) {
+ logArray[0] = target.provider;
+ logArray[3] = target.account.name.hashCode();
+ } else if (target.target_service) {
+ logArray[0] = target.service.getPackageName();
+ logArray[3] = target.service.hashCode();
+ } else {
+ Log.wtf(TAG, "sync op with invalid target: " + key);
+ }
+ return logArray;
+ }
}
diff --git a/services/java/com/android/server/content/SyncQueue.java b/services/java/com/android/server/content/SyncQueue.java
index 6f3fe6e..5d93882 100644
--- a/services/java/com/android/server/content/SyncQueue.java
+++ b/services/java/com/android/server/content/SyncQueue.java
@@ -16,12 +16,11 @@
package com.android.server.content;
-import android.accounts.Account;
import android.content.pm.PackageManager;
-import android.content.pm.RegisteredServicesCache;
import android.content.SyncAdapterType;
import android.content.SyncAdaptersCache;
import android.content.pm.RegisteredServicesCache.ServiceInfo;
+import android.os.Bundle;
import android.os.SystemClock;
import android.text.format.DateUtils;
import android.util.Log;
@@ -60,25 +59,51 @@ public class SyncQueue {
public void addPendingOperations(int userId) {
for (SyncStorageEngine.PendingOperation op : mSyncStorageEngine.getPendingOperations()) {
- if (op.userId != userId) continue;
-
- final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(
- op.account, op.userId, op.authority);
- final ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(
- SyncAdapterType.newKey(op.authority, op.account.type), op.userId);
- if (syncAdapterInfo == null) {
- Log.w(TAG, "Missing sync adapter info for authority " + op.authority + ", userId "
- + op.userId);
- continue;
+ final SyncStorageEngine.EndPoint info = op.target;
+ if (info.userId != userId) continue;
+
+ final Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(info);
+ SyncOperation operationToAdd;
+ if (info.target_provider) {
+ final ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(info.provider, info.account.type), info.userId);
+ if (syncAdapterInfo == null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Missing sync adapter info for authority " + op.target);
+ }
+ continue;
+ }
+ operationToAdd = new SyncOperation(
+ info.account, info.userId, op.reason, op.syncSource, info.provider,
+ op.extras,
+ 0 /* delay */,
+ 0 /* flex */,
+ backoff != null ? backoff.first : 0,
+ mSyncStorageEngine.getDelayUntilTime(info),
+ syncAdapterInfo.type.allowParallelSyncs());
+ operationToAdd.expedited = op.expedited;
+ operationToAdd.pendingOperation = op;
+ add(operationToAdd, op);
+ } else if (info.target_service) {
+ try {
+ mPackageManager.getServiceInfo(info.service, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.w(TAG, "Missing sync service for authority " + op.target);
+ }
+ continue;
+ }
+ operationToAdd = new SyncOperation(
+ info.service, info.userId, op.reason, op.syncSource,
+ op.extras,
+ 0 /* delay */,
+ 0 /* flex */,
+ backoff != null ? backoff.first : 0,
+ mSyncStorageEngine.getDelayUntilTime(info));
+ operationToAdd.expedited = op.expedited;
+ operationToAdd.pendingOperation = op;
+ add(operationToAdd, op);
}
- SyncOperation syncOperation = new SyncOperation(
- op.account, op.userId, op.reason, op.syncSource, op.authority, op.extras,
- 0 /* delay */, 0 /* flex */, backoff != null ? backoff.first : 0,
- mSyncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
- syncAdapterInfo.type.allowParallelSyncs());
- syncOperation.expedited = op.expedited;
- syncOperation.pendingOperation = op;
- add(syncOperation, op);
}
}
@@ -119,12 +144,8 @@ public class SyncQueue {
operation.pendingOperation = pop;
// Don't update the PendingOp if one already exists. This really is just a placeholder,
// no actual scheduling info is placed here.
- // TODO: Change this to support service components.
if (operation.pendingOperation == null) {
- pop = new SyncStorageEngine.PendingOperation(
- operation.account, operation.userId, operation.reason, operation.syncSource,
- operation.authority, operation.extras, operation.expedited);
- pop = mSyncStorageEngine.insertIntoPending(pop);
+ pop = mSyncStorageEngine.insertIntoPending(operation);
if (pop == null) {
throw new IllegalStateException("error adding pending sync operation "
+ operation);
@@ -136,17 +157,16 @@ public class SyncQueue {
return true;
}
- public void removeUser(int userId) {
+ public void removeUserLocked(int userId) {
ArrayList<SyncOperation> opsToRemove = new ArrayList<SyncOperation>();
for (SyncOperation op : mOperationsMap.values()) {
- if (op.userId == userId) {
+ if (op.target.userId == userId) {
opsToRemove.add(op);
}
}
-
- for (SyncOperation op : opsToRemove) {
- remove(op);
- }
+ for (SyncOperation op : opsToRemove) {
+ remove(op);
+ }
}
/**
@@ -154,8 +174,15 @@ public class SyncQueue {
* @param operation the operation to remove
*/
public void remove(SyncOperation operation) {
+ boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
SyncOperation operationToRemove = mOperationsMap.remove(operation.key);
+ if (isLoggable) {
+ Log.v(TAG, "Attempting to remove: " + operation.key);
+ }
if (operationToRemove == null) {
+ if (isLoggable) {
+ Log.v(TAG, "Could not find: " + operation.key);
+ }
return;
}
if (!mSyncStorageEngine.deleteFromPending(operationToRemove.pendingOperation)) {
@@ -164,41 +191,58 @@ public class SyncQueue {
}
}
- public void onBackoffChanged(Account account, int userId, String providerName, long backoff) {
- // for each op that matches the account and provider update its
+ /** Reset backoffs for all operations in the queue. */
+ public void clearBackoffs() {
+ for (SyncOperation op : mOperationsMap.values()) {
+ op.backoff = 0L;
+ op.updateEffectiveRunTime();
+ }
+ }
+
+ public void onBackoffChanged(SyncStorageEngine.EndPoint target, long backoff) {
+ // For each op that matches the target of the changed op, update its
// backoff and effectiveStartTime
for (SyncOperation op : mOperationsMap.values()) {
- if (op.account.equals(account) && op.authority.equals(providerName)
- && op.userId == userId) {
+ if (op.target.matchesSpec(target)) {
op.backoff = backoff;
op.updateEffectiveRunTime();
}
}
}
- public void onDelayUntilTimeChanged(Account account, String providerName, long delayUntil) {
- // for each op that matches the account and provider update its
- // delayUntilTime and effectiveStartTime
+ public void onDelayUntilTimeChanged(SyncStorageEngine.EndPoint target, long delayUntil) {
+ // for each op that matches the target info of the provided op, change the delay time.
for (SyncOperation op : mOperationsMap.values()) {
- if (op.account.equals(account) && op.authority.equals(providerName)) {
+ if (op.target.matchesSpec(target)) {
op.delayUntil = delayUntil;
op.updateEffectiveRunTime();
}
}
}
- public void remove(Account account, int userId, String authority) {
+ /**
+ * Remove all of the SyncOperations associated with a given target.
+ *
+ * @param info target object provided here can have null Account/provider. This is the case
+ * where you want to remove all ops associated with a provider (null Account) or all ops
+ * associated with an account (null provider).
+ * @param extras option bundle to include to further specify which operation to remove. If this
+ * bundle contains sync settings flags, they are ignored.
+ */
+ public void remove(final SyncStorageEngine.EndPoint info, Bundle extras) {
Iterator<Map.Entry<String, SyncOperation>> entries = mOperationsMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, SyncOperation> entry = entries.next();
SyncOperation syncOperation = entry.getValue();
- if (account != null && !syncOperation.account.equals(account)) {
- continue;
- }
- if (authority != null && !syncOperation.authority.equals(authority)) {
+ final SyncStorageEngine.EndPoint opInfo = syncOperation.target;
+ if (!opInfo.matchesSpec(info)) {
continue;
}
- if (userId != syncOperation.userId) {
+ if (extras != null
+ && !SyncManager.syncExtrasEquals(
+ syncOperation.extras,
+ extras,
+ false /* no config flags*/)) {
continue;
}
entries.remove();
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index d51c2d7..1d8ca5a 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.ISyncStatusObserver;
import android.content.PeriodicSync;
import android.content.SyncInfo;
+import android.content.SyncRequest;
import android.content.SyncStatusInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
@@ -36,10 +37,12 @@ import android.os.Message;
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.ArrayMap;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
@@ -71,7 +74,6 @@ import java.util.TimeZone;
public class SyncStorageEngine extends Handler {
private static final String TAG = "SyncManager";
- private static final boolean DEBUG = false;
private static final String TAG_FILE = "SyncManagerFile";
private static final String XML_ATTR_NEXT_AUTHORITY_ID = "nextAuthorityId";
@@ -108,10 +110,7 @@ public class SyncStorageEngine extends Handler {
/** Enum value for a local-initiated sync. */
public static final int SOURCE_LOCAL = 1;
- /**
- * Enum value for a poll-based sync (e.g., upon connection to
- * network)
- */
+ /** Enum value for a poll-based sync (e.g., upon connection to network) */
public static final int SOURCE_POLL = 2;
/** Enum value for a user-initiated sync. */
@@ -119,6 +118,9 @@ public class SyncStorageEngine extends Handler {
/** Enum value for a periodic sync. */
public static final int SOURCE_PERIODIC = 4;
+
+ /** Enum value for a sync started for a service. */
+ public static final int SOURCE_SERVICE = 5;
public static final long NOT_IN_BACKOFF_MODE = -1;
@@ -128,7 +130,8 @@ public class SyncStorageEngine extends Handler {
"LOCAL",
"POLL",
"USER",
- "PERIODIC" };
+ "PERIODIC",
+ "SERVICE"};
// The MESG column will contain one of these or one of the Error types.
public static final String MESG_SUCCESS = "success";
@@ -156,41 +159,54 @@ public class SyncStorageEngine extends Handler {
}
public static class PendingOperation {
- final Account account;
- final int userId;
+ final EndPoint target;
final int reason;
final int syncSource;
- final String authority;
final Bundle extras; // note: read-only.
- final ComponentName serviceName;
final boolean expedited;
- int authorityId;
+ final int authorityId;
+ // No longer used.
+ // Keep around for sake up updating from pending.bin to pending.xml
byte[] flatExtras;
- PendingOperation(Account account, int userId, int reason, int source,
- String authority, Bundle extras, boolean expedited) {
- this.account = account;
- this.userId = userId;
+ PendingOperation(AuthorityInfo authority, int reason, int source,
+ Bundle extras, boolean expedited) {
+ this.target = authority.target;
this.syncSource = source;
this.reason = reason;
- this.authority = authority;
this.extras = extras != null ? new Bundle(extras) : extras;
this.expedited = expedited;
- this.authorityId = -1;
- this.serviceName = null;
+ this.authorityId = authority.ident;
}
PendingOperation(PendingOperation other) {
- this.account = other.account;
- this.userId = other.userId;
this.reason = other.reason;
this.syncSource = other.syncSource;
- this.authority = other.authority;
+ this.target = other.target;
this.extras = other.extras;
this.authorityId = other.authorityId;
this.expedited = other.expedited;
- this.serviceName = other.serviceName;
+ }
+
+ /**
+ * Considered equal if they target the same sync adapter (A
+ * {@link android.content.SyncService}
+ * is considered an adapter), for the same userId.
+ * @param other PendingOperation to compare.
+ * @return true if the two pending ops are the same.
+ */
+ public boolean equals(PendingOperation other) {
+ return target.matchesSpec(other.target);
+ }
+
+ public String toString() {
+ return "service=" + target.service
+ + " user=" + target.userId
+ + " auth=" + target
+ + " account=" + target.account
+ + " src=" + syncSource
+ + " extras=" + extras;
}
}
@@ -204,17 +220,96 @@ public class SyncStorageEngine extends Handler {
}
}
- public static class AuthorityInfo {
+ /** Bare bones representation of a sync target. */
+ public static class EndPoint {
+ public final static EndPoint USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL =
+ new EndPoint(null, null, UserHandle.USER_ALL);
final ComponentName service;
final Account account;
final int userId;
- final String authority;
+ final String provider;
+ final boolean target_service;
+ final boolean target_provider;
+
+ public EndPoint(ComponentName service, int userId) {
+ this.service = service;
+ this.userId = userId;
+ this.account = null;
+ this.provider = null;
+ this.target_service = true;
+ this.target_provider = false;
+ }
+
+ public EndPoint(Account account, String provider, int userId) {
+ this.account = account;
+ this.provider = provider;
+ this.userId = userId;
+ this.service = null;
+ this.target_service = false;
+ this.target_provider = true;
+ }
+
+ /**
+ * An Endpoint for a sync matches if it targets the same sync adapter for the same user.
+ *
+ * @param spec the Endpoint to match. If the spec has null fields, they indicate a wildcard
+ * and match any.
+ */
+ public boolean matchesSpec(EndPoint spec) {
+ if (userId != spec.userId
+ && userId != UserHandle.USER_ALL
+ && spec.userId != UserHandle.USER_ALL) {
+ return false;
+ }
+ if (target_service && spec.target_service) {
+ return service.equals(spec.service);
+ } else if (target_provider && spec.target_provider) {
+ boolean accountsMatch;
+ if (spec.account == null) {
+ accountsMatch = true;
+ } else {
+ accountsMatch = account.equals(spec.account);
+ }
+ boolean providersMatch;
+ if (spec.provider == null) {
+ providersMatch = true;
+ } else {
+ providersMatch = provider.equals(spec.provider);
+ }
+ return accountsMatch && providersMatch;
+ }
+ return false;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (target_provider) {
+ sb.append(account == null ? "ALL ACCS" : account.name)
+ .append("/")
+ .append(provider == null ? "ALL PDRS" : provider);
+ } else if (target_service) {
+ sb.append(service.getPackageName() + "/")
+ .append(service.getClassName());
+ } else {
+ sb.append("invalid target");
+ }
+ sb.append(":u" + userId);
+ return sb.toString();
+ }
+ }
+
+ public static class AuthorityInfo {
+ final EndPoint target;
final int ident;
boolean enabled;
int syncable;
+ /** Time at which this sync will run, taking into account backoff. */
long backoffTime;
+ /** Amount of delay due to backoff. */
long backoffDelay;
+ /** Time offset to add to any requests coming to this target. */
long delayUntil;
+
final ArrayList<PeriodicSync> periodicSyncs;
/**
@@ -224,10 +319,7 @@ public class SyncStorageEngine extends Handler {
* @param toCopy AuthorityInfo to be copied.
*/
AuthorityInfo(AuthorityInfo toCopy) {
- account = toCopy.account;
- userId = toCopy.userId;
- authority = toCopy.authority;
- service = toCopy.service;
+ target = toCopy.target;
ident = toCopy.ident;
enabled = toCopy.enabled;
syncable = toCopy.syncable;
@@ -241,56 +333,40 @@ public class SyncStorageEngine extends Handler {
}
}
- /**
- * Create an authority with one periodic sync scheduled with an empty bundle and syncing
- * every day. An empty bundle is considered equal to any other bundle see
- * {@link PeriodicSync.syncExtrasEquals}.
- * @param account Account that this authority syncs.
- * @param userId which user this sync is registered for.
- * @param userId user for which this authority is registered.
- * @param ident id of this authority.
- */
- AuthorityInfo(Account account, int userId, String authority, int ident) {
- this.account = account;
- this.userId = userId;
- this.authority = authority;
- this.service = null;
- this.ident = ident;
- enabled = SYNC_ENABLED_DEFAULT;
- syncable = -1; // default to "unknown"
- backoffTime = -1; // if < 0 then we aren't in backoff mode
- backoffDelay = -1; // if < 0 then we aren't in backoff mode
+ AuthorityInfo(EndPoint info, int id) {
+ target = info;
+ ident = id;
+ enabled = info.target_provider ?
+ SYNC_ENABLED_DEFAULT : true;
+ // Service is active by default,
+ if (info.target_service) {
+ this.syncable = 1;
+ }
periodicSyncs = new ArrayList<PeriodicSync>();
- // Old version adds one periodic sync a day.
- periodicSyncs.add(new PeriodicSync(account, authority,
- new Bundle(),
- DEFAULT_POLL_FREQUENCY_SECONDS,
- calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)));
+ defaultInitialisation();
}
- /**
- * Create an authority with one periodic sync scheduled with an empty bundle and syncing
- * every day using a sync service.
- * @param cname sync service identifier.
- * @param userId user for which this authority is registered.
- * @param ident id of this authority.
- */
- AuthorityInfo(ComponentName cname, int userId, int ident) {
- this.account = null;
- this.userId = userId;
- this.authority = null;
- this.service = cname;
- this.ident = ident;
- // Sync service is always enabled.
- enabled = true;
+ private void defaultInitialisation() {
syncable = -1; // default to "unknown"
backoffTime = -1; // if < 0 then we aren't in backoff mode
backoffDelay = -1; // if < 0 then we aren't in backoff mode
- periodicSyncs = new ArrayList<PeriodicSync>();
- periodicSyncs.add(new PeriodicSync(account, authority,
- new Bundle(),
- DEFAULT_POLL_FREQUENCY_SECONDS,
- calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS)));
+ PeriodicSync defaultSync;
+ // Old version is one sync a day. Empty bundle gets replaced by any addPeriodicSync()
+ // call.
+ if (target.target_provider) {
+ defaultSync =
+ new PeriodicSync(target.account, target.provider,
+ new Bundle(),
+ DEFAULT_POLL_FREQUENCY_SECONDS,
+ calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS));
+ periodicSyncs.add(defaultSync);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return target + ", enabled=" + enabled + ", syncable=" + syncable + ", backoff="
+ + backoffTime + ", delay=" + delayUntil;
}
}
@@ -322,16 +398,9 @@ public class SyncStorageEngine extends Handler {
}
interface OnSyncRequestListener {
- /**
- * Called when a sync is needed on an account(s) due to some change in state.
- * @param account
- * @param userId
- * @param reason
- * @param authority
- * @param extras
- */
- public void onSyncRequest(Account account, int userId, int reason, String authority,
- Bundle extras);
+
+ /** Called when a sync is needed on an account(s) due to some change in state. */
+ public void onSyncRequest(EndPoint info, int reason, Bundle extras);
}
// Primary list of all syncable authorities. Also our global lock.
@@ -356,9 +425,9 @@ public class SyncStorageEngine extends Handler {
private final RemoteCallbackList<ISyncStatusObserver> mChangeListeners
= new RemoteCallbackList<ISyncStatusObserver>();
- /** Reverse mapping for component name -> <userid -> authority id>. */
- private final HashMap<ComponentName, SparseArray<AuthorityInfo>> mServices =
- new HashMap<ComponentName, SparseArray<AuthorityInfo>>();
+ /** Reverse mapping for component name -> <userid -> target id>. */
+ private final ArrayMap<ComponentName, SparseArray<AuthorityInfo>> mServices =
+ new ArrayMap<ComponentName, SparseArray<AuthorityInfo>>();
private int mNextAuthorityId = 0;
@@ -501,7 +570,7 @@ public class SyncStorageEngine extends Handler {
* @return amount of seconds before syncTimeSeconds that the sync can occur.
* I.e.
* earliest_sync_time = syncTimeSeconds - calculateDefaultFlexTime(syncTimeSeconds)
- * The flex time is capped at a percentage of the {@link DEFAULT_POLL_FREQUENCY_SECONDS}.
+ * The flex time is capped at a percentage of the {@link #DEFAULT_POLL_FREQUENCY_SECONDS}.
*/
public static long calculateDefaultFlexTime(long syncTimeSeconds) {
if (syncTimeSeconds < DEFAULT_MIN_FLEX_ALLOWED_SECS) {
@@ -535,7 +604,7 @@ public class SyncStorageEngine extends Handler {
mChangeListeners.finishBroadcast();
}
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "reportChange " + which + " to: " + reports);
}
@@ -555,7 +624,8 @@ public class SyncStorageEngine extends Handler {
public boolean getSyncAutomatically(Account account, int userId, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
+ AuthorityInfo authority = getAuthorityLocked(
+ new EndPoint(account, providerName, userId),
"getSyncAutomatically");
return authority != null && authority.enabled;
}
@@ -563,10 +633,9 @@ public class SyncStorageEngine extends Handler {
int i = mAuthorities.size();
while (i > 0) {
i--;
- AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.authority.equals(providerName)
- && authority.userId == userId
- && authority.enabled) {
+ AuthorityInfo authorityInfo = mAuthorities.valueAt(i);
+ if (authorityInfo.target.matchesSpec(new EndPoint(account, providerName, userId))
+ && authorityInfo.enabled) {
return true;
}
}
@@ -576,15 +645,18 @@ public class SyncStorageEngine extends Handler {
public void setSyncAutomatically(Account account, int userId, String providerName,
boolean sync) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "setSyncAutomatically: " + /* account + */" provider " + providerName
+ ", user " + userId + " -> " + sync);
}
synchronized (mAuthorities) {
- AuthorityInfo authority = getOrCreateAuthorityLocked(account, userId, providerName, -1,
- false);
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(
+ new EndPoint(account, providerName, userId),
+ -1 /* ident */,
+ false);
if (authority.enabled == sync) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "setSyncAutomatically: already set to " + sync + ", doing nothing");
}
return;
@@ -603,8 +675,9 @@ public class SyncStorageEngine extends Handler {
public int getIsSyncable(Account account, int userId, String providerName) {
synchronized (mAuthorities) {
if (account != null) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
- "getIsSyncable");
+ AuthorityInfo authority = getAuthorityLocked(
+ new EndPoint(account, providerName, userId),
+ "get authority syncable");
if (authority == null) {
return -1;
}
@@ -614,9 +687,10 @@ public class SyncStorageEngine extends Handler {
int i = mAuthorities.size();
while (i > 0) {
i--;
- AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.authority.equals(providerName)) {
- return authority.syncable;
+ AuthorityInfo authorityInfo = mAuthorities.valueAt(i);
+ if (authorityInfo.target != null
+ && authorityInfo.target.provider.equals(providerName)) {
+ return authorityInfo.syncable;
}
}
return -1;
@@ -624,119 +698,178 @@ public class SyncStorageEngine extends Handler {
}
public void setIsSyncable(Account account, int userId, String providerName, int syncable) {
- if (syncable > 1) {
- syncable = 1;
- } else if (syncable < -1) {
- syncable = -1;
- }
- if (DEBUG) {
- Log.d(TAG, "setIsSyncable: " + account + ", provider " + providerName
- + ", user " + userId + " -> " + syncable);
+ setSyncableStateForEndPoint(new EndPoint(account, providerName, userId), syncable);
+ }
+
+ public boolean getIsTargetServiceActive(ComponentName cname, int userId) {
+ synchronized (mAuthorities) {
+ if (cname != null) {
+ AuthorityInfo authority = getAuthorityLocked(
+ new EndPoint(cname, userId),
+ "get service active");
+ if (authority == null) {
+ return false;
+ }
+ return (authority.syncable == 1);
+ }
+ return false;
}
+ }
+
+ public void setIsTargetServiceActive(ComponentName cname, int userId, boolean active) {
+ setSyncableStateForEndPoint(new EndPoint(cname, userId), active ? 1 : 0);
+ }
+
+ /**
+ * An enabled sync service and a syncable provider's adapter both get resolved to the same
+ * persisted variable - namely the "syncable" attribute for an AuthorityInfo in accounts.xml.
+ * @param target target to set value for.
+ * @param syncable 0 indicates unsyncable, <0 unknown, >0 is active/syncable.
+ */
+ private void setSyncableStateForEndPoint(EndPoint target, int syncable) {
+ AuthorityInfo aInfo;
synchronized (mAuthorities) {
- AuthorityInfo authority =
- getOrCreateAuthorityLocked(account, userId, providerName, -1, false);
- if (authority.syncable == syncable) {
- if (DEBUG) {
+ aInfo = getOrCreateAuthorityLocked(target, -1, false);
+ if (syncable > 1) {
+ syncable = 1;
+ } else if (syncable < -1) {
+ syncable = -1;
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.d(TAG, "setIsSyncable: " + aInfo.toString() + " -> " + syncable);
+ }
+ if (aInfo.syncable == syncable) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "setIsSyncable: already set to " + syncable + ", doing nothing");
}
return;
}
- authority.syncable = syncable;
+ aInfo.syncable = syncable;
writeAccountInfoLocked();
}
-
if (syncable > 0) {
- requestSync(account, userId, SyncOperation.REASON_IS_SYNCABLE, providerName,
- new Bundle());
+ requestSync(aInfo, SyncOperation.REASON_IS_SYNCABLE, new Bundle());
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public Pair<Long, Long> getBackoff(Account account, int userId, String providerName) {
+ public Pair<Long, Long> getBackoff(EndPoint info) {
synchronized (mAuthorities) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
- "getBackoff");
- if (authority == null || authority.backoffTime < 0) {
- return null;
+ AuthorityInfo authority = getAuthorityLocked(info, "getBackoff");
+ if (authority != null) {
+ return Pair.create(authority.backoffTime, authority.backoffDelay);
}
- return Pair.create(authority.backoffTime, authority.backoffDelay);
+ return null;
}
}
- public void setBackoff(Account account, int userId, String providerName,
- long nextSyncTime, long nextDelay) {
- if (DEBUG) {
- Log.v(TAG, "setBackoff: " + account + ", provider " + providerName
- + ", user " + userId
+ /**
+ * Update the backoff for the given endpoint. The endpoint may be for a provider/account and
+ * the account or provider info be null, which signifies all accounts or providers.
+ */
+ public void setBackoff(EndPoint info, long nextSyncTime, long nextDelay) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "setBackoff: " + info
+ " -> nextSyncTime " + nextSyncTime + ", nextDelay " + nextDelay);
}
- boolean changed = false;
+ boolean changed;
synchronized (mAuthorities) {
- if (account == null || providerName == null) {
- for (AccountInfo accountInfo : mAccounts.values()) {
- if (account != null && !account.equals(accountInfo.accountAndUser.account)
- && userId != accountInfo.accountAndUser.userId) {
- continue;
- }
- for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
- if (providerName != null
- && !providerName.equals(authorityInfo.authority)) {
- continue;
- }
- if (authorityInfo.backoffTime != nextSyncTime
- || authorityInfo.backoffDelay != nextDelay) {
- authorityInfo.backoffTime = nextSyncTime;
- authorityInfo.backoffDelay = nextDelay;
- changed = true;
- }
- }
- }
+ if (info.target_provider
+ && (info.account == null || info.provider == null)) {
+ // Do more work for a provider sync if the provided info has specified all
+ // accounts/providers.
+ changed = setBackoffLocked(
+ info.account /* may be null */,
+ info.userId,
+ info.provider /* may be null */,
+ nextSyncTime, nextDelay);
} else {
- AuthorityInfo authority =
- getOrCreateAuthorityLocked(account, userId, providerName, -1 /* ident */,
- true);
- if (authority.backoffTime == nextSyncTime && authority.backoffDelay == nextDelay) {
- return;
+ AuthorityInfo authorityInfo =
+ getOrCreateAuthorityLocked(info, -1 /* ident */, true);
+ if (authorityInfo.backoffTime == nextSyncTime
+ && authorityInfo.backoffDelay == nextDelay) {
+ changed = false;
+ } else {
+ authorityInfo.backoffTime = nextSyncTime;
+ authorityInfo.backoffDelay = nextDelay;
+ changed = true;
}
- authority.backoffTime = nextSyncTime;
- authority.backoffDelay = nextDelay;
- changed = true;
}
}
-
if (changed) {
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
}
/**
- * Callers of this function need to hold a lock for syncQueue object passed in. Bear in mind
- * this function grabs the lock for {@link #mAuthorities}
- * @param syncQueue queue containing pending sync operations.
+ * Either set backoff for a specific authority, or set backoff for all the
+ * accounts on a specific adapter/all adapters.
+ *
+ * @param account account for which to set backoff. Null to specify all accounts.
+ * @param userId id of the user making this request.
+ * @param providerName provider for which to set backoff. Null to specify all providers.
+ * @return true if a change occured.
*/
- public void clearAllBackoffsLocked(SyncQueue syncQueue) {
+ private boolean setBackoffLocked(Account account, int userId, String providerName,
+ long nextSyncTime, long nextDelay) {
+ boolean changed = false;
+ for (AccountInfo accountInfo : mAccounts.values()) {
+ if (account != null && !account.equals(accountInfo.accountAndUser.account)
+ && userId != accountInfo.accountAndUser.userId) {
+ continue;
+ }
+ for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
+ if (providerName != null
+ && !providerName.equals(authorityInfo.target.provider)) {
+ continue;
+ }
+ if (authorityInfo.backoffTime != nextSyncTime
+ || authorityInfo.backoffDelay != nextDelay) {
+ authorityInfo.backoffTime = nextSyncTime;
+ authorityInfo.backoffDelay = nextDelay;
+ changed = true;
+ }
+ }
+ }
+ return changed;
+ }
+
+ public void clearAllBackoffs(SyncQueue syncQueue) {
boolean changed = false;
synchronized (mAuthorities) {
- for (AccountInfo accountInfo : mAccounts.values()) {
- for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
- if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
- || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
- if (DEBUG) {
- Log.v(TAG, "clearAllBackoffs:"
- + " authority:" + authorityInfo.authority
- + " account:" + accountInfo.accountAndUser.account.name
- + " user:" + accountInfo.accountAndUser.userId
- + " backoffTime was: " + authorityInfo.backoffTime
- + " backoffDelay was: " + authorityInfo.backoffDelay);
+ synchronized (syncQueue) {
+ // Clear backoff for all sync adapters.
+ for (AccountInfo accountInfo : mAccounts.values()) {
+ for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
+ if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
+ || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "clearAllBackoffs:"
+ + " authority:" + authorityInfo.target
+ + " account:" + accountInfo.accountAndUser.account.name
+ + " user:" + accountInfo.accountAndUser.userId
+ + " backoffTime was: " + authorityInfo.backoffTime
+ + " backoffDelay was: " + authorityInfo.backoffDelay);
+ }
+ authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
+ authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
+ changed = true;
}
- authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
- authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
- syncQueue.onBackoffChanged(accountInfo.accountAndUser.account,
- accountInfo.accountAndUser.userId, authorityInfo.authority, 0);
- changed = true;
}
}
+ // Clear backoff for all sync services.
+ for (ComponentName service : mServices.keySet()) {
+ SparseArray<AuthorityInfo> aInfos = mServices.get(service);
+ for (int i = 0; i < aInfos.size(); i++) {
+ AuthorityInfo authorityInfo = aInfos.valueAt(i);
+ if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
+ || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
+ authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
+ authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
+ }
+ }
+ }
+ syncQueue.clearBackoffs();
}
}
@@ -745,142 +878,157 @@ public class SyncStorageEngine extends Handler {
}
}
- public void setDelayUntilTime(Account account, int userId, String providerName,
- long delayUntil) {
- if (DEBUG) {
- Log.v(TAG, "setDelayUntil: " + account + ", provider " + providerName
- + ", user " + userId + " -> delayUntil " + delayUntil);
- }
+ public long getDelayUntilTime(EndPoint info) {
synchronized (mAuthorities) {
- AuthorityInfo authority = getOrCreateAuthorityLocked(
- account, userId, providerName, -1 /* ident */, true);
- if (authority.delayUntil == delayUntil) {
- return;
+ AuthorityInfo authority = getAuthorityLocked(info, "getDelayUntil");
+ if (authority == null) {
+ return 0;
}
- authority.delayUntil = delayUntil;
+ return authority.delayUntil;
}
-
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public long getDelayUntilTime(Account account, int userId, String providerName) {
+ public void setDelayUntilTime(EndPoint info, long delayUntil) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "setDelayUntil: " + info
+ + " -> delayUntil " + delayUntil);
+ }
synchronized (mAuthorities) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
- "getDelayUntil");
- if (authority == null) {
- return 0;
+ AuthorityInfo authority = getOrCreateAuthorityLocked(info, -1, true);
+ if (authority.delayUntil == delayUntil) {
+ return;
}
- return authority.delayUntil;
+ authority.delayUntil = delayUntil;
}
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- private void updateOrRemovePeriodicSync(PeriodicSync toUpdate, int userId, boolean add) {
- if (DEBUG) {
- Log.v(TAG, "addOrRemovePeriodicSync: " + toUpdate.account + ", user " + userId
- + ", provider " + toUpdate.authority
- + " -> period " + toUpdate.period + ", extras " + toUpdate.extras);
+ public void updateOrAddPeriodicSync(EndPoint info, long period, long flextime, Bundle extras) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "addPeriodicSync: " + info
+ + " -> period " + period + ", flex " + flextime + ", extras "
+ + extras.toString());
}
synchronized (mAuthorities) {
- if (toUpdate.period <= 0 && add) {
- Log.e(TAG, "period < 0, should never happen in updateOrRemovePeriodicSync: add-"
- + add);
+ if (period <= 0) {
+ Log.e(TAG, "period < 0, should never happen in updateOrAddPeriodicSync");
}
- if (toUpdate.extras == null) {
- Log.e(TAG, "null extras, should never happen in updateOrRemovePeriodicSync: add-"
- + add);
+ if (extras == null) {
+ Log.e(TAG, "null extras, should never happen in updateOrAddPeriodicSync:");
}
try {
+ PeriodicSync toUpdate;
+ if (info.target_provider) {
+ toUpdate = new PeriodicSync(info.account,
+ info.provider,
+ extras,
+ period,
+ flextime);
+ } else {
+ toUpdate = new PeriodicSync(info.service,
+ extras,
+ period,
+ flextime);
+ }
AuthorityInfo authority =
- getOrCreateAuthorityLocked(toUpdate.account, userId, toUpdate.authority,
- -1, false);
- if (add) {
- // add this periodic sync if an equivalent periodic doesn't already exist.
- boolean alreadyPresent = false;
- for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
- PeriodicSync syncInfo = authority.periodicSyncs.get(i);
- if (PeriodicSync.syncExtrasEquals(
- toUpdate.extras,
- syncInfo.extras)) {
- if (toUpdate.period == syncInfo.period &&
- toUpdate.flexTime == syncInfo.flexTime) {
- // Absolutely the same.
- return;
- }
- authority.periodicSyncs.set(i, new PeriodicSync(toUpdate));
- alreadyPresent = true;
- break;
+ getOrCreateAuthorityLocked(info, -1, false);
+ // add this periodic sync if an equivalent periodic doesn't already exist.
+ boolean alreadyPresent = false;
+ for (int i = 0, N = authority.periodicSyncs.size(); i < N; i++) {
+ PeriodicSync syncInfo = authority.periodicSyncs.get(i);
+ if (SyncManager.syncExtrasEquals(syncInfo.extras,
+ extras,
+ true /* includeSyncSettings*/)) {
+ if (period == syncInfo.period &&
+ flextime == syncInfo.flexTime) {
+ // Absolutely the same.
+ return;
}
+ authority.periodicSyncs.set(i, toUpdate);
+ alreadyPresent = true;
+ break;
}
- // If we added an entry to the periodicSyncs array also add an entry to
- // the periodic syncs status to correspond to it.
- if (!alreadyPresent) {
- authority.periodicSyncs.add(new PeriodicSync(toUpdate));
- SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
- status.setPeriodicSyncTime(authority.periodicSyncs.size() - 1, 0L);
- }
- } else {
- // Remove any periodic syncs that match the authority and extras.
- SyncStatusInfo status = mSyncStatus.get(authority.ident);
- boolean changed = false;
- Iterator<PeriodicSync> iterator = authority.periodicSyncs.iterator();
- int i = 0;
- while (iterator.hasNext()) {
- PeriodicSync syncInfo = iterator.next();
- if (PeriodicSync.syncExtrasEquals(syncInfo.extras, toUpdate.extras)) {
- iterator.remove();
- changed = true;
- // If we removed an entry from the periodicSyncs array also
- // remove the corresponding entry from the status
- if (status != null) {
- status.removePeriodicSyncTime(i);
- } else {
- Log.e(TAG, "Tried removing sync status on remove periodic sync but"
- + "did not find it.");
- }
+ }
+ // If we added an entry to the periodicSyncs array also add an entry to
+ // the periodic syncs status to correspond to it.
+ if (!alreadyPresent) {
+ authority.periodicSyncs.add(toUpdate);
+ SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
+ // A new periodic sync is initialised as already having been run.
+ status.setPeriodicSyncTime(
+ authority.periodicSyncs.size() - 1,
+ System.currentTimeMillis());
+ }
+ } finally {
+ writeAccountInfoLocked();
+ writeStatusLocked();
+ }
+ }
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+ }
+
+ public void removePeriodicSync(EndPoint info, Bundle extras) {
+ synchronized(mAuthorities) {
+ try {
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(info, -1, false);
+ // Remove any periodic syncs that match the target and extras.
+ SyncStatusInfo status = mSyncStatus.get(authority.ident);
+ boolean changed = false;
+ Iterator<PeriodicSync> iterator = authority.periodicSyncs.iterator();
+ int i = 0;
+ while (iterator.hasNext()) {
+ PeriodicSync syncInfo = iterator.next();
+ if (SyncManager.syncExtrasEquals(syncInfo.extras,
+ extras,
+ true /* includeSyncSettings */)) {
+ iterator.remove();
+ changed = true;
+ // If we removed an entry from the periodicSyncs array also
+ // remove the corresponding entry from the status
+ if (status != null) {
+ status.removePeriodicSyncTime(i);
} else {
- i++;
+ Log.e(TAG, "Tried removing sync status on remove periodic sync but"
+ + " did not find it.");
}
+ } else {
+ i++;
}
- if (!changed) {
- return;
- }
+ }
+ if (!changed) {
+ return;
}
} finally {
writeAccountInfoLocked();
writeStatusLocked();
}
}
-
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
}
- public void addPeriodicSync(PeriodicSync toAdd, int userId) {
- updateOrRemovePeriodicSync(toAdd, userId, true /* add */);
- }
-
- public void removePeriodicSync(PeriodicSync toRemove, int userId) {
- updateOrRemovePeriodicSync(toRemove, userId, false /* remove */);
- }
-
- public List<PeriodicSync> getPeriodicSyncs(Account account, int userId, String providerName) {
- ArrayList<PeriodicSync> syncs = new ArrayList<PeriodicSync>();
+ /**
+ * @return list of periodic syncs for a target. Never null. If no such syncs exist, returns an
+ * empty list.
+ */
+ public List<PeriodicSync> getPeriodicSyncs(EndPoint info) {
synchronized (mAuthorities) {
- AuthorityInfo authority = getAuthorityLocked(account, userId, providerName,
- "getPeriodicSyncs");
- if (authority != null) {
- for (PeriodicSync item : authority.periodicSyncs) {
+ AuthorityInfo authorityInfo = getAuthorityLocked(info, "getPeriodicSyncs");
+ ArrayList<PeriodicSync> syncs = new ArrayList<PeriodicSync>();
+ if (authorityInfo != null) {
+ for (PeriodicSync item : authorityInfo.periodicSyncs) {
// Copy and send out. Necessary for thread-safety although it's parceled.
syncs.add(new PeriodicSync(item));
}
}
+ return syncs;
}
- return syncs;
}
public void setMasterSyncAutomatically(boolean flag, int userId) {
synchronized (mAuthorities) {
Boolean auto = mMasterSyncAutomatically.get(userId);
- if (auto != null && (boolean) auto == flag) {
+ if (auto != null && auto.equals(flag)) {
return;
}
mMasterSyncAutomatically.put(userId, flag);
@@ -901,12 +1049,6 @@ public class SyncStorageEngine extends Handler {
}
}
- public void removeAuthority(Account account, int userId, String authority) {
- synchronized (mAuthorities) {
- removeAuthorityLocked(account, userId, authority, true /* doWrite */);
- }
- }
-
public AuthorityInfo getAuthority(int authorityId) {
synchronized (mAuthorities) {
return mAuthorities.get(authorityId);
@@ -914,72 +1056,60 @@ public class SyncStorageEngine extends Handler {
}
/**
- * Returns true if there is currently a sync operation for the given
- * account or authority actively being processed.
+ * Returns true if there is currently a sync operation being actively processed for the given
+ * target.
*/
- public boolean isSyncActive(Account account, int userId, String authority) {
+ public boolean isSyncActive(EndPoint info) {
synchronized (mAuthorities) {
- for (SyncInfo syncInfo : getCurrentSyncs(userId)) {
+ for (SyncInfo syncInfo : getCurrentSyncs(info.userId)) {
AuthorityInfo ainfo = getAuthority(syncInfo.authorityId);
- if (ainfo != null && ainfo.account.equals(account)
- && ainfo.authority.equals(authority)
- && ainfo.userId == userId) {
+ if (ainfo != null && ainfo.target.matchesSpec(info)) {
return true;
}
}
}
-
return false;
}
- public PendingOperation insertIntoPending(PendingOperation op) {
+ public PendingOperation insertIntoPending(SyncOperation op) {
+ PendingOperation pop;
synchronized (mAuthorities) {
- if (DEBUG) {
- Log.v(TAG, "insertIntoPending: account=" + op.account
- + " user=" + op.userId
- + " auth=" + op.authority
- + " src=" + op.syncSource
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "insertIntoPending: authority=" + op.target
+ " extras=" + op.extras);
}
-
- AuthorityInfo authority = getOrCreateAuthorityLocked(op.account, op.userId,
- op.authority,
- -1 /* desired identifier */,
- true /* write accounts to storage */);
+ final EndPoint info = op.target;
+ AuthorityInfo authority =
+ getOrCreateAuthorityLocked(info,
+ -1 /* desired identifier */,
+ true /* write accounts to storage */);
if (authority == null) {
return null;
}
- op = new PendingOperation(op);
- op.authorityId = authority.ident;
- mPendingOperations.add(op);
- appendPendingOperationLocked(op);
+ pop = new PendingOperation(authority, op.reason, op.syncSource, op.extras,
+ op.expedited);
+ mPendingOperations.add(pop);
+ appendPendingOperationLocked(pop);
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = true;
}
-
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
- return op;
+ return pop;
}
/**
* Remove from list of pending operations. If successful, search through list for matching
- * authorities. If there are no more pending syncs for the same authority/account/userid,
- * update the SyncStatusInfo for that authority(authority here is the internal representation
- * of a 'sync operation'.
- * @param op
- * @return
+ * authorities. If there are no more pending syncs for the same target,
+ * update the SyncStatusInfo for that target.
+ * @param op Pending op to delete.
*/
public boolean deleteFromPending(PendingOperation op) {
boolean res = false;
synchronized (mAuthorities) {
- if (DEBUG) {
- Log.v(TAG, "deleteFromPending: account=" + op.account
- + " user=" + op.userId
- + " auth=" + op.authority
- + " src=" + op.syncSource
- + " extras=" + op.extras);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "deleteFromPending: account=" + op.toString());
}
if (mPendingOperations.remove(op)) {
if (mPendingOperations.size() == 0
@@ -989,30 +1119,27 @@ public class SyncStorageEngine extends Handler {
} else {
mNumPendingFinished++;
}
-
- AuthorityInfo authority = getAuthorityLocked(op.account, op.userId, op.authority,
- "deleteFromPending");
+ AuthorityInfo authority = getAuthorityLocked(op.target, "deleteFromPending");
if (authority != null) {
- if (DEBUG) Log.v(TAG, "removing - " + authority.toString());
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "removing - " + authority.toString());
+ }
final int N = mPendingOperations.size();
boolean morePending = false;
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
PendingOperation cur = mPendingOperations.get(i);
- if (cur.account.equals(op.account)
- && cur.authority.equals(op.authority)
- && cur.userId == op.userId) {
+ if (cur.equals(op)) {
morePending = true;
break;
}
}
if (!morePending) {
- if (DEBUG) Log.v(TAG, "no more pending!");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "no more pending!");
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = false;
}
}
-
res = true;
}
}
@@ -1047,7 +1174,9 @@ public class SyncStorageEngine extends Handler {
*/
public void doDatabaseCleanup(Account[] accounts, int userId) {
synchronized (mAuthorities) {
- if (DEBUG) Log.v(TAG, "Updating for new accounts...");
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Updating for new accounts...");
+ }
SparseArray<AuthorityInfo> removing = new SparseArray<AuthorityInfo>();
Iterator<AccountInfo> accIt = mAccounts.values().iterator();
while (accIt.hasNext()) {
@@ -1055,7 +1184,7 @@ public class SyncStorageEngine extends Handler {
if (!ArrayUtils.contains(accounts, acc.accountAndUser.account)
&& acc.accountAndUser.userId == userId) {
// This account no longer exists...
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Account removed: " + acc.accountAndUser);
}
for (AuthorityInfo auth : acc.authorities.values()) {
@@ -1102,25 +1231,25 @@ public class SyncStorageEngine extends Handler {
public SyncInfo addActiveSync(SyncManager.ActiveSyncContext activeSyncContext) {
final SyncInfo syncInfo;
synchronized (mAuthorities) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setActiveSync: account="
- + activeSyncContext.mSyncOperation.account
- + " auth=" + activeSyncContext.mSyncOperation.authority
+ + " auth=" + activeSyncContext.mSyncOperation.target
+ " src=" + activeSyncContext.mSyncOperation.syncSource
+ " extras=" + activeSyncContext.mSyncOperation.extras);
}
- AuthorityInfo authority = getOrCreateAuthorityLocked(
- activeSyncContext.mSyncOperation.account,
- activeSyncContext.mSyncOperation.userId,
- activeSyncContext.mSyncOperation.authority,
- -1 /* assign a new identifier if creating a new authority */,
+ final EndPoint info = activeSyncContext.mSyncOperation.target;
+ AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(
+ info,
+ -1 /* assign a new identifier if creating a new target */,
true /* write to storage if this results in a change */);
- syncInfo = new SyncInfo(authority.ident,
- authority.account, authority.authority,
+ syncInfo = new SyncInfo(
+ authorityInfo.ident,
+ authorityInfo.target.account,
+ authorityInfo.target.provider,
+ authorityInfo.target.service,
activeSyncContext.mStartTime);
- getCurrentSyncs(authority.userId).add(syncInfo);
+ getCurrentSyncs(authorityInfo.target.userId).add(syncInfo);
}
-
reportActiveChange();
return syncInfo;
}
@@ -1130,10 +1259,11 @@ public class SyncStorageEngine extends Handler {
*/
public void removeActiveSync(SyncInfo syncInfo, int userId) {
synchronized (mAuthorities) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeActiveSync: account=" + syncInfo.account
+ " user=" + userId
- + " auth=" + syncInfo.authority);
+ + " auth=" + syncInfo.authority
+ + " service=" + syncInfo.service);
}
getCurrentSyncs(userId).remove(syncInfo);
}
@@ -1149,37 +1279,34 @@ public class SyncStorageEngine extends Handler {
}
/**
- * Note that sync has started for the given account and authority.
+ * Note that sync has started for the given operation.
*/
- public long insertStartSyncEvent(Account accountName, int userId, int reason,
- String authorityName, long now, int source, boolean initialization, Bundle extras) {
+ public long insertStartSyncEvent(SyncOperation op, long now) {
long id;
synchronized (mAuthorities) {
- if (DEBUG) {
- Log.v(TAG, "insertStartSyncEvent: account=" + accountName + "user=" + userId
- + " auth=" + authorityName + " source=" + source);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "insertStartSyncEvent: " + op);
}
- AuthorityInfo authority = getAuthorityLocked(accountName, userId, authorityName,
- "insertStartSyncEvent");
+ AuthorityInfo authority = getAuthorityLocked(op.target, "insertStartSyncEvent");
if (authority == null) {
return -1;
}
SyncHistoryItem item = new SyncHistoryItem();
- item.initialization = initialization;
+ item.initialization = op.isInitialization();
item.authorityId = authority.ident;
item.historyId = mNextHistoryId++;
if (mNextHistoryId < 0) mNextHistoryId = 0;
item.eventTime = now;
- item.source = source;
- item.reason = reason;
- item.extras = extras;
+ item.source = op.syncSource;
+ item.reason = op.reason;
+ item.extras = op.extras;
item.event = EVENT_START;
mSyncHistory.add(0, item);
while (mSyncHistory.size() > MAX_HISTORY) {
mSyncHistory.remove(mSyncHistory.size()-1);
}
id = item.historyId;
- if (DEBUG) Log.v(TAG, "returning historyId " + id);
+ if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "returning historyId " + id);
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS);
@@ -1189,7 +1316,7 @@ public class SyncStorageEngine extends Handler {
public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage,
long downstreamActivity, long upstreamActivity) {
synchronized (mAuthorities) {
- if (DEBUG) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "stopSyncEvent: historyId=" + historyId);
}
SyncHistoryItem item = null;
@@ -1326,13 +1453,12 @@ public class SyncStorageEngine extends Handler {
}
/**
- * Return a copy of the specified authority with the corresponding sync status
+ * Return a copy of the specified target with the corresponding sync status
*/
- public Pair<AuthorityInfo, SyncStatusInfo> getCopyOfAuthorityWithSyncStatus(
- Account account, int userId, String authority) {
+ public Pair<AuthorityInfo, SyncStatusInfo> getCopyOfAuthorityWithSyncStatus(EndPoint info) {
synchronized (mAuthorities) {
- AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(account, userId, authority,
- -1 /* assign a new identifier if creating a new authority */,
+ AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(info,
+ -1 /* assign a new identifier if creating a new target */,
true /* write to storage if this results in a change */);
return createCopyPairOfAuthorityWithSyncStatusLocked(authorityInfo);
}
@@ -1353,26 +1479,24 @@ public class SyncStorageEngine extends Handler {
}
/**
- * Returns the status that matches the authority and account.
+ * Returns the status that matches the target.
*
- * @param account the account we want to check
- * @param authority the authority whose row should be selected
- * @return the SyncStatusInfo for the authority
+ * @param info the endpoint target we are querying status info for.
+ * @return the SyncStatusInfo for the endpoint.
*/
- public SyncStatusInfo getStatusByAccountAndAuthority(Account account, int userId,
- String authority) {
- if (account == null || authority == null) {
+ public SyncStatusInfo getStatusByAuthority(EndPoint info) {
+ if (info.target_provider && (info.account == null || info.provider == null)) {
throw new IllegalArgumentException();
+ } else if (info.target_service && info.service == null) {
+ throw new IllegalArgumentException();
}
synchronized (mAuthorities) {
final int N = mSyncStatus.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
SyncStatusInfo cur = mSyncStatus.valueAt(i);
AuthorityInfo ainfo = mAuthorities.get(cur.authorityId);
-
- if (ainfo != null && ainfo.authority.equals(authority)
- && ainfo.userId == userId
- && account.equals(ainfo.account)) {
+ if (ainfo != null
+ && ainfo.target.matchesSpec(info)) {
return cur;
}
}
@@ -1380,25 +1504,20 @@ public class SyncStorageEngine extends Handler {
}
}
- /**
- * Return true if the pending status is true of any matching authorities.
- */
- public boolean isSyncPending(Account account, int userId, String authority) {
+ /** Return true if the pending status is true of any matching authorities. */
+ public boolean isSyncPending(EndPoint info) {
synchronized (mAuthorities) {
final int N = mSyncStatus.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
SyncStatusInfo cur = mSyncStatus.valueAt(i);
AuthorityInfo ainfo = mAuthorities.get(cur.authorityId);
if (ainfo == null) {
continue;
}
- if (userId != ainfo.userId) {
+ if (!ainfo.target.matchesSpec(info)) {
continue;
}
- if (account != null && !ainfo.account.equals(account)) {
- continue;
- }
- if (ainfo.authority.equals(authority) && cur.pending) {
+ if (cur.pending) {
return true;
}
}
@@ -1454,128 +1573,133 @@ public class SyncStorageEngine extends Handler {
}
/**
- * Retrieve an authority, returning null if one does not exist.
+ * Retrieve a target's full info, returning null if one does not exist.
*
- * @param accountName The name of the account for the authority.
- * @param authorityName The name of the authority itself.
+ * @param info info of the target to look up.
* @param tag If non-null, this will be used in a log message if the
- * requested authority does not exist.
+ * requested target does not exist.
*/
- private AuthorityInfo getAuthorityLocked(Account accountName, int userId, String authorityName,
- String tag) {
- AccountAndUser au = new AccountAndUser(accountName, userId);
- AccountInfo accountInfo = mAccounts.get(au);
- if (accountInfo == null) {
- if (tag != null) {
- if (DEBUG) {
- Log.v(TAG, tag + ": unknown account " + au);
+ private AuthorityInfo getAuthorityLocked(EndPoint info, String tag) {
+ if (info.target_service) {
+ SparseArray<AuthorityInfo> aInfo = mServices.get(info.service);
+ AuthorityInfo authority = null;
+ if (aInfo != null) {
+ authority = aInfo.get(info.userId);
+ }
+ if (authority == null) {
+ if (tag != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + " No authority info found for " + info.service + " for"
+ + " user " + info.userId);
+ }
}
+ return null;
}
- return null;
- }
- AuthorityInfo authority = accountInfo.authorities.get(authorityName);
- if (authority == null) {
- if (tag != null) {
- if (DEBUG) {
- Log.v(TAG, tag + ": unknown authority " + authorityName);
+ return authority;
+ } else if (info.target_provider){
+ AccountAndUser au = new AccountAndUser(info.account, info.userId);
+ AccountInfo accountInfo = mAccounts.get(au);
+ if (accountInfo == null) {
+ if (tag != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + ": unknown account " + au);
+ }
}
+ return null;
}
- return null;
- }
-
- return authority;
- }
-
- /**
- * Retrieve an authority, returning null if one does not exist.
- *
- * @param service The service name used for this sync.
- * @param userId The user for whom this sync is scheduled.
- * @param tag If non-null, this will be used in a log message if the
- * requested authority does not exist.
- */
- private AuthorityInfo getAuthorityLocked(ComponentName service, int userId, String tag) {
- AuthorityInfo authority = mServices.get(service).get(userId);
- if (authority == null) {
- if (tag != null) {
- if (DEBUG) {
- Log.v(TAG, tag + " No authority info found for " + service + " for user "
- + userId);
+ AuthorityInfo authority = accountInfo.authorities.get(info.provider);
+ if (authority == null) {
+ if (tag != null) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, tag + ": unknown provider " + info.provider);
+ }
}
+ return null;
}
+ return authority;
+ } else {
+ Log.e(TAG, tag + " Authority : " + info + ", invalid target");
return null;
}
- return authority;
}
/**
- * @param cname identifier for the service.
- * @param userId for the syncs corresponding to this authority.
- * @param ident unique identifier for authority. -1 for none.
+ * @param info info identifying target.
+ * @param ident unique identifier for target. -1 for none.
* @param doWrite if true, update the accounts.xml file on the disk.
- * @return the authority that corresponds to the provided sync service, creating it if none
+ * @return the authority that corresponds to the provided sync target, creating it if none
* exists.
*/
- private AuthorityInfo getOrCreateAuthorityLocked(ComponentName cname, int userId, int ident,
- boolean doWrite) {
- SparseArray<AuthorityInfo> aInfo = mServices.get(cname);
- if (aInfo == null) {
- aInfo = new SparseArray<AuthorityInfo>();
- mServices.put(cname, aInfo);
- }
- AuthorityInfo authority = aInfo.get(userId);
- if (authority == null) {
- if (ident < 0) {
- ident = mNextAuthorityId;
- mNextAuthorityId++;
- doWrite = true;
- }
- if (DEBUG) {
- Log.v(TAG, "created a new AuthorityInfo for " + cname.getPackageName()
- + ", " + cname.getClassName()
- + ", user: " + userId);
- }
- authority = new AuthorityInfo(cname, userId, ident);
- aInfo.put(userId, authority);
- mAuthorities.put(ident, authority);
- if (doWrite) {
- writeAccountInfoLocked();
+ private AuthorityInfo getOrCreateAuthorityLocked(EndPoint info, int ident, boolean doWrite) {
+ AuthorityInfo authority = null;
+ if (info.target_service) {
+ SparseArray<AuthorityInfo> aInfo = mServices.get(info.service);
+ if (aInfo == null) {
+ aInfo = new SparseArray<AuthorityInfo>();
+ mServices.put(info.service, aInfo);
+ }
+ authority = aInfo.get(info.userId);
+ if (authority == null) {
+ authority = createAuthorityLocked(info, ident, doWrite);
+ aInfo.put(info.userId, authority);
+ }
+ } else if (info.target_provider) {
+ AccountAndUser au = new AccountAndUser(info.account, info.userId);
+ AccountInfo account = mAccounts.get(au);
+ if (account == null) {
+ account = new AccountInfo(au);
+ mAccounts.put(au, account);
+ }
+ authority = account.authorities.get(info.provider);
+ if (authority == null) {
+ authority = createAuthorityLocked(info, ident, doWrite);
+ account.authorities.put(info.provider, authority);
}
}
return authority;
}
- private AuthorityInfo getOrCreateAuthorityLocked(Account accountName, int userId,
- String authorityName, int ident, boolean doWrite) {
- AccountAndUser au = new AccountAndUser(accountName, userId);
- AccountInfo account = mAccounts.get(au);
- if (account == null) {
- account = new AccountInfo(au);
- mAccounts.put(au, account);
- }
- AuthorityInfo authority = account.authorities.get(authorityName);
- if (authority == null) {
- if (ident < 0) {
- ident = mNextAuthorityId;
- mNextAuthorityId++;
- doWrite = true;
- }
- if (DEBUG) {
- Log.v(TAG, "created a new AuthorityInfo for " + accountName
- + ", user " + userId
- + ", provider " + authorityName);
- }
- authority = new AuthorityInfo(accountName, userId, authorityName, ident);
- account.authorities.put(authorityName, authority);
- mAuthorities.put(ident, authority);
- if (doWrite) {
- writeAccountInfoLocked();
- }
+ private AuthorityInfo createAuthorityLocked(EndPoint info, int ident, boolean doWrite) {
+ AuthorityInfo authority;
+ if (ident < 0) {
+ ident = mNextAuthorityId;
+ mNextAuthorityId++;
+ doWrite = true;
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "created a new AuthorityInfo for " + info);
+ }
+ authority = new AuthorityInfo(info, ident);
+ mAuthorities.put(ident, authority);
+ if (doWrite) {
+ writeAccountInfoLocked();
}
-
return authority;
}
+ public void removeAuthority(EndPoint info) {
+ synchronized (mAuthorities) {
+ if (info.target_provider) {
+ removeAuthorityLocked(info.account, info.userId, info.provider, true /* doWrite */);
+ } else {
+ SparseArray<AuthorityInfo> aInfos = mServices.get(info.service);
+ if (aInfos != null) {
+ AuthorityInfo authorityInfo = aInfos.get(info.userId);
+ if (authorityInfo != null) {
+ mAuthorities.remove(authorityInfo.ident);
+ aInfos.delete(info.userId);
+ writeAccountInfoLocked();
+ }
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Remove an authority associated with a provider. Needs to be a standalone function for
+ * backward compatibility.
+ */
private void removeAuthorityLocked(Account account, int userId, String authorityName,
boolean doWrite) {
AccountInfo accountInfo = mAccounts.get(new AccountAndUser(account, userId));
@@ -1592,10 +1716,9 @@ public class SyncStorageEngine extends Handler {
/**
* Updates (in a synchronized way) the periodic sync time of the specified
- * authority id and target periodic sync
+ * target id and target periodic sync
*/
- public void setPeriodicSyncTime(
- int authorityId, PeriodicSync targetPeriodicSync, long when) {
+ public void setPeriodicSyncTime(int authorityId, PeriodicSync targetPeriodicSync, long when) {
boolean found = false;
final AuthorityInfo authorityInfo;
synchronized (mAuthorities) {
@@ -1611,7 +1734,7 @@ public class SyncStorageEngine extends Handler {
}
if (!found) {
Log.w(TAG, "Ignoring setPeriodicSyncTime request for a sync that does not exist. " +
- "Authority: " + authorityInfo.authority);
+ "Authority: " + authorityInfo.target);
}
}
@@ -1672,7 +1795,7 @@ public class SyncStorageEngine extends Handler {
try {
fis = mAccountInfoFile.openRead();
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Reading " + mAccountInfoFile.getBaseFile());
+ Log.v(TAG_FILE, "Reading " + mAccountInfoFile.getBaseFile());
}
XmlPullParser parser = Xml.newPullParser();
parser.setInput(fis, null);
@@ -1780,10 +1903,14 @@ public class SyncStorageEngine extends Handler {
ArrayList<AuthorityInfo> authoritiesToRemove = new ArrayList<AuthorityInfo>();
final int N = mAuthorities.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
AuthorityInfo authority = mAuthorities.valueAt(i);
+ // skip this authority if it doesn't target a provider
+ if (authority.target.target_service) {
+ continue;
+ }
// skip this authority if it isn't one of the renamed ones
- final String newAuthorityName = sAuthorityRenames.get(authority.authority);
+ final String newAuthorityName = sAuthorityRenames.get(authority.target.provider);
if (newAuthorityName == null) {
continue;
}
@@ -1799,20 +1926,26 @@ public class SyncStorageEngine extends Handler {
}
// if we already have a record of this new authority then don't copy over the settings
- if (getAuthorityLocked(authority.account, authority.userId, newAuthorityName, "cleanup")
- != null) {
+ EndPoint newInfo =
+ new EndPoint(authority.target.account,
+ newAuthorityName,
+ authority.target.userId);
+ if (getAuthorityLocked(newInfo, "cleanup") != null) {
continue;
}
- AuthorityInfo newAuthority = getOrCreateAuthorityLocked(authority.account,
- authority.userId, newAuthorityName, -1 /* ident */, false /* doWrite */);
+ AuthorityInfo newAuthority =
+ getOrCreateAuthorityLocked(newInfo, -1 /* ident */, false /* doWrite */);
newAuthority.enabled = true;
writeNeeded = true;
}
for (AuthorityInfo authorityInfo : authoritiesToRemove) {
- removeAuthorityLocked(authorityInfo.account, authorityInfo.userId,
- authorityInfo.authority, false /* doWrite */);
+ removeAuthorityLocked(
+ authorityInfo.target.account,
+ authorityInfo.target.userId,
+ authorityInfo.target.provider,
+ false /* doWrite */);
writeNeeded = true;
}
@@ -1854,30 +1987,37 @@ public class SyncStorageEngine extends Handler {
String packageName = parser.getAttributeValue(null, "package");
String className = parser.getAttributeValue(null, "class");
int userId = user == null ? 0 : Integer.parseInt(user);
- if (accountType == null) {
+ if (accountType == null && packageName == null) {
accountType = "com.google";
syncable = "unknown";
}
authority = mAuthorities.get(id);
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Adding authority: account="
- + accountName + " auth=" + authorityName
+ Log.v(TAG_FILE, "Adding authority:"
+ + " account=" + accountName
+ + " accountType=" + accountType
+ + " auth=" + authorityName
+ + " package=" + packageName
+ + " class=" + className
+ " user=" + userId
+ " enabled=" + enabled
+ " syncable=" + syncable);
}
if (authority == null) {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Creating entry");
+ Log.v(TAG_FILE, "Creating authority entry");
}
- if (accountName != null && accountType != null) {
- authority = getOrCreateAuthorityLocked(
- new Account(accountName, accountType), userId, authorityName, id,
- false);
+ EndPoint info;
+ if (accountName != null && authorityName != null) {
+ info = new EndPoint(
+ new Account(accountName, accountType),
+ authorityName, userId);
} else {
- authority = getOrCreateAuthorityLocked(
- new ComponentName(packageName, className), userId, id, false);
+ info = new EndPoint(
+ new ComponentName(packageName, className),
+ userId);
}
+ authority = getOrCreateAuthorityLocked(info, id, false);
// If the version is 0 then we are upgrading from a file format that did not
// know about periodic syncs. In that case don't clear the list since we
// want the default, which is a daily periodic sync.
@@ -1908,7 +2048,7 @@ public class SyncStorageEngine extends Handler {
/**
* Parse a periodic sync from accounts.xml. Sets the bundle to be empty.
*/
- private PeriodicSync parsePeriodicSync(XmlPullParser parser, AuthorityInfo authority) {
+ private PeriodicSync parsePeriodicSync(XmlPullParser parser, AuthorityInfo authorityInfo) {
Bundle extras = new Bundle(); // Gets filled in later.
String periodValue = parser.getAttributeValue(null, "period");
String flexValue = parser.getAttributeValue(null, "flex");
@@ -1926,17 +2066,31 @@ public class SyncStorageEngine extends Handler {
try {
flextime = Long.parseLong(flexValue);
} catch (NumberFormatException e) {
- Log.e(TAG, "Error formatting value parsed for periodic sync flex: " + flexValue);
flextime = calculateDefaultFlexTime(period);
+ Log.e(TAG, "Error formatting value parsed for periodic sync flex: " + flexValue
+ + ", using default: "
+ + flextime);
} catch (NullPointerException expected) {
flextime = calculateDefaultFlexTime(period);
Log.d(TAG, "No flex time specified for this sync, using a default. period: "
+ period + " flex: " + flextime);
}
- final PeriodicSync periodicSync =
- new PeriodicSync(authority.account, authority.authority, extras,
+ PeriodicSync periodicSync;
+ if (authorityInfo.target.target_provider) {
+ periodicSync =
+ new PeriodicSync(authorityInfo.target.account,
+ authorityInfo.target.provider,
+ extras,
period, flextime);
- authority.periodicSyncs.add(periodicSync);
+ } else {
+ periodicSync =
+ new PeriodicSync(
+ authorityInfo.target.service,
+ extras,
+ period,
+ flextime);
+ }
+ authorityInfo.periodicSyncs.add(periodicSync);
return periodicSync;
}
@@ -1974,7 +2128,7 @@ public class SyncStorageEngine extends Handler {
*/
private void writeAccountInfoLocked() {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Writing new " + mAccountInfoFile.getBaseFile());
+ Log.v(TAG_FILE, "Writing new " + mAccountInfoFile.getBaseFile());
}
FileOutputStream fos = null;
@@ -2004,17 +2158,18 @@ public class SyncStorageEngine extends Handler {
final int N = mAuthorities.size();
for (int i = 0; i < N; i++) {
AuthorityInfo authority = mAuthorities.valueAt(i);
+ EndPoint info = authority.target;
out.startTag(null, "authority");
out.attribute(null, "id", Integer.toString(authority.ident));
- out.attribute(null, XML_ATTR_USER, Integer.toString(authority.userId));
+ out.attribute(null, XML_ATTR_USER, Integer.toString(info.userId));
out.attribute(null, XML_ATTR_ENABLED, Boolean.toString(authority.enabled));
- if (authority.service == null) {
- out.attribute(null, "account", authority.account.name);
- out.attribute(null, "type", authority.account.type);
- out.attribute(null, "authority", authority.authority);
+ if (info.service == null) {
+ out.attribute(null, "account", info.account.name);
+ out.attribute(null, "type", info.account.type);
+ out.attribute(null, "authority", info.provider);
} else {
- out.attribute(null, "package", authority.service.getPackageName());
- out.attribute(null, "class", authority.service.getClassName());
+ out.attribute(null, "package", info.service.getPackageName());
+ out.attribute(null, "class", info.service.getClassName());
}
if (authority.syncable < 0) {
out.attribute(null, "syncable", "unknown");
@@ -2074,7 +2229,7 @@ public class SyncStorageEngine extends Handler {
// Copy in all of the status information, as well as accounts.
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Reading legacy sync accounts db");
+ Log.v(TAG_FILE, "Reading legacy sync accounts db");
}
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables("stats, status");
@@ -2108,9 +2263,13 @@ public class SyncStorageEngine extends Handler {
accountType = "com.google";
}
String authorityName = c.getString(c.getColumnIndex("authority"));
- AuthorityInfo authority = this.getOrCreateAuthorityLocked(
- new Account(accountName, accountType), 0 /* legacy is single-user */,
- authorityName, -1, false);
+ AuthorityInfo authority =
+ this.getOrCreateAuthorityLocked(
+ new EndPoint(new Account(accountName, accountType),
+ authorityName,
+ 0 /* legacy is single-user */)
+ , -1,
+ false);
if (authority != null) {
int i = mSyncStatus.size();
boolean found = false;
@@ -2162,7 +2321,7 @@ public class SyncStorageEngine extends Handler {
while (i > 0) {
i--;
AuthorityInfo authority = mAuthorities.valueAt(i);
- if (authority.authority.equals(provider)) {
+ if (authority.target.provider.equals(provider)) {
authority.enabled = value == null || Boolean.parseBoolean(value);
authority.syncable = 1;
}
@@ -2186,7 +2345,7 @@ public class SyncStorageEngine extends Handler {
*/
private void readStatusLocked() {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Reading " + mStatusFile.getBaseFile());
+ Log.v(TAG_FILE, "Reading " + mStatusFile.getBaseFile());
}
try {
byte[] data = mStatusFile.readFully();
@@ -2200,8 +2359,7 @@ public class SyncStorageEngine extends Handler {
if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
status.pending = false;
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Adding status for id "
- + status.authorityId);
+ Log.v(TAG_FILE, "Adding status for id " + status.authorityId);
}
mSyncStatus.put(status.authorityId, status);
}
@@ -2221,7 +2379,7 @@ public class SyncStorageEngine extends Handler {
*/
private void writeStatusLocked() {
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG, "Writing new " + mStatusFile.getBaseFile());
+ Log.v(TAG_FILE, "Writing new " + mStatusFile.getBaseFile());
}
// The file is being written, so we don't need to have a scheduled
@@ -2264,6 +2422,9 @@ public class SyncStorageEngine extends Handler {
}
try {
fis = mPendingFile.openRead();
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
+ Log.v(TAG_FILE, "Reading " + mPendingFile.getBaseFile());
+ }
XmlPullParser parser;
parser = Xml.newPullParser();
parser.setInput(fis, null);
@@ -2275,12 +2436,11 @@ public class SyncStorageEngine extends Handler {
}
if (eventType == XmlPullParser.END_DOCUMENT) return; // Nothing to read.
- String tagName = parser.getName();
do {
PendingOperation pop = null;
if (eventType == XmlPullParser.START_TAG) {
try {
- tagName = parser.getName();
+ String tagName = parser.getName();
if (parser.getDepth() == 1 && "op".equals(tagName)) {
// Verify version.
String versionString =
@@ -2305,18 +2465,16 @@ public class SyncStorageEngine extends Handler {
}
if (authority != null) {
pop = new PendingOperation(
- authority.account, authority.userId, reason,
- syncSource, authority.authority, new Bundle(),
- expedited);
+ authority, reason, syncSource, 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
+ + pop.target
+ " src=" + pop.syncSource
+ " reason=" + pop.reason
+ " expedited=" + pop.expedited);
- }
+ }
} else {
// Skip non-existent authority.
pop = null;
@@ -2351,11 +2509,40 @@ public class SyncStorageEngine extends Handler {
}
}
+ static private byte[] flattenBundle(Bundle bundle) {
+ byte[] flatData = null;
+ Parcel parcel = Parcel.obtain();
+ try {
+ bundle.writeToParcel(parcel, 0);
+ flatData = parcel.marshall();
+ } finally {
+ parcel.recycle();
+ }
+ return flatData;
+ }
+
+ static private Bundle unflattenBundle(byte[] flatData) {
+ Bundle bundle;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.unmarshall(flatData, 0, flatData.length);
+ parcel.setDataPosition(0);
+ bundle = parcel.readBundle();
+ } catch (RuntimeException e) {
+ // A RuntimeException is thrown if we were unable to parse the parcel.
+ // Create an empty parcel in this case.
+ bundle = new Bundle();
+ } finally {
+ parcel.recycle();
+ }
+ return bundle;
+ }
+
+ private static final String XML_ATTR_VERSION = "version";
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";
/**
* Write all currently pending ops to the pending ops file.
@@ -2365,14 +2552,14 @@ public class SyncStorageEngine extends Handler {
FileOutputStream fos = null;
try {
if (N == 0) {
- if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG_FILE, "Truncating " + mPendingFile.getBaseFile());
+ if (Log.isLoggable(TAG_FILE, Log.VERBOSE)){
+ Log.v(TAG, "Truncating " + mPendingFile.getBaseFile());
}
mPendingFile.truncate();
return;
}
if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
- Log.v(TAG_FILE, "Writing new " + mPendingFile.getBaseFile());
+ Log.v(TAG, "Writing new " + mPendingFile.getBaseFile());
}
fos = mPendingFile.startWrite();
XmlSerializer out = new FastXmlSerializer();
@@ -2381,9 +2568,9 @@ public class SyncStorageEngine extends Handler {
for (int i = 0; i < N; i++) {
PendingOperation pop = mPendingOperations.get(i);
writePendingOperationLocked(pop, out);
- }
- out.endDocument();
- mPendingFile.finishWrite(fos);
+ }
+ out.endDocument();
+ mPendingFile.finishWrite(fos);
} catch (java.io.IOException e1) {
Log.w(TAG, "Error writing pending operations", e1);
if (fos != null) {
@@ -2443,35 +2630,6 @@ public class SyncStorageEngine extends Handler {
}
}
- static private byte[] flattenBundle(Bundle bundle) {
- byte[] flatData = null;
- Parcel parcel = Parcel.obtain();
- try {
- bundle.writeToParcel(parcel, 0);
- flatData = parcel.marshall();
- } finally {
- parcel.recycle();
- }
- return flatData;
- }
-
- static private Bundle unflattenBundle(byte[] flatData) {
- Bundle bundle;
- Parcel parcel = Parcel.obtain();
- try {
- parcel.unmarshall(flatData, 0, flatData.length);
- parcel.setDataPosition(0);
- bundle = parcel.readBundle();
- } catch (RuntimeException e) {
- // A RuntimeException is thrown if we were unable to parse the parcel.
- // Create an empty parcel in this case.
- bundle = new Bundle();
- } finally {
- parcel.recycle();
- }
- return bundle;
- }
-
private void extrasToXml(XmlSerializer out, Bundle extras) throws java.io.IOException {
for (String key : extras.keySet()) {
out.startTag(null, "extra");
@@ -2504,6 +2662,24 @@ public class SyncStorageEngine extends Handler {
}
}
+ private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras) {
+ if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
+ && mSyncRequestListener != null) {
+ mSyncRequestListener.onSyncRequest(authorityInfo.target, reason, extras);
+ } else {
+ SyncRequest.Builder req =
+ new SyncRequest.Builder()
+ .syncOnce(0, 0)
+ .setExtras(extras);
+ if (authorityInfo.target.target_provider) {
+ req.setSyncAdapter(authorityInfo.target.account, authorityInfo.target.provider);
+ } else {
+ req.setSyncAdapter(authorityInfo.target.service);
+ }
+ ContentResolver.requestSync(req.build());
+ }
+ }
+
private void requestSync(Account account, int userId, int reason, String authority,
Bundle extras) {
// If this is happening in the system process, then call the syncrequest listener
@@ -2512,7 +2688,10 @@ public class SyncStorageEngine extends Handler {
// which will know which userId to apply based on the Binder id.
if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
&& mSyncRequestListener != null) {
- mSyncRequestListener.onSyncRequest(account, userId, reason, authority, extras);
+ mSyncRequestListener.onSyncRequest(
+ new EndPoint(account, authority, userId),
+ reason,
+ extras);
} else {
ContentResolver.requestSync(account, authority, extras);
}
@@ -2608,10 +2787,8 @@ public class SyncStorageEngine extends Handler {
public void dumpPendingOperations(StringBuilder sb) {
sb.append("Pending Ops: ").append(mPendingOperations.size()).append(" operation(s)\n");
for (PendingOperation pop : mPendingOperations) {
- sb.append("(" + pop.account)
- .append(", u" + pop.userId)
- .append(", " + pop.authority)
- .append(", " + pop.extras)
+ sb.append("(info: " + pop.target.toString())
+ .append(", extras: " + pop.extras)
.append(")\n");
}
}
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
index aaa0b58..6df1dbd 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -268,11 +268,13 @@ public class IntentFirewall {
}
File[] files = rulesDir.listFiles();
- for (int i=0; i<files.length; i++) {
- File file = files[i];
+ if (files != null) {
+ for (int i=0; i<files.length; i++) {
+ File file = files[i];
- if (file.getName().endsWith(".xml")) {
- readRules(file, resolvers);
+ if (file.getName().endsWith(".xml")) {
+ readRules(file, resolvers);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
index e44652f..0354ffd 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -17,6 +17,7 @@
package com.android.server.content;
import android.accounts.Account;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -32,22 +33,34 @@ import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.content.SyncStorageEngine.EndPoint;
+
import com.android.internal.os.AtomicFile;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
+import com.android.server.content.SyncStorageEngine.EndPoint;
+
public class SyncStorageEngineTest extends AndroidTestCase {
protected Account account1;
+ protected Account account2;
+ protected ComponentName syncService1;
protected String authority1 = "testprovider";
protected Bundle defaultBundle;
protected final int DEFAULT_USER = 0;
-
+
+ /* Some default poll frequencies. */
+ final long dayPoll = (60 * 60 * 24);
+ final long dayFuzz = 60;
+ final long thousandSecs = 1000;
+ final long thousandSecsFuzz = 100;
+
MockContentResolver mockResolver;
SyncStorageEngine engine;
-
+
private File getSyncDir() {
return new File(new File(getContext().getFilesDir(), "system"), "sync");
}
@@ -55,6 +68,8 @@ public class SyncStorageEngineTest extends AndroidTestCase {
@Override
public void setUp() {
account1 = new Account("a@example.com", "example.type");
+ account2 = new Account("b@example.com", "example.type");
+ syncService1 = new ComponentName("com.example", "SyncService");
// Default bundle.
defaultBundle = new Bundle();
defaultBundle.putInt("int_key", 0);
@@ -80,11 +95,13 @@ public class SyncStorageEngineTest extends AndroidTestCase {
SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
new TestContext(mockResolver, getContext()));
-
long time0 = 1000;
- long historyId = engine.insertStartSyncEvent(
- account, 0, SyncOperation.REASON_PERIODIC, authority, time0,
- SyncStorageEngine.SOURCE_LOCAL, false /* initialization */, null /* extras */);
+ SyncOperation op = new SyncOperation(account, 0,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_LOCAL,
+ authority,
+ Bundle.EMPTY, time0, 0 /* flex*/, 0, 0, true);
+ long historyId = engine.insertStartSyncEvent(op, time0);
long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
}
@@ -93,28 +110,100 @@ public class SyncStorageEngineTest extends AndroidTestCase {
* Test persistence of pending operations.
*/
@MediumTest
- public void testPending() throws Exception {
- SyncStorageEngine.PendingOperation pop =
- new SyncStorageEngine.PendingOperation(account1, DEFAULT_USER,
- SyncOperation.REASON_PERIODIC, SyncStorageEngine.SOURCE_LOCAL,
- authority1, defaultBundle, false);
-
- engine.insertIntoPending(pop);
+ public void testAppendPending() throws Exception {
+ SyncOperation sop = new SyncOperation(account1,
+ DEFAULT_USER,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY,
+ 0 /* runtime */, 0 /* flex */, 0 /* backoff */, 0 /* delayuntil */,
+ true /* expedited */);
+ engine.insertIntoPending(sop);
+
// Force engine to read from disk.
engine.clearAndReadState();
- assert(engine.getPendingOperationCount() == 1);
+ assertTrue(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));
+ assertEquals(sop.target.account, popRetrieved.target.account);
+ assertEquals(sop.target.provider, popRetrieved.target.provider);
+ assertEquals(sop.target.service, popRetrieved.target.service);
+ assertEquals(sop.target.userId, popRetrieved.target.userId);
+ assertEquals(sop.reason, popRetrieved.reason);
+ assertEquals(sop.syncSource, popRetrieved.syncSource);
+ assertEquals(sop.expedited, popRetrieved.expedited);
+ assert(android.content.PeriodicSync.syncExtrasEquals(sop.extras, popRetrieved.extras));
+ }
+ /**
+ * Verify {@link com.android.server.content.SyncStorageEngine#writePendingOperationsLocked()}
+ */
+ public void testWritePendingOperationsLocked() throws Exception {
+ SyncOperation sop = new SyncOperation(account1,
+ DEFAULT_USER,
+ SyncOperation.REASON_IS_SYNCABLE,
+ SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY,
+ 1000L /* runtime */, 57L /* flex */, 0 /* backoff */, 0 /* delayuntil */,
+ true /* expedited */);
+ SyncOperation sop1 = new SyncOperation(account2,
+ DEFAULT_USER,
+ SyncOperation.REASON_PERIODIC,
+ SyncStorageEngine.SOURCE_LOCAL, authority1, defaultBundle,
+ 0 /* runtime */, 0 /* flex */, 20L /* backoff */, 100L /* delayuntil */,
+ false /* expedited */);
+ SyncOperation deleted = new SyncOperation(account2,
+ DEFAULT_USER,
+ SyncOperation.REASON_SYNC_AUTO,
+ SyncStorageEngine.SOURCE_LOCAL, authority1, Bundle.EMPTY,
+ 0 /* runtime */, 0 /* flex */, 20L /* backoff */, 100L /* delayuntil */,
+ false /* expedited */);
+ engine.insertIntoPending(sop);
+ engine.insertIntoPending(sop1);
+ engine.insertIntoPending(deleted);
+
+ SyncStorageEngine.PendingOperation popDeleted = engine.getPendingOperations().get(2);
+ // Free verifying, going to delete it anyway.
+ assertEquals(deleted.target.account, popDeleted.target.account);
+ assertEquals(deleted.target.provider, popDeleted.target.provider);
+ assertEquals(deleted.target.service, popDeleted.target.service);
+ assertEquals(deleted.target.userId, popDeleted.target.userId);
+ assertEquals(deleted.reason, popDeleted.reason);
+ assertEquals(deleted.syncSource, popDeleted.syncSource);
+ assertEquals(deleted.expedited, popDeleted.expedited);
+ assert(android.content.PeriodicSync.syncExtrasEquals(deleted.extras, popDeleted.extras));
+ // Delete one to force write-all
+ engine.deleteFromPending(popDeleted);
+ assertEquals("Delete of pending op failed.", 2, engine.getPendingOperationCount());
+ // If there's dirty pending data (which there is because we deleted a pending op) this
+ // re-writes the entire file.
+ engine.writeAllState();
+
+ engine.clearAndReadState();
+
+ // Validate state read back out.
+ assertEquals("Delete of pending op failed.", 2, engine.getPendingOperationCount());
+
+ List<SyncStorageEngine.PendingOperation> pops = engine.getPendingOperations();
+
+ SyncStorageEngine.PendingOperation popRetrieved = pops.get(0);
+ assertEquals(sop.target.account, popRetrieved.target.account);
+ assertEquals(sop.target.provider, popRetrieved.target.provider);
+ assertEquals(sop.target.service, popRetrieved.target.service);
+ assertEquals(sop.target.userId, popRetrieved.target.userId);
+ assertEquals(sop.reason, popRetrieved.reason);
+ assertEquals(sop.syncSource, popRetrieved.syncSource);
+ assertEquals(sop.expedited, popRetrieved.expedited);
+ assert(android.content.PeriodicSync.syncExtrasEquals(sop.extras, popRetrieved.extras));
+
+ popRetrieved = pops.get(1);
+ assertEquals(sop1.target.account, popRetrieved.target.account);
+ assertEquals(sop1.target.provider, popRetrieved.target.provider);
+ assertEquals(sop1.target.service, popRetrieved.target.service);
+ assertEquals(sop1.target.userId, popRetrieved.target.userId);
+ assertEquals(sop1.reason, popRetrieved.reason);
+ assertEquals(sop1.syncSource, popRetrieved.syncSource);
+ assertEquals(sop1.expedited, popRetrieved.expedited);
+ assert(android.content.PeriodicSync.syncExtrasEquals(sop1.extras, popRetrieved.extras));
}
/**
@@ -134,42 +223,44 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final int period2 = 1000;
PeriodicSync sync1 = new PeriodicSync(account1, authority, extras1, period1);
+ EndPoint end1 = new EndPoint(account1, authority, 0);
+
PeriodicSync sync2 = new PeriodicSync(account1, authority, extras2, period1);
PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2);
PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2);
-
+
removePeriodicSyncs(engine, account1, 0, authority);
removePeriodicSyncs(engine, account2, 0, authority);
removePeriodicSyncs(engine, account1, 1, authority);
// this should add two distinct periodic syncs for account1 and one for account2
- engine.addPeriodicSync(sync1, 0);
- engine.addPeriodicSync(sync2, 0);
- engine.addPeriodicSync(sync3, 0);
- engine.addPeriodicSync(sync4, 0);
+ engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period1, 0, extras1);
+ engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period1, 0, extras2);
+ engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 0), period2, 0, extras2);
+ engine.updateOrAddPeriodicSync(new EndPoint(account2, authority, 0), period2, 0, extras2);
// add a second user
- engine.addPeriodicSync(sync2, 1);
+ engine.updateOrAddPeriodicSync(new EndPoint(account1, authority, 1), period1, 0, extras2);
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(new EndPoint(account1, authority, 0));
assertEquals(2, syncs.size());
assertEquals(sync1, syncs.get(0));
assertEquals(sync3, syncs.get(1));
- engine.removePeriodicSync(sync1, 0);
+ engine.removePeriodicSync(new EndPoint(account1, authority, 0), extras1);
- syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ syncs = engine.getPeriodicSyncs(new EndPoint(account1, authority, 0));
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account2, 0, authority);
+ syncs = engine.getPeriodicSyncs(new EndPoint(account2, authority, 0));
assertEquals(1, syncs.size());
assertEquals(sync4, syncs.get(0));
- syncs = engine.getPeriodicSyncs(sync2.account, 1, sync2.authority);
+ syncs = engine.getPeriodicSyncs(new EndPoint(sync2.account, sync2.authority, 1));
assertEquals(1, syncs.size());
assertEquals(sync2, syncs.get(0));
}
@@ -190,12 +281,19 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final int period2 = 1000;
final int flex1 = 10;
final int flex2 = 100;
+ EndPoint point1 = new EndPoint(account1, authority, 0);
+ EndPoint point2 = new EndPoint(account2, authority, 0);
+ EndPoint point1User2 = new EndPoint(account1, authority, 1);
PeriodicSync sync1 = new PeriodicSync(account1, authority, extras1, period1, flex1);
PeriodicSync sync2 = new PeriodicSync(account1, authority, extras2, period1, flex1);
PeriodicSync sync3 = new PeriodicSync(account1, authority, extras2, period2, flex2);
PeriodicSync sync4 = new PeriodicSync(account2, authority, extras2, period2, flex2);
+ EndPoint target1 = new EndPoint(account1, authority, 0);
+ EndPoint target2 = new EndPoint(account2, authority, 0);
+ EndPoint target1UserB = new EndPoint(account1, authority, 1);
+
MockContentResolver mockResolver = new MockContentResolver();
SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
@@ -206,40 +304,42 @@ public class SyncStorageEngineTest extends AndroidTestCase {
removePeriodicSyncs(engine, account1, 1, authority);
// This should add two distinct periodic syncs for account1 and one for account2
- engine.addPeriodicSync(sync1, 0);
- engine.addPeriodicSync(sync2, 0);
- engine.addPeriodicSync(sync3, 0); // Should edit sync2 and update the period.
- engine.addPeriodicSync(sync4, 0);
- // add a second user
- engine.addPeriodicSync(sync2, 1);
+ engine.updateOrAddPeriodicSync(target1, period1, flex1, extras1);
+ engine.updateOrAddPeriodicSync(target1, period1, flex1, extras2);
+ // Edit existing sync and update the period and flex.
+ engine.updateOrAddPeriodicSync(target1, period2, flex2, extras2);
+ engine.updateOrAddPeriodicSync(target2, period2, flex2, extras2);
+ // add a target for a second user.
+ engine.updateOrAddPeriodicSync(target1UserB, period1, flex1, extras2);
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
assertEquals(2, syncs.size());
assertEquals(sync1, syncs.get(0));
assertEquals(sync3, syncs.get(1));
- engine.removePeriodicSync(sync1, 0);
+ engine.removePeriodicSync(target1, extras1);
- syncs = engine.getPeriodicSyncs(account1, 0, authority);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account2, 0, authority);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync4, syncs.get(0));
- syncs = engine.getPeriodicSyncs(sync2.account, 1, sync2.authority);
+ syncs = engine.getPeriodicSyncs(target1UserB);
assertEquals(1, syncs.size());
assertEquals(sync2, syncs.get(0));
}
private void removePeriodicSyncs(SyncStorageEngine engine, Account account, int userId, String authority) {
- engine.setIsSyncable(account, userId, authority, engine.getIsSyncable(account, 0, authority));
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, userId, authority);
+ EndPoint target = new EndPoint(account, authority, userId);
+ engine.setIsSyncable(account, userId, authority, engine.getIsSyncable(account, userId, authority));
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target);
for (PeriodicSync sync : syncs) {
- engine.removePeriodicSync(sync, userId);
+ engine.removePeriodicSync(target, sync.extras);
}
}
@@ -264,16 +364,19 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final int flex1 = 10;
final int flex2 = 100;
+ EndPoint point1 = new EndPoint(account1, authority1, 0);
+ EndPoint point2 = new EndPoint(account1, authority2, 0);
+ EndPoint point3 = new EndPoint(account2, authority1, 0);
+
PeriodicSync sync1 = new PeriodicSync(account1, authority1, extras1, period1, flex1);
PeriodicSync sync2 = new PeriodicSync(account1, authority1, extras2, period1, flex1);
PeriodicSync sync3 = new PeriodicSync(account1, authority2, extras1, period1, flex1);
PeriodicSync sync4 = new PeriodicSync(account1, authority2, extras2, period2, flex2);
PeriodicSync sync5 = new PeriodicSync(account2, authority1, extras1, period1, flex1);
- MockContentResolver mockResolver = new MockContentResolver();
-
- SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
- new TestContext(mockResolver, getContext()));
+ EndPoint target1 = new EndPoint(account1, authority1, 0);
+ EndPoint target2 = new EndPoint(account1, authority2, 0);
+ EndPoint target3 = new EndPoint(account2, authority1, 0);
removePeriodicSyncs(engine, account1, 0, authority1);
removePeriodicSyncs(engine, account2, 0, authority1);
@@ -294,26 +397,26 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.setIsSyncable(account2, 0, authority2, 0);
engine.setSyncAutomatically(account2, 0, authority2, true);
- engine.addPeriodicSync(sync1, 0);
- engine.addPeriodicSync(sync2, 0);
- engine.addPeriodicSync(sync3, 0);
- engine.addPeriodicSync(sync4, 0);
- engine.addPeriodicSync(sync5, 0);
+ engine.updateOrAddPeriodicSync(target1, period1, flex1, extras1);
+ engine.updateOrAddPeriodicSync(target1, period1, flex1, extras2);
+ engine.updateOrAddPeriodicSync(target2, period1, flex1, extras1);
+ engine.updateOrAddPeriodicSync(target2, period2, flex2, extras2);
+ engine.updateOrAddPeriodicSync(target3, period1, flex1, extras1);
engine.writeAllState();
engine.clearAndReadState();
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account1, 0, authority1);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
assertEquals(2, syncs.size());
assertEquals(sync1, syncs.get(0));
assertEquals(sync2, syncs.get(1));
- syncs = engine.getPeriodicSyncs(account1, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(2, syncs.size());
assertEquals(sync3, syncs.get(0));
assertEquals(sync4, syncs.get(1));
- syncs = engine.getPeriodicSyncs(account2, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync5, syncs.get(0));
@@ -328,6 +431,50 @@ public class SyncStorageEngineTest extends AndroidTestCase {
assertEquals(0, engine.getIsSyncable(account2, 0, authority2));
}
+ @SmallTest
+ public void testComponentParsing() throws Exception {
+
+ byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<accounts version=\"2\" >\n"
+ + "<authority id=\"0\" user=\"0\" package=\"" + syncService1.getPackageName() + "\""
+ + " class=\"" + syncService1.getClassName() + "\" syncable=\"true\">"
+ + "\n<periodicSync period=\"" + dayPoll + "\" flex=\"" + dayFuzz + "\"/>"
+ + "\n</authority>"
+ + "</accounts>").getBytes();
+
+ File syncDir = getSyncDir();
+ syncDir.mkdirs();
+ AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"));
+ FileOutputStream fos = accountInfoFile.startWrite();
+ fos.write(accountsFileData);
+ accountInfoFile.finishWrite(fos);
+
+ engine.clearAndReadState();
+
+ SyncStorageEngine.AuthorityInfo aInfo = engine.getAuthority(0);
+ assertNotNull(aInfo);
+
+ // Test service component read
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(
+ new SyncStorageEngine.EndPoint(syncService1, 0));
+ assertEquals(1, syncs.size());
+ assertEquals(true, engine.getIsTargetServiceActive(syncService1, 0));
+ }
+
+ @SmallTest
+ public void testComponentSettings() throws Exception {
+ EndPoint target1 = new EndPoint(syncService1, 0);
+ engine.updateOrAddPeriodicSync(target1, dayPoll, dayFuzz, Bundle.EMPTY);
+
+ engine.setIsTargetServiceActive(target1.service, 0, true);
+ boolean active = engine.getIsTargetServiceActive(target1.service, 0);
+ assert(active);
+
+ engine.setIsTargetServiceActive(target1.service, 1, false);
+ active = engine.getIsTargetServiceActive(target1.service, 1);
+ assert(!active);
+ }
+
@MediumTest
/**
* V2 introduces flex time as well as service components.
@@ -339,20 +486,20 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final String authority2 = "auth2";
final String authority3 = "auth3";
- final long dayPoll = (60 * 60 * 24);
- final long dayFuzz = 60;
- final long thousandSecs = 1000;
- final long thousandSecsFuzz = 100;
- final Bundle extras = new Bundle();
- PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, dayPoll, dayFuzz);
- PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, dayPoll, dayFuzz);
- PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, dayPoll, dayFuzz);
- PeriodicSync sync1s = new PeriodicSync(account, authority1, extras, thousandSecs, thousandSecsFuzz);
- PeriodicSync sync2s = new PeriodicSync(account, authority2, extras, thousandSecs, thousandSecsFuzz);
- PeriodicSync sync3s = new PeriodicSync(account, authority3, extras, thousandSecs, thousandSecsFuzz);
- MockContentResolver mockResolver = new MockContentResolver();
-
- final TestContext testContext = new TestContext(mockResolver, getContext());
+ EndPoint target1 = new EndPoint(account, authority1, 0);
+ EndPoint target2 = new EndPoint(account, authority2, 0);
+ EndPoint target3 = new EndPoint(account, authority3, 0);
+ EndPoint target4 = new EndPoint(account, authority3, 1);
+
+ PeriodicSync sync1 = new PeriodicSync(account, authority1, Bundle.EMPTY, dayPoll, dayFuzz);
+ PeriodicSync sync2 = new PeriodicSync(account, authority2, Bundle.EMPTY, dayPoll, dayFuzz);
+ PeriodicSync sync3 = new PeriodicSync(account, authority3, Bundle.EMPTY, dayPoll, dayFuzz);
+ PeriodicSync sync1s = new PeriodicSync(account, authority1, Bundle.EMPTY, thousandSecs,
+ thousandSecsFuzz);
+ PeriodicSync sync2s = new PeriodicSync(account, authority2, Bundle.EMPTY, thousandSecs,
+ thousandSecsFuzz);
+ PeriodicSync sync3s = new PeriodicSync(account, authority3, Bundle.EMPTY, thousandSecs,
+ thousandSecsFuzz);
byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<accounts version=\"2\" >\n"
@@ -378,21 +525,22 @@ public class SyncStorageEngineTest extends AndroidTestCase {
fos.write(accountsFileData);
accountInfoFile.finishWrite(fos);
- SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
+ engine.clearAndReadState();
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
assertEquals("Got incorrect # of syncs", 1, syncs.size());
assertEquals(sync1, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync2, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 1, authority3);
+ syncs = engine.getPeriodicSyncs(target4);
+
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
@@ -411,13 +559,13 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.clearAndReadState();
- syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(0, syncs.size());
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(0, syncs.size());
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(0, syncs.size());
accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
@@ -440,15 +588,15 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.clearAndReadState();
- syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(1, syncs.size());
assertEquals(sync1s, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync2s, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync3s, syncs.get(0));
}
@@ -460,6 +608,12 @@ public class SyncStorageEngineTest extends AndroidTestCase {
final String authority2 = "auth2";
final String authority3 = "auth3";
final Bundle extras = new Bundle();
+
+ EndPoint target1 = new EndPoint(account, authority1, 0);
+ EndPoint target2 = new EndPoint(account, authority2, 0);
+ EndPoint target3 = new EndPoint(account, authority3, 0);
+ EndPoint target4 = new EndPoint(account, authority3, 1);
+
PeriodicSync sync1 = new PeriodicSync(account, authority1, extras, (long) (60 * 60 * 24));
PeriodicSync sync2 = new PeriodicSync(account, authority2, extras, (long) (60 * 60 * 24));
PeriodicSync sync3 = new PeriodicSync(account, authority3, extras, (long) (60 * 60 * 24));
@@ -488,19 +642,20 @@ public class SyncStorageEngineTest extends AndroidTestCase {
SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext);
- List<PeriodicSync> syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ List<PeriodicSync> syncs = engine.getPeriodicSyncs(target1);
assertEquals(1, syncs.size());
assertEquals("expected sync1: " + sync1.toString() + " == sync 2" + syncs.get(0).toString(), sync1, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync2, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
+ syncs = engine.getPeriodicSyncs(target4);
+
- syncs = engine.getPeriodicSyncs(account, 1, authority3);
assertEquals(1, syncs.size());
assertEquals(sync3, syncs.get(0));
@@ -518,13 +673,13 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.clearAndReadState();
- syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(0, syncs.size());
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(0, syncs.size());
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(0, syncs.size());
accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
@@ -547,15 +702,15 @@ public class SyncStorageEngineTest extends AndroidTestCase {
engine.clearAndReadState();
- syncs = engine.getPeriodicSyncs(account, 0, authority1);
+ syncs = engine.getPeriodicSyncs(target1);
assertEquals(1, syncs.size());
assertEquals(sync1s, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority2);
+ syncs = engine.getPeriodicSyncs(target2);
assertEquals(1, syncs.size());
assertEquals(sync2s, syncs.get(0));
- syncs = engine.getPeriodicSyncs(account, 0, authority3);
+ syncs = engine.getPeriodicSyncs(target3);
assertEquals(1, syncs.size());
assertEquals(sync3s, syncs.get(0));
}