From e799175b6ba3aadd972f4b861758d675d1f93987 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 16 Jan 2013 17:56:46 -0800 Subject: [PATCH] AppOps: fix nested op tracking, new API to get apps using permissions. Change-Id: I20c7bd58febc01d6911a90440867eaacd133c464 --- api/current.txt | 2 + .../app/ApplicationPackageManager.java | 22 ++++++ .../android/content/pm/IPackageManager.aidl | 9 +++ .../android/content/pm/PackageManager.java | 38 ++++++++++- .../com/android/server/AppOpsService.java | 1 + .../server/pm/PackageManagerService.java | 68 +++++++++++++++++++ .../android/test/mock/MockPackageManager.java | 6 ++ 7 files changed, 143 insertions(+), 3 deletions(-) diff --git a/api/current.txt b/api/current.txt index 71b6b14f776ab..ac367f657d643 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6592,6 +6592,7 @@ package android.content.pm { method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String[] getPackagesForUid(int); + method public abstract java.util.List getPackagesHoldingPermissions(java.lang.String[], int); method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PermissionInfo getPermissionInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract int getPreferredActivities(java.util.List, java.util.List, java.lang.String); @@ -21689,6 +21690,7 @@ package android.test.mock { method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] getPackagesForUid(int); + method public java.util.List getPackagesHoldingPermissions(java.lang.String[], int); method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PermissionInfo getPermissionInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public int getPreferredActivities(java.util.List, java.util.List, java.lang.String); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 03d1a3f3fec34..2ef39443e5e96 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -442,6 +442,28 @@ final class ApplicationPackageManager extends PackageManager { } } + @SuppressWarnings("unchecked") + @Override + public List getPackagesHoldingPermissions( + String[] permissions, int flags) { + final int userId = mContext.getUserId(); + try { + final List packageInfos = new ArrayList(); + PackageInfo lastItem = null; + ParceledListSlice slice; + + do { + final String lastKey = lastItem != null ? lastItem.packageName : null; + slice = mPM.getPackagesHoldingPermissions(permissions, flags, lastKey, userId); + lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR); + } while (!slice.isLastSlice()); + + return packageInfos; + } catch (RemoteException e) { + throw new RuntimeException("Package manager has died", e); + } + } + @SuppressWarnings("unchecked") @Override public List getInstalledApplications(int flags) { diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index b9e432c120fbf..4c9c278a718ee 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -129,6 +129,15 @@ interface IPackageManager { */ ParceledListSlice getInstalledPackages(int flags, in String lastRead, in int userId); + /** + * This implements getPackagesHoldingPermissions via a "last returned row" + * mechanism that is not exposed in the API. This is to get around the IPC + * limit that kicks in when flags are included that bloat up the data + * returned. + */ + ParceledListSlice getPackagesHoldingPermissions(in String[] permissions, + int flags, in String lastRead, int userId); + /** * This implements getInstalledApplications via a "last returned row" * mechanism that is not exposed in the API. This is to get around the IPC diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index cdd91951387c2..a69f2202ca287 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1512,10 +1512,42 @@ public abstract class PackageManager { * @see #GET_SERVICES * @see #GET_SIGNATURES * @see #GET_UNINSTALLED_PACKAGES - * */ public abstract List getInstalledPackages(int flags); + /** + * Return a List of all installed packages that are currently + * holding any of the given permissions. + * + * @param flags Additional option flags. Use any combination of + * {@link #GET_ACTIVITIES}, + * {@link #GET_GIDS}, + * {@link #GET_CONFIGURATIONS}, + * {@link #GET_INSTRUMENTATION}, + * {@link #GET_PERMISSIONS}, + * {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, + * {@link #GET_SERVICES}, + * {@link #GET_SIGNATURES}, + * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. + * + * @return Returns a List of PackageInfo objects, one for each installed + * application that is holding any of the permissions that were provided. + * + * @see #GET_ACTIVITIES + * @see #GET_GIDS + * @see #GET_CONFIGURATIONS + * @see #GET_INSTRUMENTATION + * @see #GET_PERMISSIONS + * @see #GET_PROVIDERS + * @see #GET_RECEIVERS + * @see #GET_SERVICES + * @see #GET_SIGNATURES + * @see #GET_UNINSTALLED_PACKAGES + */ + public abstract List getPackagesHoldingPermissions( + String[] permissions, int flags); + /** * Return a List of all packages that are installed on the device, for a specific user. * Requesting a list of installed packages for another user @@ -1742,14 +1774,14 @@ public abstract class PackageManager { /** * Return a List of all application packages that are installed on the * device. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all - * applications including those deleted with DONT_DELETE_DATA(partially + * applications including those deleted with DONT_DELETE_DATA (partially * installed apps with data directory) will be returned. * * @param flags Additional option flags. Use any combination of * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. * - * @return A List of ApplicationInfo objects, one for each application that + * @return Returns a List of ApplicationInfo objects, one for each application that * is installed on the device. In the unlikely case of there being * no installed applications, an empty list is returned. * If flag GET_UNINSTALLED_PACKAGES is set, a list of all diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java index aff994c147328..17128062b0a10 100644 --- a/services/java/com/android/server/AppOpsService.java +++ b/services/java/com/android/server/AppOpsService.java @@ -233,6 +233,7 @@ public class AppOpsService extends IAppOpsService.Stub { + " code " + code + " time=" + op.time + " duration=" + op.duration + " nesting=" + op.nesting); } + op.nesting = 0; } else { op.nesting--; } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 2238f17621f1c..d2a330ffd8e62 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -2943,6 +2943,74 @@ public class PackageManagerService extends IPackageManager.Stub { return list; } + @Override + public ParceledListSlice getPackagesHoldingPermissions( + String[] permissions, int flags, String lastRead, int userId) { + if (!sUserManager.exists(userId)) return null; + final ParceledListSlice list = new ParceledListSlice(); + final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + + // writer + synchronized (mPackages) { + ArrayList keysList = new ArrayList(); + if (listUninstalled) { + for (PackageSetting ps : mSettings.mPackages.values()) { + for (String perm : permissions) { + if (ps.grantedPermissions.contains(perm)) { + keysList.add(ps.name); + break; + } + } + } + } else { + for (PackageParser.Package pkg : mPackages.values()) { + PackageSetting ps = (PackageSetting)pkg.mExtras; + if (ps != null) { + for (String perm : permissions) { + if (ps.grantedPermissions.contains(perm)) { + keysList.add(ps.name); + break; + } + } + } + } + } + + String[] keys = new String[keysList.size()]; + keysList.toArray(keys); + Arrays.sort(keys); + int i = getContinuationPoint(keys, lastRead); + final int N = keys.length; + + while (i < N) { + final String packageName = keys[i++]; + + PackageInfo pi = null; + if (listUninstalled) { + final PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps != null) { + pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId); + } + } else { + final PackageParser.Package p = mPackages.get(packageName); + if (p != null) { + pi = generatePackageInfo(p, flags, userId); + } + } + + if (pi != null && list.append(pi)) { + break; + } + } + + if (i == N) { + list.setLastSlice(true); + } + } + + return list; + } + @Override public ParceledListSlice getInstalledApplications(int flags, String lastRead, int userId) { diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 5ee52de0a32db..20a26ab86a01b 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -146,6 +146,12 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + @Override + public List getPackagesHoldingPermissions(String[] permissions, + int flags) { + throw new UnsupportedOperationException(); + } + /** @hide */ @Override public List getInstalledPackages(int flags, int userId) {