Add new API to retrieve app names in a batch

Change-Id: I57e5c132bc58a32d70007a7a105775b526ff7bb9
Fixes: 62805090
Test: cts-tradefed run commandAndExit cts-dev -m CtsContentTestCases -t android.content.pm.cts.PackageManagerTest#testGetNamesForUids_null
Test: cts-tradefed run commandAndExit cts-dev -m CtsContentTestCases -t android.content.pm.cts.PackageManagerTest#testGetNamesForUids_empty
Test: cts-tradefed run commandAndExit cts-dev -m CtsContentTestCases -t android.content.pm.cts.PackageManagerTest#testGetNamesForUids_valid
diff --git a/api/current.txt b/api/current.txt
index b4c6089..f2381d5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41049,6 +41049,7 @@
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
+    method public java.lang.String[] getNamesForUids(int[]);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
diff --git a/api/system-current.txt b/api/system-current.txt
index 57bf4b4..8bed3e7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -44696,6 +44696,7 @@
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
+    method public java.lang.String[] getNamesForUids(int[]);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
diff --git a/api/test-current.txt b/api/test-current.txt
index 52a659e..0305c65 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -41303,6 +41303,7 @@
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
+    method public java.lang.String[] getNamesForUids(int[]);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7fc9a69..0eafdec 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -31,7 +31,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ChangedPackages;
 import android.content.pm.ComponentInfo;
-import android.content.pm.InstantAppInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IOnPermissionsChangeListener;
 import android.content.pm.IPackageDataObserver;
@@ -40,6 +39,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstantAppInfo;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
@@ -88,13 +88,14 @@
 import android.util.Log;
 import android.view.Display;
 
-import dalvik.system.VMRuntime;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.UserIcons;
+
+import dalvik.system.VMRuntime;
+
 import libcore.util.EmptyArray;
 
 import java.lang.ref.WeakReference;
@@ -706,6 +707,15 @@
     }
 
     @Override
+    public String[] getNamesForUids(int[] uids) {
+        try {
+            return mPM.getNamesForUids(uids);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public int getUidForSharedUser(String sharedUserName)
             throws NameNotFoundException {
         try {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 64d687e..6990d6d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -61,6 +61,12 @@
  *  {@hide}
  */
 interface IPackageManager {
+    // Since these transactions are also called from native code, these must be kept in sync with
+    // the ones in frameworks/native/include/binder/IPackageManager.h
+    // =============== Beginning of transactions used on native side as well ======================
+    String[] getNamesForUids(in int[] uids);
+    // =============== End of transactions used on native side as well ============================
+
     void checkPackageStartable(String packageName, int userId);
     boolean isPackageAvailable(String packageName, int userId);
     PackageInfo getPackageInfo(String packageName, int flags, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 175293d..f6eaed4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3590,6 +3590,14 @@
     public abstract @Nullable String getNameForUid(int uid);
 
     /**
+     * Retrieves the official names associated with each given uid.
+     * @see #getNameForUid(int)
+     *
+     * @hide
+     */
+    public abstract @Nullable String[] getNamesForUids(int[] uids);
+
+    /**
      * Return the user id associated with a shared user name. Multiple
      * applications can specify a shared user name in their manifest and thus
      * end up using a common uid. This might be used for new applications
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 815d871..4f097b8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6397,18 +6397,41 @@
             return null;
         }
         synchronized (mPackages) {
-            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
-            if (obj instanceof SharedUserSetting) {
-                final SharedUserSetting sus = (SharedUserSetting) obj;
-                return sus.name + ":" + sus.userId;
-            } else if (obj instanceof PackageSetting) {
-                final PackageSetting ps = (PackageSetting) obj;
-                if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
-                    return null;
-                }
-                return ps.name;
+            return getNameForUidLocked(callingUid, uid);
+        }
+    }
+
+    @Override
+    public String[] getNamesForUids(int[] uids) {
+        if (uids == null || uids.length == 0) {
+            return null;
+        }
+        final int callingUid = Binder.getCallingUid();
+        if (getInstantAppPackageName(callingUid) != null) {
+            return null;
+        }
+        final String[] names = new String[uids.length];
+        synchronized (mPackages) {
+            for (int i = uids.length - 1; i >= 0; i--) {
+                final int uid = uids[i];
+                names[i] = getNameForUidLocked(callingUid, uid);
             }
         }
+        return names;
+    }
+
+    private String getNameForUidLocked(int callingUid, int uid) {
+        Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
+        if (obj instanceof SharedUserSetting) {
+            final SharedUserSetting sus = (SharedUserSetting) obj;
+            return sus.name + ":" + sus.userId;
+        } else if (obj instanceof PackageSetting) {
+            final PackageSetting ps = (PackageSetting) obj;
+            if (filterAppAccessLPr(ps, callingUid, UserHandle.getUserId(callingUid))) {
+                return null;
+            }
+            return ps.name;
+        }
         return null;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
index 45b107d..0e940f2 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
@@ -275,6 +275,11 @@
     }
 
     @Override
+    public String[] getNamesForUids(int uid[]) {
+        return null;
+    }
+
+    @Override
     public int getUidForSharedUser(String sharedUserName)
             throws NameNotFoundException {
         return 0;
diff --git a/test-runner/api/android-test-mock-current.txt b/test-runner/api/android-test-mock-current.txt
index 4063ed7..93bbf6c 100644
--- a/test-runner/api/android-test-mock-current.txt
+++ b/test-runner/api/android-test-mock-current.txt
@@ -292,6 +292,7 @@
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public int getMoveStatus(int);
     method public java.lang.String getNameForUid(int);
+    method public java.lang.String[] getNamesForUids(int[]);
     method public java.util.List<android.os.storage.VolumeInfo> getPackageCandidateVolumes(android.content.pm.ApplicationInfo);
     method public android.os.storage.VolumeInfo getPackageCurrentVolume(android.content.pm.ApplicationInfo);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 3cb1f39..68fd825 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -321,6 +321,11 @@
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public String[] getNamesForUids(int uid[]) {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * @hide - to match hiding in superclass
      */