diff options
8 files changed, 134 insertions, 57 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 0f10c4f10cd4..91753aaff89f 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -502,20 +502,28 @@ final class ApplicationPackageManager extends PackageManager { } } + /** + * @hide + */ @Override - public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) { + public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) { try { return mPM.queryIntentReceivers( intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, - UserHandle.myUserId()); + userId); } catch (RemoteException e) { throw new RuntimeException("Package manager has died", e); } } @Override + public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) { + return queryBroadcastReceivers(intent, flags, UserHandle.myUserId()); + } + + @Override public ResolveInfo resolveService(Intent intent, int flags) { try { return mPM.resolveService( diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 0aa094f6dc1c..2afeb7e7dd65 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1796,6 +1796,26 @@ public abstract class PackageManager { int flags); /** + * Retrieve all receivers that can handle a broadcast of the given intent, for a specific + * user. + * + * @param intent The desired intent as per resolveActivity(). + * @param flags Additional option flags. + * @param userId The userId of the user being queried. + * + * @return A List<ResolveInfo> containing one entry for each matching + * Receiver. These are ordered from first to last in priority. If + * there are no matching receivers, an empty list is returned. + * + * @see #MATCH_DEFAULT_ONLY + * @see #GET_INTENT_FILTERS + * @see #GET_RESOLVED_FILTER + * @hide + */ + public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent, + int flags, int userId); + + /** * Determine the best service to handle for a given Intent. * * @param intent An intent containing all of the desired specification diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java index 4e00ef92d992..30ca340361ff 100644 --- a/core/java/android/server/search/Searchables.java +++ b/core/java/android/server/search/Searchables.java @@ -27,6 +27,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.provider.Settings; @@ -70,7 +71,7 @@ public class Searchables { "com.google.android.providers.enhancedgooglesearch/.Launcher"; // Cache the package manager instance - private IPackageManager mPm; + final private IPackageManager mPm; // User for which this Searchables caches information private int mUserId; @@ -81,6 +82,7 @@ public class Searchables { public Searchables (Context context, int userId) { mContext = context; mUserId = userId; + mPm = AppGlobals.getPackageManager(); } /** @@ -125,50 +127,50 @@ public class Searchables { ActivityInfo ai = null; try { - ai = mContext.getPackageManager(). - getActivityInfo(activity, PackageManager.GET_META_DATA ); - String refActivityName = null; + ai = mPm.getActivityInfo(activity, PackageManager.GET_META_DATA, mUserId); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error getting activity info " + re); + return null; + } + String refActivityName = null; - // First look for activity-specific reference - Bundle md = ai.metaData; + // First look for activity-specific reference + Bundle md = ai.metaData; + if (md != null) { + refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); + } + // If not found, try for app-wide reference + if (refActivityName == null) { + md = ai.applicationInfo.metaData; if (md != null) { refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); } - // If not found, try for app-wide reference - if (refActivityName == null) { - md = ai.applicationInfo.metaData; - if (md != null) { - refActivityName = md.getString(MD_LABEL_DEFAULT_SEARCHABLE); - } - } + } - // Irrespective of source, if a reference was found, follow it. - if (refActivityName != null) - { - // This value is deprecated, return null - if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) { - return null; - } - String pkg = activity.getPackageName(); - ComponentName referredActivity; - if (refActivityName.charAt(0) == '.') { - referredActivity = new ComponentName(pkg, pkg + refActivityName); - } else { - referredActivity = new ComponentName(pkg, refActivityName); - } + // Irrespective of source, if a reference was found, follow it. + if (refActivityName != null) + { + // This value is deprecated, return null + if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) { + return null; + } + String pkg = activity.getPackageName(); + ComponentName referredActivity; + if (refActivityName.charAt(0) == '.') { + referredActivity = new ComponentName(pkg, pkg + refActivityName); + } else { + referredActivity = new ComponentName(pkg, refActivityName); + } - // Now try the referred activity, and if found, cache - // it against the original name so we can skip the check - synchronized (this) { - result = mSearchablesMap.get(referredActivity); - if (result != null) { - mSearchablesMap.put(activity, result); - return result; - } + // Now try the referred activity, and if found, cache + // it against the original name so we can skip the check + synchronized (this) { + result = mSearchablesMap.get(referredActivity); + if (result != null) { + mSearchablesMap.put(activity, result); + return result; } } - } catch (PackageManager.NameNotFoundException e) { - // case 3: no metadata } // Step 3. None found. Return null. @@ -208,6 +210,7 @@ public class Searchables { // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers. List<ResolveInfo> searchList; final Intent intent = new Intent(Intent.ACTION_SEARCH); + searchList = queryIntentActivities(intent, PackageManager.GET_META_DATA); List<ResolveInfo> webSearchInfoList; @@ -219,6 +222,7 @@ public class Searchables { int search_count = (searchList == null ? 0 : searchList.size()); int web_search_count = (webSearchInfoList == null ? 0 : webSearchInfoList.size()); int count = search_count + web_search_count; + long token = Binder.clearCallingIdentity(); for (int ii = 0; ii < count; ii++) { // for each component, try to find metadata ResolveInfo info = (ii < search_count) @@ -237,6 +241,7 @@ public class Searchables { } } } + Binder.restoreCallingIdentity(token); } List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities(); @@ -391,9 +396,6 @@ public class Searchables { } private List<ResolveInfo> queryIntentActivities(Intent intent, int flags) { - if (mPm == null) { - mPm = AppGlobals.getPackageManager(); - } List<ResolveInfo> activities = null; try { activities = diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index 539e5612ed64..79dabee4be6d 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -1514,11 +1514,12 @@ class AppWidgetServiceImpl { String pkg = parser.getAttributeValue(null, "pkg"); String cl = parser.getAttributeValue(null, "cl"); - final PackageManager packageManager = mContext.getPackageManager(); + final IPackageManager packageManager = AppGlobals.getPackageManager(); try { - packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0); - } catch (PackageManager.NameNotFoundException e) { - String[] pkgs = packageManager + packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0, + UserHandle.getCallingUserId()); + } catch (RemoteException e) { + String[] pkgs = mContext.getPackageManager() .currentToCanonicalPackageNames(new String[] { pkg }); pkg = pkgs[0]; } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 9b61ec480bd7..e45cee30c3a4 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -21,6 +21,7 @@ import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.app.ActivityManagerNative; +import android.app.AppGlobals; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; @@ -1313,14 +1314,14 @@ public class NotificationManagerService extends INotificationManager.Stub return; } try { - ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo( - pkg, 0); + ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( + pkg, 0, UserHandle.getCallingUserId()); if (!UserHandle.isSameApp(ai.uid, uid)) { throw new SecurityException("Calling uid " + uid + " gave package" + pkg + " which is owned by uid " + ai.uid); } - } catch (PackageManager.NameNotFoundException e) { - throw new SecurityException("Unknown package " + pkg); + } catch (RemoteException re) { + throw new SecurityException("Unknown package " + pkg + "\n" + re); } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index eee818b652ad..6c87252dcb61 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -8193,7 +8193,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (String pkg : process.pkgList) { sb.append("Package: ").append(pkg); try { - PackageInfo pi = pm.getPackageInfo(pkg, 0, 0); + PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId()); if (pi != null) { sb.append(" v").append(pi.versionCode); if (pi.versionName != null) { diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 48a4b74cd160..5220a7d20169 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -1633,6 +1633,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public PackageInfo getPackageInfo(String packageName, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package info"); // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1675,6 +1676,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public int getPackageUid(String packageName, int userId) { if (!sUserManager.exists(userId)) return -1; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get package uid"); // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1831,6 +1833,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get application info"); // writer synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1910,6 +1913,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get activity info"); synchronized (mPackages) { PackageParser.Activity a = mActivities.mActivities.get(component); @@ -1930,6 +1934,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get receiver info"); synchronized (mPackages) { PackageParser.Activity a = mReceivers.mActivities.get(component); if (DEBUG_PACKAGE_INFO) Log.v( @@ -1947,6 +1952,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get service info"); synchronized (mPackages) { PackageParser.Service s = mServices.mServices.get(component); if (DEBUG_PACKAGE_INFO) Log.v( @@ -1964,6 +1970,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get provider info"); synchronized (mPackages) { PackageParser.Provider p = mProvidersByComponent.get(component); if (DEBUG_PACKAGE_INFO) Log.v( @@ -2065,6 +2072,34 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.PERMISSION_DENIED; } + /** + * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS + * or INTERACT_ACROSS_USERS_FULL permissions, if the userid is not for the caller. + * @param message the message to log on security exception + * @return + */ + private void enforceCrossUserPermission(int callingUid, int userId, + boolean requireFullPermission, String message) { + if (userId < 0) { + throw new IllegalArgumentException("Invalid userId " + userId); + } + if (userId == UserHandle.getUserId(callingUid)) return; + if (callingUid != Process.SYSTEM_UID && callingUid != 0) { + if (requireFullPermission) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); + } else { + try { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); + } catch (SecurityException se) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS, message); + } + } + } + } + private BasePermission findPermissionTreeLP(String permName) { for(BasePermission bp : mSettings.mPermissionTrees.values()) { if (permName.startsWith(bp.name) && @@ -2397,6 +2432,7 @@ public class PackageManagerService extends IPackageManager.Stub { public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "resolve intent"); List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId); return chooseBestActivity(intent, resolvedType, flags, query, userId); } @@ -2538,6 +2574,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities"); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { @@ -2577,6 +2614,8 @@ public class PackageManagerService extends IPackageManager.Stub { Intent[] specifics, String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return null; + enforceCrossUserPermission(Binder.getCallingUid(), userId, false, + "query intent activity options"); final String resultsAction = intent.getAction(); List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags @@ -8230,7 +8269,7 @@ public class PackageManagerService extends IPackageManager.Stub { final IPackageDataObserver observer, final int userId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_USER_DATA, null); - checkValidCaller(Binder.getCallingUid(), userId); + enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "clear application data"); // Queue up an async operation since the package deletion may take a little while. mHandler.post(new Runnable() { public void run() { @@ -8462,7 +8501,7 @@ public class PackageManagerService extends IPackageManager.Stub { ComponentName[] set, ComponentName activity, int userId) { // writer int callingUid = Binder.getCallingUid(); - checkValidCaller(callingUid, userId); + enforceCrossUserPermission(callingUid, userId, true, "add preferred activity"); synchronized (mPackages) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) @@ -8652,7 +8691,7 @@ public class PackageManagerService extends IPackageManager.Stub { final int uid = Binder.getCallingUid(); final int permission = mContext.checkCallingPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); - checkValidCaller(uid, userId); + enforceCrossUserPermission(uid, userId, false, "set enabled"); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); boolean sendNow = false; boolean isApp = (className == null); @@ -8780,7 +8819,7 @@ public class PackageManagerService extends IPackageManager.Stub { final int permission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); - checkValidCaller(uid, userId); + enforceCrossUserPermission(uid, userId, true, "stop package"); // writer synchronized (mPackages) { if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission, @@ -8801,7 +8840,7 @@ public class PackageManagerService extends IPackageManager.Stub { public int getApplicationEnabledSetting(String packageName, int userId) { if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int uid = Binder.getCallingUid(); - checkValidCaller(uid, userId); + enforceCrossUserPermission(uid, userId, false, "get enabled"); // reader synchronized (mPackages) { return mSettings.getApplicationEnabledSettingLPr(packageName, userId); @@ -8812,7 +8851,7 @@ public class PackageManagerService extends IPackageManager.Stub { public int getComponentEnabledSetting(ComponentName componentName, int userId) { if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int uid = Binder.getCallingUid(); - checkValidCaller(uid, userId); + enforceCrossUserPermission(uid, userId, false, "get component enabled"); // reader synchronized (mPackages) { return mSettings.getComponentEnabledSettingLPr(componentName, userId); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 562f2863ae2b..19eb8d2ef5fd 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -226,6 +226,12 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) { + throw new UnsupportedOperationException(); + } + @Override public ResolveInfo resolveService(Intent intent, int flags) { throw new UnsupportedOperationException(); |