diff options
14 files changed, 586 insertions, 42 deletions
diff --git a/services/vr/vr_window_manager/Android.mk_disable b/services/vr/vr_window_manager/Android.mk_disable index 9a6f7525df..cc1db7beba 100644 --- a/services/vr/vr_window_manager/Android.mk_disable +++ b/services/vr/vr_window_manager/Android.mk_disable @@ -14,6 +14,30 @@ LOCAL_PATH := $(call my-dir) +binder_src := \ + vr_window_manager_binder.cpp \ + aidl/android/service/vr/IVrWindowManager.aidl + +static_libs := \ + libcutils + +shared_libs := \ + libbase \ + libbinder \ + libutils + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(binder_src) +LOCAL_STATIC_LIBRARIES := $(static_libs) +LOCAL_SHARED_LIBRARIES := $(shared_libs) +LOCAL_CPPFLAGS += -std=c++11 +LOCAL_CFLAGS += -DLOG_TAG=\"VrWindowManager\" +LOCAL_LDLIBS := -llog +LOCAL_MODULE := libvrwm_binder +LOCAL_MODULE_TAGS := optional +include $(BUILD_STATIC_LIBRARY) + + native_src := \ application.cpp \ controller_mesh.cpp \ @@ -94,7 +118,7 @@ include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(native_src) LOCAL_C_INCLUDES := hardware/qcom/display/msm8996/libgralloc -LOCAL_STATIC_LIBRARIES := $(static_libs) +LOCAL_STATIC_LIBRARIES := $(static_libs) libvrwm_binder LOCAL_SHARED_LIBRARIES := $(shared_libs) LOCAL_SHARED_LIBRARIES += libgvr LOCAL_STATIC_LIBRARIES += libgvr_ext @@ -126,3 +150,27 @@ LOCAL_AAPT_FLAGS += --auto-add-overlay LOCAL_AAPT_FLAGS += --extra-packages com.google.vr.cardboard LOCAL_PROGUARD_FLAG_FILES := proguard.flags include $(BUILD_PACKAGE) + + +cmd_src := \ + vr_wm_ctl.cpp \ + aidl/android/service/vr/IVrWindowManager.aidl + +static_libs := \ + libcutils + +shared_libs := \ + libbase \ + libbinder \ + libutils + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(cmd_src) +LOCAL_STATIC_LIBRARIES := $(static_libs) +LOCAL_SHARED_LIBRARIES := $(shared_libs) +LOCAL_CPPFLAGS += -std=c++11 +LOCAL_CFLAGS += -DLOG_TAG=\"vrwmctl\" +LOCAL_LDLIBS := -llog +LOCAL_MODULE := vr_wm_ctl +LOCAL_MODULE_TAGS := optional +include $(BUILD_EXECUTABLE) diff --git a/services/vr/vr_window_manager/AndroidManifest.xml b/services/vr/vr_window_manager/AndroidManifest.xml index 5cc4b5c4d2..d5008a3a09 100644 --- a/services/vr/vr_window_manager/AndroidManifest.xml +++ b/services/vr/vr_window_manager/AndroidManifest.xml @@ -27,7 +27,7 @@ <service android:name=".VrWindowManagerService" /> <receiver android:name="com.google.vr.windowmanager.BootCompletedReceiver"> <intent-filter> - <action android:name="android.intent.action.BOOT_COMPLETED" /> + <!-- action android:name="android.intent.action.BOOT_COMPLETED" / --> </intent-filter> </receiver> </application> diff --git a/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl new file mode 100644 index 0000000000..b5dbb8b725 --- /dev/null +++ b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2017, 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.service.vr; + +/** @hide */ +interface IVrWindowManager { + const String SERVICE_NAME = "vr_window_manager"; + void connectController(in FileDescriptor fd) = 0; + void disconnectController() = 1; + void enterVrMode() = 2; + void exitVrMode() = 3; + void setDebugMode(int mode) = 4; +} + diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp index 62db639fa9..895f25f3f6 100644 --- a/services/vr/vr_window_manager/application.cpp +++ b/services/vr/vr_window_manager/application.cpp @@ -226,10 +226,8 @@ void Application::DrawFrame() { if (fade_value_ > 1.0f) fade_value_ = 1.0f; - quat controller_quat(controller_orientation_.qw, controller_orientation_.qx, - controller_orientation_.qy, controller_orientation_.qz); - controller_position_ = elbow_model_.Update( - delta, last_pose_.GetRotation(), controller_quat, false); + controller_position_ = elbow_model_.Update(delta, last_pose_.GetRotation(), + controller_orientation_, false); dvrBeginRenderFrameEds(graphics_context_, pose.orientation, pose.translation); @@ -257,6 +255,61 @@ void Application::DrawFrame() { } void Application::ProcessControllerInput() { + if (controller_data_provider_) { + shmem_controller_active_ = false; + const void* data = controller_data_provider_->LockControllerData(); + // TODO(kpschoedel): define wire format. + if (data) { + struct wire_format { + uint32_t version; + uint32_t timestamph; + uint32_t timestampl; + uint32_t quat_count; + float q[4]; + uint32_t buttonsh; + uint32_t buttonsl; + } __attribute__((__aligned__(32))); + const wire_format* wire_data = static_cast<const wire_format*>(data); + static uint64_t last_timestamp = 0; + if (wire_data->version == 1) { + shmem_controller_active_ = true; + uint64_t timestamp = + (((uint64_t)wire_data->timestamph) << 32) | wire_data->timestampl; + if (timestamp == last_timestamp) { + static uint64_t last_logged_timestamp = 0; + if (last_logged_timestamp != last_timestamp) { + last_logged_timestamp = last_timestamp; + ALOGI("Controller shmem stale T=0x%" PRIX64, last_timestamp); + } + } else { + last_timestamp = timestamp; + controller_orientation_ = quat(wire_data->q[3], wire_data->q[0], + wire_data->q[1], wire_data->q[2]); + shmem_controller_buttons_ = + (((uint64_t)wire_data->buttonsh) << 32) | wire_data->buttonsl; + } + } else if (wire_data->version == 0xFEEDFACE) { + static bool logged_init = false; + if (!logged_init) { + logged_init = true; + ALOGI("Controller shmem waiting for data"); + } + } + } + controller_data_provider_->UnlockControllerData(); + if (shmem_controller_active_) { + // TODO(kpschoedel): change to ALOGV or remove. + ALOGI("Controller shmem orientation: %f %f %f %f", + controller_orientation_.x(), controller_orientation_.y(), + controller_orientation_.z(), controller_orientation_.w()); + if (shmem_controller_buttons_) { + ALOGI("Controller shmem buttons: %017" PRIX64, + shmem_controller_buttons_); + } + return; + } + } + if (!controller_) return; @@ -289,8 +342,11 @@ void Application::ProcessControllerInput() { controller_connection_state_logged_ = false; } - if (new_api_status == gvr::kControllerApiOk) - controller_orientation_ = controller_state_->GetOrientation(); + if (new_api_status == gvr::kControllerApiOk) { + gvr_quatf orientation = controller_state_->GetOrientation(); + controller_orientation_ = + quat(orientation.qw, orientation.qx, orientation.qy, orientation.qz); + } controller_api_status_ = new_api_status; controller_connection_state_ = new_connection_state; diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h index 47a0927273..0c6385f7db 100644 --- a/services/vr/vr_window_manager/application.h +++ b/services/vr/vr_window_manager/application.h @@ -11,6 +11,7 @@ #include <chrono> #include <mutex> +#include "controller_data_provider.h" #include "elbow_model.h" struct DvrGraphicsContext; @@ -32,6 +33,10 @@ class Application { void DrawFrame(); + void SetControllerDataProvider(ControllerDataProvider* provider) { + controller_data_provider_ = provider; + } + protected: enum class MainThreadTask { EnteringVrMode, @@ -69,9 +74,11 @@ class Application { std::unique_ptr<gvr::ControllerState> controller_state_; gvr::ControllerApiStatus controller_api_status_; gvr::ControllerConnectionState controller_connection_state_; - gvr_quatf controller_orientation_; + quat controller_orientation_; + bool shmem_controller_active_ = false; bool controller_api_status_logged_; bool controller_connection_state_logged_; + uint64_t shmem_controller_buttons_; bool is_visible_ = false; std::chrono::time_point<std::chrono::system_clock> visibility_button_press_; @@ -93,6 +100,9 @@ class Application { jobject app_context_; jobject class_loader_; + // Controller data provider from shared memory buffer. + ControllerDataProvider* controller_data_provider_ = nullptr; + Application(const Application&) = delete; void operator=(const Application&) = delete; }; diff --git a/services/vr/vr_window_manager/controller_data_provider.h b/services/vr/vr_window_manager/controller_data_provider.h new file mode 100644 index 0000000000..bc1450c668 --- /dev/null +++ b/services/vr/vr_window_manager/controller_data_provider.h @@ -0,0 +1,19 @@ +#ifndef VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_ +#define VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_ + +namespace android { +namespace dvr { + +class ControllerDataProvider { + public: + virtual ~ControllerDataProvider() {} + // Returns data pointer or nullptr. If pointer is valid, call to + // UnlockControllerData is required. + virtual const void* LockControllerData() = 0; + virtual void UnlockControllerData() = 0; +}; + +} // namespace dvr +} // namespace android + +#endif // VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_
\ No newline at end of file diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp index 11680af56c..29ade643fd 100644 --- a/services/vr/vr_window_manager/shell_view.cpp +++ b/services/vr/vr_window_manager/shell_view.cpp @@ -190,14 +190,6 @@ mat4 GetLayerTransform(const TextureLayer& texture_layer, float display_width, return layer_transform; } -vec3 FromGvrVec3f(const gvr_vec3f& vec3f) { - return vec3(vec3f.x, vec3f.y, vec3f.z); -} - -quat FromGvrQuatf(const gvr_quatf& quaternion) { - return quat(quaternion.qw, quaternion.qx, quaternion.qy, quaternion.qz); -} - // Determine if ths frame should be shown or hidden. ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame, uint32_t vr_app) { @@ -302,15 +294,24 @@ void ShellView::DeallocateResources() { } void ShellView::EnableDebug(bool debug) { + ALOGI("EnableDebug(%d)", (int)debug); // XXX TODO delete QueueTask(debug ? MainThreadTask::EnableDebugMode : MainThreadTask::DisableDebugMode); } void ShellView::VrMode(bool mode) { + ALOGI("VrMode(%d)", (int)mode); // XXX TODO delete QueueTask(mode ? MainThreadTask::EnteringVrMode : MainThreadTask::ExitingVrMode); } +void ShellView::dumpInternal(String8& result) { + result.append("[shell]\n"); + result.appendFormat("initialized = %s\n", initialized_ ? "true" : "false"); + result.appendFormat("is_visible = %s\n", is_visible_ ? "true" : "false"); + result.appendFormat("debug_mode = %s\n\n", debug_mode_ ? "true" : "false"); +} + void ShellView::AdvanceFrame() { if (!pending_frames_.empty()) { // Check if we should advance the frame. @@ -398,7 +399,11 @@ void ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) { if (visibility == ViewMode::Hidden && debug_mode_) visibility = ViewMode::VR; - current_vr_app_ = frame->layers().front().appid; + + if (frame->layers().empty()) + current_vr_app_ = 0; + else + current_vr_app_ = frame->layers().front().appid; std::unique_lock<std::mutex> l(pending_frame_mutex_); @@ -418,7 +423,8 @@ void ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) { // If we are showing ourselves the main thread is not processing anything, // so give it a kick. - if (visibility != ViewMode::Hidden && current_frame_.visibility == ViewMode::Hidden) { + if (visibility != ViewMode::Hidden && + current_frame_.visibility == ViewMode::Hidden) { QueueTask(MainThreadTask::EnteringVrMode); QueueTask(MainThreadTask::Show); } @@ -598,23 +604,50 @@ void ShellView::DrawReticle(const mat4& perspective, const mat4& eye_matrix, vec3 pointer_location = last_pose_.GetPosition(); quat view_quaternion = last_pose_.GetRotation(); - if (controller_ && controller_api_status_ == gvr::kControllerApiOk) { - view_quaternion = FromGvrQuatf(controller_orientation_); + bool gvr_api_active = + controller_ && controller_api_status_ == gvr::kControllerApiOk; + + if (gvr_api_active || shmem_controller_active_) { + view_quaternion = controller_orientation_; vec4 controller_location = controller_translate_ * vec4(0, 0, 0, 1); pointer_location = vec3(controller_location.x(), controller_location.y(), controller_location.z()); - if (controller_state_->GetButtonDown(gvr::kControllerButtonClick)) - OnClick(true); - - if (controller_state_->GetButtonUp(gvr::kControllerButtonClick)) - OnClick(false); - - if (controller_state_->GetButtonDown(gvr::kControllerButtonApp)) - OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK); - - if (controller_state_->GetButtonUp(gvr::kControllerButtonApp)) - OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK); + if (shmem_controller_active_) { + uint64_t buttons = shmem_controller_buttons_; + shmem_controller_buttons_ = 0; + while (buttons) { + switch (buttons & 0xF) { + case 0x1: + OnClick(false); + break; + case 0x3: + OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK); + break; + case 0x9: + OnClick(true); + break; + case 0xB: + OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK); + break; + default: + break; + } + buttons >>= 4; + } + } else if (controller_) { + if (controller_state_->GetButtonDown(gvr::kControllerButtonClick)) + OnClick(true); + + if (controller_state_->GetButtonUp(gvr::kControllerButtonClick)) + OnClick(false); + + if (controller_state_->GetButtonDown(gvr::kControllerButtonApp)) + OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK); + + if (controller_state_->GetButtonUp(gvr::kControllerButtonApp)) + OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK); + } } vec3 view_direction = vec3(view_quaternion * vec3(0, 0, -1)); @@ -643,7 +676,7 @@ void ShellView::DrawReticle(const mat4& perspective, const mat4& eye_matrix, void ShellView::DrawController(const mat4& perspective, const mat4& eye_matrix, const mat4& head_matrix) { - if (!controller_) + if (!controller_ && !shmem_controller_active_) return; controller_program_->Use(); @@ -653,7 +686,7 @@ void ShellView::DrawController(const mat4& perspective, const mat4& eye_matrix, controller_program_->GetProgram(), "uViewProjection"); glUniformMatrix4fv(view_projection_location, 1, 0, mvp.data()); - quat view_quaternion = FromGvrQuatf(controller_orientation_); + quat view_quaternion = controller_orientation_; view_quaternion.toRotationMatrix(); vec3 world_pos = last_pose_.GetPosition() + controller_position_; diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h index ba46e6ddf6..14ad0f3cb8 100644 --- a/services/vr/vr_window_manager/shell_view.h +++ b/services/vr/vr_window_manager/shell_view.h @@ -9,6 +9,7 @@ #include "application.h" #include "reticle.h" +#include "shell_view_binder_interface.h" #include "surface_flinger_view.h" namespace android { @@ -20,7 +21,9 @@ enum class ViewMode { App, }; -class ShellView : public Application, public HwcCallback::Client { +class ShellView : public Application, + public android::dvr::ShellViewBinderInterface, + public HwcCallback::Client { public: ShellView(); virtual ~ShellView(); @@ -31,8 +34,10 @@ class ShellView : public Application, public HwcCallback::Client { int AllocateResources() override; void DeallocateResources() override; - void EnableDebug(bool debug); - void VrMode(bool mode); + // ShellViewBinderInterface: + void EnableDebug(bool debug) override; + void VrMode(bool mode) override; + void dumpInternal(String8& result) override; protected: void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix, diff --git a/services/vr/vr_window_manager/shell_view_binder_interface.h b/services/vr/vr_window_manager/shell_view_binder_interface.h new file mode 100644 index 0000000000..b58e4bdbf1 --- /dev/null +++ b/services/vr/vr_window_manager/shell_view_binder_interface.h @@ -0,0 +1,20 @@ +#ifndef VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_ +#define VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_ + +namespace android { +namespace dvr { + +class ShellViewBinderInterface { + public: + ShellViewBinderInterface() {}; + virtual ~ShellViewBinderInterface() {}; + + virtual void EnableDebug(bool debug) = 0; + virtual void VrMode(bool mode) = 0; + virtual void dumpInternal(String8& result) = 0; +}; + +} // namespace dvr +} // namespace android + +#endif // VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_ diff --git a/services/vr/vr_window_manager/vr_window_manager.cpp b/services/vr/vr_window_manager/vr_window_manager.cpp index 8d9ad79b91..c51ddee007 100644 --- a/services/vr/vr_window_manager/vr_window_manager.cpp +++ b/services/vr/vr_window_manager/vr_window_manager.cpp @@ -1,18 +1,33 @@ +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> #include <binder/ProcessState.h> #include "shell_view.h" +#include "vr_window_manager_binder.h" int main(int /* argc */, char** /* argv */) { + android::dvr::ShellView app; + const int app_status = app.Initialize(nullptr, nullptr, nullptr); + LOG_ALWAYS_FATAL_IF(app_status != 0, "failed to initialize: %d", app_status); + + android::service::vr::VrWindowManagerBinder service(app); + const int status = service.Initialize(); + LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status); + android::ProcessState::self()->startThreadPool(); - android::dvr::ShellView app; - if (app.Initialize(nullptr, nullptr, nullptr)) { - ALOGE("Failed to initialize"); - return 1; - } + android::sp<android::IServiceManager> sm(android::defaultServiceManager()); + const android::status_t service_status = sm->addService( + android::service::vr::VrWindowManagerBinder::SERVICE_NAME(), &service, + false /*allowIsolated*/); + LOG_ALWAYS_FATAL_IF(service_status != android::OK, "service not added: %d", + static_cast<int>(service_status)); + + app.SetControllerDataProvider(&service); while (true) app.DrawFrame(); + android::IPCThreadState::self()->joinThreadPool(); return 0; } diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.cpp b/services/vr/vr_window_manager/vr_window_manager_binder.cpp new file mode 100644 index 0000000000..c2138b7bcd --- /dev/null +++ b/services/vr/vr_window_manager/vr_window_manager_binder.cpp @@ -0,0 +1,156 @@ +#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("TODO"); // TODO(kpschoedel) +} // 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(); +} + +status_t VrWindowManagerBinder::dump( + int fd, const Vector<String16>& args [[gnu::unused]]) { + String8 result; + const android::IPCThreadState* ipc = android::IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int 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 diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.h b/services/vr/vr_window_manager/vr_window_manager_binder.h new file mode 100644 index 0000000000..99ca27a129 --- /dev/null +++ b/services/vr/vr_window_manager/vr_window_manager_binder.h @@ -0,0 +1,77 @@ +#ifndef VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_ +#define VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_ + +#include <android/service/vr/BnVrWindowManager.h> + +#include <mutex> + +#include "controller_data_provider.h" +#include "shell_view_binder_interface.h" + +namespace android { +namespace service { +namespace vr { + +class AshmemControllerDataProvider : public dvr::ControllerDataProvider { + public: + AshmemControllerDataProvider() {} + virtual ~AshmemControllerDataProvider() {} + + status_t Connect(int fd); + status_t Disconnect(); + + // ControllerDataProvider: + const void* LockControllerData() override; + void UnlockControllerData() override; + + protected: + void dumpInternal(String8& result); + + private: + static constexpr size_t kRegionLength = 8192; // TODO(kpschoedel) + ::android::base::unique_fd fd_; + + // Mutex for guarding shared_region_. + std::mutex mutex_; + void* shared_region_ = nullptr; + + AshmemControllerDataProvider(const AshmemControllerDataProvider&) = delete; + void operator=(const AshmemControllerDataProvider&) = delete; +}; + +class VrWindowManagerBinder : public BnVrWindowManager, + public AshmemControllerDataProvider { + public: + VrWindowManagerBinder(android::dvr::ShellViewBinderInterface& app) + : app_(app) {} + virtual ~VrWindowManagerBinder() {} + + // Must be called before clients can connect. + // Returns 0 if initialization is successful. + int Initialize(); + static char const* getServiceName() { return "vr_window_manager"; } + + protected: + // Implements IVrWindowManagerBinder. + ::android::binder::Status connectController( + const ::android::base::unique_fd& fd) override; + ::android::binder::Status disconnectController() override; + ::android::binder::Status enterVrMode() override; + ::android::binder::Status exitVrMode() override; + ::android::binder::Status setDebugMode(int32_t mode) override; + + // Implements BBinder::dump(). + status_t dump(int fd, const Vector<String16>& args) override; + + private: + android::dvr::ShellViewBinderInterface& app_; + + VrWindowManagerBinder(const VrWindowManagerBinder&) = delete; + void operator=(const VrWindowManagerBinder&) = delete; +}; + +} // namespace vr +} // namespace service +} // namespace android + +#endif // VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_ diff --git a/services/vr/vr_window_manager/vr_window_manager_binder_test.cpp b/services/vr/vr_window_manager/vr_window_manager_binder_test.cpp new file mode 100644 index 0000000000..f43e803d9e --- /dev/null +++ b/services/vr/vr_window_manager/vr_window_manager_binder_test.cpp @@ -0,0 +1,29 @@ +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <cutils/log.h> + +#include "vr_window_manager_binder.h" + +int main() { + ALOGI("Starting"); + android::service::vr::VrWindowManagerBinder service; + const int status = service.Initialize(); + LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status); + + signal(SIGPIPE, SIG_IGN); + android::sp<android::ProcessState> ps(android::ProcessState::self()); + ps->setThreadPoolMaxThreadCount(4); + ps->startThreadPool(); + ps->giveThreadPoolName(); + + android::sp<android::IServiceManager> sm(android::defaultServiceManager()); + const android::status_t service_status = sm->addService( + android::service::vr::VrWindowManagerBinder::SERVICE_NAME(), &service, + false /*allowIsolated*/); + LOG_ALWAYS_FATAL_IF(service_status != android::OK, "service not added: %d", + static_cast<int>(service_status)); + + android::IPCThreadState::self()->joinThreadPool(); + return 0; +} diff --git a/services/vr/vr_window_manager/vr_wm_ctl.cpp b/services/vr/vr_window_manager/vr_wm_ctl.cpp new file mode 100644 index 0000000000..c67b2ebe0a --- /dev/null +++ b/services/vr/vr_window_manager/vr_wm_ctl.cpp @@ -0,0 +1,48 @@ +#include <android/service/vr/BpVrWindowManager.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <inttypes.h> + +void usage() { fprintf(stderr, "usage: vr_wm_ctl [enter|exit|debug N]\n"); } + +int report(const android::binder::Status& status) { + if (status.isOk()) { + fprintf(stderr, "ok\n"); + return 0; + } + fprintf(stderr, "failed (%" PRId32 ") %s\n", status.exceptionCode(), + status.exceptionMessage().string()); + return (int)status.exceptionCode(); +} + +int main(int argc, char* argv[]) { + android::sp<android::IServiceManager> sm(android::defaultServiceManager()); + if (sm == nullptr) { + fprintf(stderr, "service manager not found\n"); + exit(1); + } + + android::sp<android::service::vr::IVrWindowManager> vrwm = + android::interface_cast<android::service::vr::IVrWindowManager>( + sm->getService( + android::service::vr::IVrWindowManager::SERVICE_NAME())); + if (vrwm == nullptr) { + fprintf(stderr, "service not found\n"); + exit(1); + } + + android::binder::Status status; + if ((argc == 2) && (strcmp(argv[1], "enter") == 0)) { + exit(report(vrwm->enterVrMode())); + } else if ((argc == 2) && (strcmp(argv[1], "exit") == 0)) { + exit(report(vrwm->exitVrMode())); + } else if ((argc == 3) && (strcmp(argv[1], "debug") == 0)) { + exit(report(vrwm->setDebugMode(atoi(argv[2])))); + } else { + usage(); + exit(2); + } + + return 0; +} |