summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Svet Ganov <svetoslavganov@google.com> 2021-04-17 06:58:37 +0000
committer Svet Ganov <svetoslavganov@google.com> 2021-04-22 23:37:32 +0000
commit39c075301a36b8f2280c3e3ede5fad4816d1ebc7 (patch)
tree266e0f03c343abbb7eb7db513af70c89db4282dd
parentf45fd103bf2ef1ae7b528daf67cbcb487b1a5045 (diff)
Prepare AttributionSource to expose to native - native
Separate the internal state of AttributionSource from the class to make it a simple AIDL we can translate automatically to native - keeping Java and native parts in sync. This would allow writing a thin native lib for checking attribution source permissions which would be used to teach camera and audio about attributions. Deinfe an AIDL interface for passing around an attribution source and opr performing permission checker oprations allowing native and Java permission checks on attribution chains to be handled. The Java side permission checker functions are in a dedicated permisison checker service on top of which sits the PermissionChecker. We expose similar PermissionChecker native APIs sitting on top of the same remote interface. The nice thing is that we have native and Java permisison checkers in sync sharing remoting code and being close in shape. For now the PermissionChecker in Java is divorced from the PermissionManager but in T we will consider how to unify them, either by an extension object on the PermmissionManager or APIs on the PermissionManager, or another approach, and then migrate clients off the PermissionChecker APIs. bug: 158792096 Test: atest CtsPermission5TestCases Change-Id: I16740cc2d3feae731ffbfeb98f045aa9a71ff771
-rw-r--r--libs/permission/Android.bp27
-rw-r--r--libs/permission/aidl/android/content/AttributionSourceState.aidl40
-rw-r--r--libs/permission/aidl/android/permission/IPermissionChecker.aidl37
-rw-r--r--libs/permission/android/permission/PermissionChecker.cpp114
-rw-r--r--libs/permission/include/android/permission/PermissionChecker.h136
5 files changed, 353 insertions, 1 deletions
diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp
index a5712b319f..1ae0a001a3 100644
--- a/libs/permission/Android.bp
+++ b/libs/permission/Android.bp
@@ -7,17 +7,42 @@ package {
default_applicable_licenses: ["frameworks_native_license"],
}
+aidl_interface {
+ name: "framework-permission-aidl",
+ unstable: true,
+ local_include_dir: "aidl",
+ backend: {
+ ndk: {
+ enabled: false
+ }
+ },
+ srcs: [
+ "aidl/android/content/AttributionSourceState.aidl",
+ "aidl/android/permission/IPermissionChecker.aidl",
+ ],
+}
+
cc_library_shared {
name: "libpermission",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
srcs: [
"AppOpsManager.cpp",
"IAppOpsCallback.cpp",
"IAppOpsService.cpp",
+ "android/permission/PermissionChecker.cpp",
],
export_include_dirs: ["include"],
shared_libs: [
+ "libutils",
"libbinder",
+ "libcutils",
"liblog",
- "libutils",
+ ],
+ static_libs: [
+ "framework-permission-aidl-cpp",
],
}
diff --git a/libs/permission/aidl/android/content/AttributionSourceState.aidl b/libs/permission/aidl/android/content/AttributionSourceState.aidl
new file mode 100644
index 0000000000..b6e54bf153
--- /dev/null
+++ b/libs/permission/aidl/android/content/AttributionSourceState.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 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.content;
+
+/**
+ * Payload for the {@link AttributionSource} class needed to interoperate
+ * with different languages.
+ *
+ * {@hide}
+ */
+parcelable AttributionSourceState {
+ /** The UID that is accessing the permission protected data. */
+ int uid;
+ /** The package that is accessing the permission protected data. */
+ @nullable @utf8InCpp String packageName;
+ /** The attribution tag of the app accessing the permission protected data. */
+ @nullable @utf8InCpp String attributionTag;
+ /** Unique token for that source. */
+ @nullable IBinder token;
+ /** Permissions that should be considered revoked regardless if granted. */
+ @nullable @utf8InCpp String[] renouncedPermissions;
+ /** The next app to receive the permission protected data. */
+ // TODO: We use an array as a workaround - the C++ backend doesn't
+ // support referring to the parcelable as it expects ctor/dtor
+ @nullable AttributionSourceState[] next;
+}
diff --git a/libs/permission/aidl/android/permission/IPermissionChecker.aidl b/libs/permission/aidl/android/permission/IPermissionChecker.aidl
new file mode 100644
index 0000000000..1f0e32d248
--- /dev/null
+++ b/libs/permission/aidl/android/permission/IPermissionChecker.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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 android.content.AttributionSourceState;
+
+/**
+ * Interface to communicate directly with the permission checker service.
+ */
+interface IPermissionChecker {
+ const int PERMISSION_GRANTED = 0;
+ const int PERMISSION_SOFT_DENIED = 1;
+ const int PERMISSION_HARD_DENIED = 2;
+
+ int checkPermission(String permission, in AttributionSourceState attributionSource,
+ @nullable String message, boolean forDataDelivery, boolean startDataDelivery,
+ boolean fromDatasource);
+
+ void finishDataDelivery(String op, in AttributionSourceState attributionSource);
+
+ int checkOp(int op, in AttributionSourceState attributionSource,
+ String message, boolean forDataDelivery, boolean startDataDelivery);
+}
diff --git a/libs/permission/android/permission/PermissionChecker.cpp b/libs/permission/android/permission/PermissionChecker.cpp
new file mode 100644
index 0000000000..a8083ee410
--- /dev/null
+++ b/libs/permission/android/permission/PermissionChecker.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <mutex>
+#include <include/android/permission/PermissionChecker.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+#include <sys/types.h>
+#include <private/android_filesystem_config.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "PermissionChecker"
+
+namespace android {
+
+using android::content::AttributionSourceState;
+
+PermissionChecker::PermissionChecker()
+{
+}
+
+sp<IPermissionChecker> PermissionChecker::getService()
+{
+ static String16 permission_checker("permission_checker");
+
+ std::lock_guard<Mutex> scoped_lock(mLock);
+ int64_t startTime = 0;
+ sp<IPermissionChecker> service = mService;
+ while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
+ sp<IBinder> binder = defaultServiceManager()->checkService(permission_checker);
+ if (binder == nullptr) {
+ // Wait for the permission checker service to come back...
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ ALOGW("Waiting for permission checker service");
+ } else if ((uptimeMillis() - startTime) > 10000) {
+ ALOGE("Waiting too long for permission checker service, giving up");
+ service = nullptr;
+ break;
+ }
+ sleep(1);
+ } else {
+ mService = interface_cast<IPermissionChecker>(binder);
+ }
+ }
+ return mService;
+}
+
+PermissionChecker::PermissionResult
+ PermissionChecker::checkPermissionForDataDeliveryFromDatasource(
+ const String16& permission, AttributionSourceState& attributionSource,
+ const String16& message)
+{
+ return static_cast<PermissionResult>(checkPermission(permission, attributionSource, message,
+ /*forDataDelivery*/ true, /*startDataDelivery*/ false,/*fromDatasource*/ true));
+}
+
+PermissionChecker::PermissionResult
+ PermissionChecker::checkPermissionForStartDataDeliveryFromDatasource(
+ const String16& permission, AttributionSourceState& attributionSource,
+ const String16& message)
+{
+ return static_cast<PermissionResult>(checkPermission(permission, attributionSource, message,
+ /*forDataDelivery*/ true, /*startDataDelivery*/ true, /*fromDatasource*/ true));
+}
+
+void PermissionChecker::finishDataDelivery(const String16& op,
+ AttributionSourceState& attributionSource)
+{
+ sp<IPermissionChecker> service = getService();
+ if (service != nullptr) {
+ binder::Status status = service->finishDataDelivery(op, attributionSource);
+ if (!status.isOk()) {
+ ALOGE("finishDataDelivery failed: %s", status.exceptionMessage().c_str());
+ }
+ }
+}
+
+int32_t PermissionChecker::checkPermission(const String16& permission,
+ AttributionSourceState& attributionSource, const String16& message,
+ bool forDataDelivery, bool startDataDelivery, bool fromDatasource)
+{
+ sp<IPermissionChecker> service = getService();
+ if (service != nullptr) {
+ int32_t result;
+ binder::Status status = service->checkPermission(permission, attributionSource, message,
+ forDataDelivery, startDataDelivery, fromDatasource, &result);
+ if (status.isOk()) {
+ return result;
+ }
+ ALOGE("checkPermission failed: %s", status.exceptionMessage().c_str());
+ }
+ return PERMISSION_DENIED;
+}
+
+} // namespace android
diff --git a/libs/permission/include/android/permission/PermissionChecker.h b/libs/permission/include/android/permission/PermissionChecker.h
new file mode 100644
index 0000000000..20ab51fc8a
--- /dev/null
+++ b/libs/permission/include/android/permission/PermissionChecker.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#include <android/content/AttributionSourceState.h>
+#include <android/permission/IPermissionChecker.h>
+
+#include <utils/threads.h>
+
+#include <optional>
+
+#ifdef __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+using android::content::AttributionSourceState;
+using android::permission::IPermissionChecker;
+
+class PermissionChecker
+{
+public:
+
+ enum PermissionResult {
+
+ /**
+ * The permission is granted.
+ */
+ PERMISSION_GRANTED = IPermissionChecker::PERMISSION_GRANTED,
+
+ /**
+ * The permission is denied. Applicable only to runtime and app op permissions.
+ *
+ * Returned when:
+ * - the runtime permission is granted, but the corresponding app op is denied
+ * for runtime permissions.
+ * - the app ops is ignored for app op permissions.
+ *
+ */
+ PERMISSION_SOFT_DENIED = IPermissionChecker::PERMISSION_SOFT_DENIED,
+
+ /**
+ * The permission is denied.
+ *
+ * Returned when:
+ * - the permission is denied for non app op permissions.
+ * - the app op is denied or app op is AppOpsManager#MODE_DEFAULT and permission is denied.
+ */
+ PERMISSION_HARD_DENIED = IPermissionChecker::PERMISSION_HARD_DENIED
+ };
+
+ PermissionChecker();
+
+ /**
+ * Checks whether a given data access chain described by the given attribution source
+ * has a given permission and whether the app op that corresponds to this permission
+ * is allowed. Call this method if you are the datasource which would not blame you for
+ * access to the data since you are the data. Note that the attribution source chain
+ *
+ * NOTE: The attribution source should be for yourself with its next attribution
+ * source being the app that would receive the data from you.
+ *
+ * NOTE: Use this method only for permission checks at the point where you will deliver
+ * the permission protected data to clients.
+ *
+ * @param permission The permission to check.
+ * @param attributionSource The attribution chain to check.
+ * @param message A message describing the reason the permission was checked.
+ * @return The permission check result which is either PERMISSION_GRANTED,
+ * or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED.
+ */
+ PermissionChecker::PermissionResult checkPermissionForDataDeliveryFromDatasource(
+ const String16& permission, AttributionSourceState& attributionSource,
+ const String16& message);
+
+ /**
+ * Checks whether a given data access chain described by the given attribution source
+ * has a given permission and whether the app op that corresponds to this permission
+ * is allowed. The app ops are also marked as started. This is useful for long running
+ * permissions like camera and microphone.
+ *
+ * NOTE: The attribution source should be for yourself with its next attribution
+ * source being the app that would receive the data from you.
+ *
+ * NOTE: Use this method only for permission checks at the point where you will deliver
+ * the permission protected data to clients.
+ *
+ * @param permission The permission to check.
+ * @param attributionSource The attribution chain to check.
+ * @param message A message describing the reason the permission was checked.
+ * @return The permission check result which is either PERMISSION_GRANTED,
+ * or PERMISSION_SOFT_DENIED or PERMISSION_HARD_DENIED.
+ */
+ PermissionResult checkPermissionForStartDataDeliveryFromDatasource(
+ const String16& permission, AttributionSourceState& attributionSource,
+ const String16& message);
+
+ /**
+ * Finishes an ongoing op for data access chain described by the given
+ * attribution source.
+ *
+ * @param op The op to finish.
+ * @param attributionSource The attribution chain for which to finish data delivery.
+ */
+ void finishDataDelivery(const String16& op, AttributionSourceState& attributionSource);
+
+private:
+ Mutex mLock;
+ sp<IPermissionChecker> mService;
+ sp<IPermissionChecker> getService();
+
+ int32_t checkPermission(const String16& permission, AttributionSourceState& attributionSource,
+ const String16& message, bool forDataDelivery, bool startDataDelivery,
+ bool fromDatasource);
+};
+
+
+} // namespace android
+
+// ---------------------------------------------------------------------------