Merge "Prepare AttributionSource to expose to native - native" into sc-dev
diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp
index a5712b3..1ae0a00 100644
--- a/libs/permission/Android.bp
+++ b/libs/permission/Android.bp
@@ -7,17 +7,42 @@
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: [
- "libbinder",
- "liblog",
"libutils",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ ],
+ 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 0000000..b6e54bf
--- /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 0000000..1f0e32d
--- /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 0000000..a8083ee
--- /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 0000000..20ab51f
--- /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
+
+// ---------------------------------------------------------------------------