blob: fdcb8b24c2771ef72206857665f5f732e3dd89c3 [file] [log] [blame]
#include "vr_window_manager_binder.h"
#include <inttypes.h>
#include <sys/mman.h>
#include <binder/IPCThreadState.h>
#include <binder/PermissionCache.h>
#include <binder/Status.h>
#include <cutils/log.h>
#include <private/android_filesystem_config.h>
#include <utils/Errors.h>
namespace android {
namespace service {
namespace vr {
namespace {
const String16 kDumpPermission("android.permission.DUMP");
const String16 kSendMeControllerInputPermission(
"android.permission.RESTRICTED_VR_ACCESS");
} // anonymous namespace
constexpr size_t AshmemControllerDataProvider::kRegionLength;
status_t AshmemControllerDataProvider::Connect(const int in_fd) {
if (in_fd < 0) {
return BAD_VALUE;
}
if (fd_.get() >= 0) {
// The VrCore is dead. Long live the VrCore.
Disconnect();
}
void* const shared_region =
::mmap(nullptr, kRegionLength, PROT_READ, MAP_SHARED, in_fd, 0);
if (shared_region == MAP_FAILED) {
shared_region_ = nullptr;
return NO_MEMORY;
}
errno = 0;
const int fd = ::fcntl(in_fd, F_DUPFD_CLOEXEC, 0);
if (fd < 0) {
::munmap(shared_region, kRegionLength);
return -errno;
}
fd_.reset(fd);
ALOGI("controller connected %d -> %d @ %p", in_fd, fd, shared_region);
std::lock_guard<std::mutex> guard(mutex_);
shared_region_ = shared_region;
return OK;
}
status_t AshmemControllerDataProvider::Disconnect() {
if (shared_region_ == nullptr || fd_.get() < 0) {
return INVALID_OPERATION;
}
std::lock_guard<std::mutex> guard(mutex_);
::munmap(shared_region_, kRegionLength);
shared_region_ = nullptr;
fd_.reset();
ALOGI("controller disconnected");
return OK;
}
const void* AshmemControllerDataProvider::LockControllerData() {
mutex_.lock();
if (!shared_region_) {
mutex_.unlock();
return nullptr;
}
return shared_region_;
}
void AshmemControllerDataProvider::UnlockControllerData() { mutex_.unlock(); }
void AshmemControllerDataProvider::dumpInternal(String8& result) {
result.appendFormat("[controller]\nfd = %d\n", fd_.get());
if (shared_region_) {
int32_t* p = reinterpret_cast<int32_t*>(shared_region_);
result.appendFormat("header = ");
for (int i = 0; i < 8; ++i) {
result.appendFormat("%c 0x%08" PRIX32, i ? ',' : '[', p[i]);
}
result.appendFormat(" ]\n\n");
}
}
int VrWindowManagerBinder::Initialize() { return 0; }
binder::Status VrWindowManagerBinder::connectController(
const ::android::base::unique_fd& in_fd) {
// TODO(kpschoedel): check permission
#if 0
int32_t pid, uid;
if (!PermissionCache::checkCallingPermission(kSendMeControllerInputPermission,
&pid, &uid)) {
ALOGE("permission denied to pid=%" PRId32 " uid=%" PRId32, pid, uid);
return binder::Status::fromStatusT(PERMISSION_DENIED);
}
#endif
return binder::Status::fromStatusT(Connect(in_fd.get()));
}
binder::Status VrWindowManagerBinder::disconnectController() {
// TODO(kpschoedel): check permission
#if 0
int32_t pid, uid;
if (!PermissionCache::checkCallingPermission(kSendMeControllerInputPermission,
&pid, &uid)) {
ALOGE("permission denied to pid=%" PRId32 " uid=%" PRId32, pid, uid);
return binder::Status::fromStatusT(PERMISSION_DENIED);
}
#endif
return binder::Status::fromStatusT(Disconnect());
}
binder::Status VrWindowManagerBinder::enterVrMode() {
// TODO(kpschoedel): check permission
app_.VrMode(true);
return binder::Status::ok();
}
binder::Status VrWindowManagerBinder::exitVrMode() {
// TODO(kpschoedel): check permission
app_.VrMode(false);
return binder::Status::ok();
}
binder::Status VrWindowManagerBinder::setDebugMode(int32_t mode) {
// TODO(kpschoedel): check permission
app_.EnableDebug(static_cast<bool>(mode));
return binder::Status::ok();
}
binder::Status VrWindowManagerBinder::set2DMode(int32_t mode) {
app_.Set2DMode(static_cast<bool>(mode));
return binder::Status::ok();
}
binder::Status VrWindowManagerBinder::setRotation(int32_t angle) {
app_.SetRotation(angle);
return binder::Status::ok();
}
status_t VrWindowManagerBinder::dump(
int fd, const Vector<String16>& args [[gnu::unused]]) {
String8 result;
const android::IPCThreadState* ipc = android::IPCThreadState::self();
const pid_t pid = ipc->getCallingPid();
const uid_t uid = ipc->getCallingUid();
if ((uid != AID_SHELL) &&
!PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
result.appendFormat("Permission denial: can't dump " LOG_TAG
" from pid=%d, uid=%d\n",
pid, uid);
} else {
app_.dumpInternal(result);
AshmemControllerDataProvider::dumpInternal(result);
}
write(fd, result.string(), result.size());
return OK;
}
} // namespace vr
} // namespace service
} // namespace android