VulpesOS/tundra/probes/beatles-camera-permission-bridge.cpp
2026-11-04 12:52:20 +01:00

99 lines
4.1 KiB
C++

// SPDX-License-Identifier: MPL-2.0
// Temporary, narrowly scoped API-23 permission controller for a RAM camera test.
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <camera/ICameraService.h>
#include <grp.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <unistd.h>
#include <stdio.h>
namespace {
const android::String16 kDescriptor("android.os.IPermissionController");
const android::String16 kCameraPermission("android.permission.CAMERA");
const android::String16 kSystemEventPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
const android::String16 kProbePackage("gonk.camera");
const android::String16 kSystemPackage("android");
const int32_t kCameraUid = 1006;
class CameraPermissionBridge : public android::BBinder {
public:
const android::String16& getInterfaceDescriptor() const override {
return kDescriptor;
}
protected:
android::status_t onTransact(uint32_t code, const android::Parcel& data,
android::Parcel* reply, uint32_t flags) override {
if (code == android::IBinder::FIRST_CALL_TRANSACTION) {
if (!data.enforceInterface(kDescriptor)) return android::PERMISSION_DENIED;
const android::String16 permission = data.readString16();
const int32_t pid = data.readInt32();
const int32_t uid = data.readInt32();
(void)pid;
const bool grant = (permission == kCameraPermission && uid == kCameraUid) ||
(permission == kSystemEventPermission && uid == 1000);
android::String8 permissionName(permission);
fprintf(stderr, "permission check uid=%d name=%s grant=%d\n", uid,
permissionName.string(), grant);
reply->writeNoException();
reply->writeInt32(grant ? 1 : 0);
return android::NO_ERROR;
}
if (code == android::IBinder::FIRST_CALL_TRANSACTION + 1) {
if (!data.enforceInterface(kDescriptor)) return android::PERMISSION_DENIED;
const int32_t uid = data.readInt32();
reply->writeNoException();
const bool hasPackage = uid == kCameraUid || uid == 1000;
reply->writeInt32(hasPackage ? 1 : 0);
if (uid == kCameraUid) reply->writeString16(kProbePackage);
else if (uid == 1000) reply->writeString16(kSystemPackage);
return android::NO_ERROR;
}
if (code == android::IBinder::FIRST_CALL_TRANSACTION + 2) {
if (!data.enforceInterface(kDescriptor)) return android::PERMISSION_DENIED;
const android::String16 permission = data.readString16();
reply->writeNoException();
reply->writeInt32(permission == kCameraPermission ? 1 : 0);
return android::NO_ERROR;
}
return android::BBinder::onTransact(code, data, reply, flags);
}
};
}
int main(int argc, char**) {
if (argc != 1) return 2;
android::ProcessState::self()->startThreadPool();
android::sp<android::IServiceManager> manager = android::defaultServiceManager();
android::sp<CameraPermissionBridge> service = new CameraPermissionBridge();
android::status_t result = manager->addService(android::String16("permission"), service);
fprintf(stderr, "register permission bridge pid=%d uid=%d result=%d\n",
getpid(), getuid(), result);
if (result != android::NO_ERROR) return 3;
gid_t systemGroup = 1000;
if (setgroups(1, &systemGroup) || setgid(1000) || setuid(1000)) {
perror("drop permission bridge to Android system UID");
return 4;
}
fprintf(stderr, "permission bridge ready\n");
android::sp<android::IBinder> cameraBinder =
manager->checkService(android::String16("media.camera"));
android::sp<android::ICameraService> cameraService =
android::interface_cast<android::ICameraService>(cameraBinder);
if (cameraService != nullptr) {
const int32_t activeUsers[] = {0};
cameraService->notifySystemEvent(android::ICameraService::USER_SWITCHED,
activeUsers, 1);
fprintf(stderr, "notified CameraService active user 0\n");
} else {
fprintf(stderr, "CameraService unavailable for active-user notification\n");
}
android::IPCThreadState::self()->joinThreadPool();
return 0;
}