summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2019-01-14 20:17:05 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-01-14 20:17:05 +0000
commita7fdcc92bce9e05bc9b9044a35d28c780345917c (patch)
tree3f7c6d54b74ebc4cd4daeec62c2427909fffc2ed
parent1cf011cd7658f7f10ae5c802799a79ef91e3ec2b (diff)
parent5f63b8394904a4d7cfe1203930b7a92032bb17dd (diff)
Merge "Add new method to count how many apps have used permissions"
-rw-r--r--api/system-current.txt8
-rw-r--r--core/java/android/permission/IPermissionController.aidl1
-rw-r--r--core/java/android/permission/PermissionControllerManager.java94
-rw-r--r--core/java/android/permission/PermissionControllerService.java39
-rw-r--r--core/java/android/permission/RuntimePermissionUsageInfo.aidl19
-rw-r--r--core/java/android/permission/RuntimePermissionUsageInfo.java96
6 files changed, 257 insertions, 0 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index f6866041ec13..2428b90de9a4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4880,6 +4880,14 @@ package android.permission {
field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionPresentationInfo> CREATOR;
}
+ public final class RuntimePermissionUsageInfo implements android.os.Parcelable {
+ ctor public RuntimePermissionUsageInfo(java.lang.CharSequence, int);
+ method public int describeContents();
+ method public java.lang.CharSequence getName();
+ method public int getAppAccessCount();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionUsageInfo> CREATOR;
+ }
}
package android.permissionpresenterservice {
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 0e18b445fd01..7a7bd83089f7 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -31,4 +31,5 @@ oneway interface IPermissionController {
void revokeRuntimePermission(String packageName, String permissionName);
void countPermissionApps(in List<String> permissionNames, boolean countOnlyGranted,
boolean countSystem, in RemoteCallback callback);
+ void getPermissionUsages(boolean countSystem, long numMillis, in RemoteCallback callback);
}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index d7332ae92fb5..9744c49a5bab 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -18,6 +18,7 @@ package android.permission;
import static android.permission.PermissionControllerService.SERVICE_INTERFACE;
+import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -146,6 +147,20 @@ public final class PermissionControllerManager {
void onCountPermissionApps(int numApps);
}
+ /**
+ * Callback for delivering the result of {@link #getPermissionUsages}.
+ *
+ * @hide
+ */
+ public interface OnPermissionUsageResultCallback {
+ /**
+ * The result for {@link #getPermissionUsages}.
+ *
+ * @param users The users list.
+ */
+ void onPermissionUsageResult(@NonNull List<RuntimePermissionUsageInfo> users);
+ }
+
private final @NonNull Context mContext;
/**
@@ -264,6 +279,28 @@ public final class PermissionControllerManager {
}
/**
+ * Count how many apps have used permissions.
+ *
+ * @param countSystem Also count system apps
+ * @param numMillis The number of milliseconds in the past to check for uses
+ * @param executor Executor on which to invoke the callback
+ * @param callback Callback to receive the result
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+ public void getPermissionUsages(boolean countSystem, long numMillis,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnPermissionUsageResultCallback callback) {
+ checkArgumentNonnegative(numMillis);
+ checkNotNull(executor);
+ checkNotNull(callback);
+
+ sRemoteService.scheduleRequest(new PendingGetPermissionUsagesRequest(sRemoteService,
+ countSystem, numMillis, executor, callback));
+ }
+
+ /**
* A connection to the remote service
*/
static final class RemoteService extends
@@ -521,4 +558,61 @@ public final class PermissionControllerManager {
}
}
}
+
+ /**
+ * Request for {@link #getPermissionUsages}
+ */
+ private static final class PendingGetPermissionUsagesRequest extends
+ AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
+ private final @NonNull OnPermissionUsageResultCallback mCallback;
+ private final boolean mCountSystem;
+ private final long mNumMillis;
+
+ private final @NonNull RemoteCallback mRemoteCallback;
+
+ private PendingGetPermissionUsagesRequest(@NonNull RemoteService service,
+ boolean countSystem, long numMillis, @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnPermissionUsageResultCallback callback) {
+ super(service);
+
+ mCountSystem = countSystem;
+ mNumMillis = numMillis;
+ mCallback = callback;
+
+ mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ final List<RuntimePermissionUsageInfo> reportedUsers;
+ List<RuntimePermissionUsageInfo> users = null;
+ if (result != null) {
+ users = result.getParcelableArrayList(KEY_RESULT);
+ } else {
+ users = Collections.emptyList();
+ }
+ reportedUsers = users;
+
+ callback.onPermissionUsageResult(reportedUsers);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+
+ finish();
+ }
+ }), null);
+ }
+
+ @Override
+ protected void onTimeout(RemoteService remoteService) {
+ mCallback.onPermissionUsageResult(Collections.emptyList());
+ }
+
+ @Override
+ public void run() {
+ try {
+ getService().getServiceInterface().getPermissionUsages(mCountSystem, mNumMillis,
+ mRemoteCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error counting permission users", e);
+ }
+ }
+ }
}
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index f621737e5ed4..75d61e6fe570 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -17,6 +17,7 @@
package android.permission;
import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -112,6 +113,17 @@ public abstract class PermissionControllerService extends Service {
public abstract int onCountPermissionApps(@NonNull List<String> permissionNames,
boolean countOnlyGranted, boolean countSystem);
+ /**
+ * Count how many apps have used permissions.
+ *
+ * @param countSystem Also count system apps
+ * @param numMillis The number of milliseconds in the past to check for uses
+ *
+ * @return descriptions of the users of permissions
+ */
+ public abstract @NonNull List<RuntimePermissionUsageInfo>
+ onPermissionUsageResult(boolean countSystem, long numMillis);
+
@Override
public final IBinder onBind(Intent intent) {
return new IPermissionController.Stub() {
@@ -187,6 +199,20 @@ public abstract class PermissionControllerService extends Service {
PermissionControllerService.this, permissionNames, countOnlyGranted,
countSystem, callback));
}
+
+ @Override
+ public void getPermissionUsages(boolean countSystem, long numMillis,
+ RemoteCallback callback) {
+ checkArgumentNonnegative(numMillis);
+ checkNotNull(callback, "callback");
+
+ enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+
+ mHandler.sendMessage(
+ obtainMessage(PermissionControllerService::getPermissionUsages,
+ PermissionControllerService.this, countSystem, numMillis,
+ callback));
+ }
};
}
@@ -230,4 +256,17 @@ public abstract class PermissionControllerService extends Service {
result.putInt(PermissionControllerManager.KEY_RESULT, numApps);
callback.sendResult(result);
}
+
+ private void getPermissionUsages(boolean countSystem, long numMillis,
+ @NonNull RemoteCallback callback) {
+ List<RuntimePermissionUsageInfo> users =
+ onPermissionUsageResult(countSystem, numMillis);
+ if (users != null && !users.isEmpty()) {
+ Bundle result = new Bundle();
+ result.putParcelableList(PermissionControllerManager.KEY_RESULT, users);
+ callback.sendResult(result);
+ } else {
+ callback.sendResult(null);
+ }
+ }
}
diff --git a/core/java/android/permission/RuntimePermissionUsageInfo.aidl b/core/java/android/permission/RuntimePermissionUsageInfo.aidl
new file mode 100644
index 000000000000..88820ddbc092
--- /dev/null
+++ b/core/java/android/permission/RuntimePermissionUsageInfo.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+parcelable RuntimePermissionUsageInfo; \ No newline at end of file
diff --git a/core/java/android/permission/RuntimePermissionUsageInfo.java b/core/java/android/permission/RuntimePermissionUsageInfo.java
new file mode 100644
index 000000000000..af1a1bec37cf
--- /dev/null
+++ b/core/java/android/permission/RuntimePermissionUsageInfo.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains information about how a runtime permission
+ * is used. A single runtime permission presented to the user may
+ * correspond to multiple platform defined permissions, e.g. the
+ * location permission may control both the coarse and fine platform
+ * permissions.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RuntimePermissionUsageInfo implements Parcelable {
+ private final @NonNull CharSequence mName;
+ private final int mNumUsers;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param name The permission group name.
+ * @param numUsers The number of apps that have used this permission.
+ */
+ public RuntimePermissionUsageInfo(@NonNull CharSequence name, int numUsers) {
+ checkNotNull(name);
+ checkArgumentNonnegative(numUsers);
+
+ mName = name;
+ mNumUsers = numUsers;
+ }
+
+ private RuntimePermissionUsageInfo(Parcel parcel) {
+ this(parcel.readCharSequence(), parcel.readInt());
+ }
+
+ /**
+ * @return The number of apps that accessed this permission
+ */
+ public int getAppAccessCount() {
+ return mNumUsers;
+ }
+
+ /**
+ * Gets the permission group name.
+ *
+ * @return The name.
+ */
+ public @NonNull CharSequence getName() {
+ return mName;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeCharSequence(mName);
+ parcel.writeInt(mNumUsers);
+ }
+
+ public static final Creator<RuntimePermissionUsageInfo> CREATOR =
+ new Creator<RuntimePermissionUsageInfo>() {
+ public RuntimePermissionUsageInfo createFromParcel(Parcel source) {
+ return new RuntimePermissionUsageInfo(source);
+ }
+
+ public RuntimePermissionUsageInfo[] newArray(int size) {
+ return new RuntimePermissionUsageInfo[size];
+ }
+ };
+}