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