diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index ffd0d0bec328a..563b6cf0349cf 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3192,6 +3192,21 @@ public abstract class ContentResolver implements ContentInterface {
}
}
+ /**
+ * Returns the package name of the syncadapter that matches a given account type, authority
+ * and user.
+ * @hide
+ */
+ @Nullable
+ public static String getSyncAdapterPackageAsUser(@NonNull String accountType,
+ @NonNull String authority, @UserIdInt int userId) {
+ try {
+ return getContentService().getSyncAdapterPackageAsUser(accountType, authority, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Check if the provider should be synced when a network tickle is received
*
This method requires the caller to hold the permission
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 2044fc02a7e5c..127466d586299 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -150,6 +150,7 @@ interface IContentService {
SyncAdapterType[] getSyncAdapterTypesAsUser(int userId);
String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId);
+ String getSyncAdapterPackageAsUser(String accountType, String authority, int userId);
/**
* Returns true if there is currently a operation for the given account/authority or service
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index c3c42bae55b0b..fadcce9ee9b3e 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -23,6 +23,7 @@ import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
@@ -822,6 +823,21 @@ public final class ContentService extends IContentService.Stub {
}
}
+ @Override
+ public String getSyncAdapterPackageAsUser(@NonNull String accountType,
+ @NonNull String authority, @UserIdInt int userId) {
+ enforceCrossUserPermission(userId,
+ "no permission to read sync settings for user " + userId);
+ final int callingUid = Binder.getCallingUid();
+ final long identityToken = clearCallingIdentity();
+ try {
+ return getSyncManager().getSyncAdapterPackageAsUser(accountType, authority,
+ callingUid, userId);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
@Override
public boolean getSyncAutomatically(Account account, String providerName) {
return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
@@ -1205,7 +1221,7 @@ public final class ContentService extends IContentService.Stub {
SyncManager syncManager = getSyncManager();
if (syncManager != null && callback != null) {
syncManager.getSyncStorageEngine().addStatusChangeListener(
- mask, UserHandle.getUserId(callingUid), callback);
+ mask, callingUid, callback);
}
} finally {
restoreCallingIdentity(identityToken);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index fb919fbe0a3df..484f97f6524d7 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1246,6 +1246,26 @@ public class SyncManager {
return filteredResult.toArray(new String[] {});
}
+ public String getSyncAdapterPackageAsUser(String accountType, String authority,
+ int callingUid, int userId) {
+ if (accountType == null || authority == null) {
+ return null;
+ }
+ final RegisteredServicesCache.ServiceInfo syncAdapterInfo =
+ mSyncAdapters.getServiceInfo(
+ SyncAdapterType.newKey(authority, accountType),
+ userId);
+ if (syncAdapterInfo == null) {
+ return null;
+ }
+ final String packageName = syncAdapterInfo.type.getPackageName();
+ if (TextUtils.isEmpty(packageName) || mPackageManagerInternal.filterAppAccess(
+ packageName, callingUid, userId)) {
+ return null;
+ }
+ return packageName;
+ }
+
private void sendSyncFinishedOrCanceledMessage(ActiveSyncContext syncContext,
SyncResult syncResult) {
if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "sending MESSAGE_SYNC_FINISHED");
@@ -3403,7 +3423,7 @@ public class SyncManager {
scheduleSyncOperationH(op);
mSyncStorageEngine.reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
- target.userId);
+ op.owningPackage, target.userId);
}
/**
@@ -3922,7 +3942,7 @@ public class SyncManager {
syncOperation.toEventLog(SyncStorageEngine.EVENT_STOP));
mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime,
resultMessage, downstreamActivity, upstreamActivity,
- syncOperation.target.userId);
+ syncOperation.owningPackage, syncOperation.target.userId);
}
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 668142b7e8eec..1894c0fc6045f 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -33,6 +33,7 @@ import android.content.SyncInfo;
import android.content.SyncRequest;
import android.content.SyncStatusInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -59,6 +60,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IntPair;
+import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -166,6 +168,8 @@ public class SyncStorageEngine {
private static HashMap sAuthorityRenames;
private static PeriodicSyncAddedListener mPeriodicSyncAddedListener;
+ private final PackageManagerInternal mPackageManagerInternal;
+
private volatile boolean mIsClockValid;
static {
@@ -525,6 +529,8 @@ public class SyncStorageEngine {
mDefaultMasterSyncAutomatically = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_syncstorageengine_masterSyncAutomatically);
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+
File systemDir = new File(dataDir, "system");
mSyncDir = new File(systemDir, SYNC_DIR_NAME);
mSyncDir.mkdirs();
@@ -609,9 +615,9 @@ public class SyncStorageEngine {
return mSyncRandomOffset;
}
- public void addStatusChangeListener(int mask, int userId, ISyncStatusObserver callback) {
+ public void addStatusChangeListener(int mask, int callingUid, ISyncStatusObserver callback) {
synchronized (mAuthorities) {
- final long cookie = IntPair.of(userId, mask);
+ final long cookie = IntPair.of(callingUid, mask);
mChangeListeners.register(callback, cookie);
}
}
@@ -644,16 +650,32 @@ public class SyncStorageEngine {
}
}
- void reportChange(int which, int callingUserId) {
+ void reportChange(int which, EndPoint target) {
+ final String syncAdapterPackageName;
+ if (target.account == null || target.provider == null) {
+ syncAdapterPackageName = null;
+ } else {
+ syncAdapterPackageName = ContentResolver.getSyncAdapterPackageAsUser(
+ target.account.type, target.provider, target.userId);
+ }
+ reportChange(which, syncAdapterPackageName, target.userId);
+ }
+
+ void reportChange(int which, String callingPackageName, int callingUserId) {
ArrayList reports = null;
synchronized (mAuthorities) {
int i = mChangeListeners.beginBroadcast();
while (i > 0) {
i--;
final long cookie = (long) mChangeListeners.getBroadcastCookie(i);
- final int userId = IntPair.first(cookie);
+ final int registerUid = IntPair.first(cookie);
+ final int registerUserId = UserHandle.getUserId(registerUid);
final int mask = IntPair.second(cookie);
- if ((which & mask) == 0 || callingUserId != userId) {
+ if ((which & mask) == 0 || callingUserId != registerUserId) {
+ continue;
+ }
+ if (callingPackageName != null && mPackageManagerInternal.filterAppAccess(
+ callingPackageName, registerUid, callingUserId)) {
continue;
}
if (reports == null) {
@@ -716,12 +738,12 @@ public class SyncStorageEngine {
" cuid=", callingUid,
" cpid=", callingPid
);
+ final AuthorityInfo authority;
synchronized (mAuthorities) {
- AuthorityInfo authority =
- getOrCreateAuthorityLocked(
- new EndPoint(account, providerName, userId),
- -1 /* ident */,
- false);
+ authority = getOrCreateAuthorityLocked(
+ new EndPoint(account, providerName, userId),
+ -1 /* ident */,
+ false);
if (authority.enabled == sync) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.d(TAG, "setSyncAutomatically: already set to " + sync + ", doing nothing");
@@ -743,7 +765,7 @@ public class SyncStorageEngine {
new Bundle(),
syncExemptionFlag, callingUid, callingPid);
}
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, userId);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, authority.target);
queueBackup();
}
@@ -811,7 +833,7 @@ public class SyncStorageEngine {
requestSync(aInfo, SyncOperation.REASON_IS_SYNCABLE, new Bundle(),
ContentResolver.SYNC_EXEMPTION_NONE, callingUid, callingPid);
}
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, target.userId);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, target);
}
public Pair getBackoff(EndPoint info) {
@@ -857,7 +879,7 @@ public class SyncStorageEngine {
}
}
if (changed) {
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, info.userId);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, info);
}
}
@@ -919,7 +941,8 @@ public class SyncStorageEngine {
}
for (int i = changedUserIds.size() - 1; i > 0; i--) {
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, changedUserIds.valueAt(i));
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
+ null /* callingPackageName */, changedUserIds.valueAt(i));
}
}
@@ -945,7 +968,7 @@ public class SyncStorageEngine {
}
authority.delayUntil = delayUntil;
}
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, info.userId);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, info);
}
/**
@@ -988,7 +1011,8 @@ public class SyncStorageEngine {
new Bundle(),
syncExemptionFlag, callingUid, callingPid);
}
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, userId);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
+ null /* callingPackageName */, userId);
mContext.sendBroadcast(ContentResolver.ACTION_SYNC_CONN_STATUS_CHANGED);
queueBackup();
}
@@ -1039,7 +1063,7 @@ public class SyncStorageEngine {
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = pendingValue;
}
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING, info.userId);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING, info);
}
/**
@@ -1129,7 +1153,7 @@ public class SyncStorageEngine {
activeSyncContext.mStartTime);
getCurrentSyncs(authorityInfo.target.userId).add(syncInfo);
}
- reportActiveChange(activeSyncContext.mSyncOperation.target.userId);
+ reportActiveChange(activeSyncContext.mSyncOperation.target);
return syncInfo;
}
@@ -1146,14 +1170,14 @@ public class SyncStorageEngine {
getCurrentSyncs(userId).remove(syncInfo);
}
- reportActiveChange(userId);
+ reportActiveChange(new EndPoint(syncInfo.account, syncInfo.authority, userId));
}
/**
* To allow others to send active change reports, to poke clients.
*/
- public void reportActiveChange(int userId) {
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE, userId);
+ public void reportActiveChange(EndPoint target) {
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE, target);
}
/**
@@ -1188,12 +1212,13 @@ public class SyncStorageEngine {
if (Log.isLoggable(TAG, Log.VERBOSE)) Slog.v(TAG, "returning historyId " + id);
}
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS, op.target.userId);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS, op.owningPackage, op.target.userId);
return id;
}
public void stopSyncEvent(long historyId, long elapsedTime, String resultMessage,
- long downstreamActivity, long upstreamActivity, int userId) {
+ long downstreamActivity, long upstreamActivity, String opPackageName,
+ int userId) {
synchronized (mAuthorities) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Slog.v(TAG, "stopSyncEvent: historyId=" + historyId);
@@ -1333,7 +1358,7 @@ public class SyncStorageEngine {
}
}
- reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS, userId);
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_STATUS, opPackageName, userId);
}
/**