Enforce permissions for calls with specified userId

Fix a couple of places where incorrect userIds were being passed in.

Change-Id: I398c676e0488ff7e584be96e96c8b32652134238
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 0f10c4f..91753aa 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -502,20 +502,28 @@
         }
     }
 
+    /**
+     * @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 0aa094f..2afeb7e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1796,6 +1796,26 @@
             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&lt;ResolveInfo&gt; 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 4e00ef9..30ca340 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.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 @@
             "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 Searchables (Context context, int userId) {
         mContext = context;
         mUserId = userId;
+        mPm = AppGlobals.getPackageManager();
     }
 
     /**
@@ -125,50 +127,50 @@
 
         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 @@
         // 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 @@
             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 @@
                     }
                 }
             }
+            Binder.restoreCallingIdentity(token);
         }
 
         List<ResolveInfo> newGlobalSearchActivities = findGlobalSearchActivities();
@@ -391,9 +396,6 @@
     }
 
     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 539e561..79dabee 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -1514,11 +1514,12 @@
                         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 9b61ec4..e45cee3 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.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 @@
             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 eee818b..6c87252 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8193,7 +8193,7 @@
             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 48a4b74..5220a7d 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1633,6 +1633,7 @@
     @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 @@
     @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 @@
     @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 @@
     @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 @@
     @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 @@
     @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 @@
     @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 @@
         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 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 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 @@
             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 @@
             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 @@
             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 @@
         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 @@
         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 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 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 562f286..19eb8d2 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -226,6 +226,12 @@
         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();