diff --git a/android/service/platform_api_stub.cpp b/android/service/platform_api_stub.cpp index abda887..5abe59a 100644 --- a/android/service/platform_api_stub.cpp +++ b/android/service/platform_api_stub.cpp @@ -21,6 +21,9 @@ #include "anbox_rpc.pb.h" #include "anbox_bridge.pb.h" +#define LOG_TAG "Anboxd" +#include + namespace anbox { PlatformApiStub::PlatformApiStub(const std::shared_ptr &rpc_channel) : rpc_channel_(rpc_channel) { @@ -87,4 +90,55 @@ void PlatformApiStub::update_application_list(const ApplicationListUpdate &updat rpc_channel_->send_event(seq); } + +void PlatformApiStub::on_clipboard_data_set(Request *request) { + request->wh.result_received(); +} + +void PlatformApiStub::set_clipboard_data(const ClipboardData &data) { + auto c = std::make_shared>(); + + protobuf::bridge::ClipboardData message; + message.set_text(data.text); + + { + std::lock_guard lock(mutex_); + c->wh.expect_result(); + } + + rpc_channel_->call_method("set_clipboard_data", &message, c->response.get(), + google::protobuf::NewCallback( + this, &PlatformApiStub::on_clipboard_data_set, c.get())); + + c->wh.wait_for_all(); + + if (c->response->has_error()) throw std::runtime_error(c->response->error()); +} + +void PlatformApiStub::on_clipboard_data_get(Request *request) { + request->wh.result_received(); +} + +PlatformApiStub::ClipboardData PlatformApiStub::get_clipboard_data() { + auto c = std::make_shared>(); + + protobuf::rpc::Void message; + + received_clipboard_data_ = ClipboardData{}; + + { + std::lock_guard lock(mutex_); + c->wh.expect_result(); + } + + rpc_channel_->call_method("get_clipboard_data", &message, c->response.get(), + google::protobuf::NewCallback( + this, &PlatformApiStub::on_clipboard_data_get, c.get())); + + c->wh.wait_for_all(); + + if (c->response->has_error()) throw std::runtime_error(c->response->error()); + + return ClipboardData{c->response->text()}; +} } // namespace anbox diff --git a/android/service/platform_api_stub.h b/android/service/platform_api_stub.h index af5c14d..2397437 100644 --- a/android/service/platform_api_stub.h +++ b/android/service/platform_api_stub.h @@ -29,6 +29,9 @@ namespace protobuf { namespace rpc { class Void; } // namespace rpc +namespace bridge { +class ClipboardData; +} // namespace bridge } // namespace protobuf namespace rpc { class Channel; @@ -80,17 +83,29 @@ public: void update_application_list(const ApplicationListUpdate &update); + struct ClipboardData { + std::string text; + }; + + void set_clipboard_data(const ClipboardData &data); + ClipboardData get_clipboard_data(); + private: template struct Request { Request() : response(std::make_shared()), success(true) { } std::shared_ptr response; bool success; + common::WaitHandle wh; }; - mutable std::mutex mutex_; + void on_clipboard_data_set(Request *request); + void on_clipboard_data_get(Request *request); + mutable std::mutex mutex_; std::shared_ptr rpc_channel_; + + ClipboardData received_clipboard_data_; }; } // namespace anbox diff --git a/android/service/platform_service.cpp b/android/service/platform_service.cpp index 8015122..d6257df 100644 --- a/android/service/platform_service.cpp +++ b/android/service/platform_service.cpp @@ -124,4 +124,25 @@ status_t PlatformService::update_application_list(const Parcel &data) { return OK; } + +status_t PlatformService::set_clipboard_data(const Parcel &data) { + if (data.readInt32() == 0) + return OK; + String8 text(data.readString16()); + const auto clip_data = anbox::PlatformApiStub::ClipboardData{text.string()}; + platform_api_stub_->set_clipboard_data(clip_data); + return OK; +} + +status_t PlatformService::get_clipboard_data(const Parcel &data, Parcel *reply) { + (void) data; + const auto clip_data = platform_api_stub_->get_clipboard_data(); + if (clip_data.text.empty()) { + reply->writeInt32(0); + return OK; + } + reply->writeInt32(1); + reply->writeString16(String16(clip_data.text.c_str(), clip_data.text.length())); + return OK; +} } // namespace android diff --git a/android/service/platform_service.h b/android/service/platform_service.h index 6ba6bbf..0c3b620 100644 --- a/android/service/platform_service.h +++ b/android/service/platform_service.h @@ -35,6 +35,8 @@ public: status_t boot_finished() override; status_t update_window_state(const Parcel &data) override; status_t update_application_list(const Parcel &data) override; + status_t set_clipboard_data(const Parcel &data) override; + status_t get_clipboard_data(const Parcel &data, Parcel *reply) override; private: anbox::PlatformApiStub::WindowStateUpdate::Window unpack_window_state(const Parcel &data); diff --git a/android/service/platform_service_interface.cpp b/android/service/platform_service_interface.cpp index 0df9c14..a2219ca 100644 --- a/android/service/platform_service_interface.cpp +++ b/android/service/platform_service_interface.cpp @@ -40,6 +40,18 @@ status_t BpPlatformService::update_application_list(const Parcel&) { return remote()->transact(IPlatformService::UPDATE_APPLICATION_LIST, data, &reply); } +status_t BpPlatformService::set_clipboard_data(const Parcel&) { + Parcel data, reply; + data.writeInterfaceToken(IPlatformService::getInterfaceDescriptor()); + return remote()->transact(IPlatformService::SET_CLIPBOARD_DATA, data, &reply); +} + +status_t BpPlatformService::get_clipboard_data(const Parcel&, Parcel*) { + Parcel data, reply; + data.writeInterfaceToken(IPlatformService::getInterfaceDescriptor()); + return remote()->transact(IPlatformService::GET_CLIPBOARD_DATA, data, &reply); +} + IMPLEMENT_META_INTERFACE(PlatformService, "org.anbox.IPlatformService"); status_t BnPlatformService::onTransact(uint32_t code, const Parcel &data, @@ -54,6 +66,12 @@ status_t BnPlatformService::onTransact(uint32_t code, const Parcel &data, case UPDATE_APPLICATION_LIST: CHECK_INTERFACE(IPlatformService, data, reply); return update_application_list(data); + case SET_CLIPBOARD_DATA: + CHECK_INTERFACE(IPlatformService, data, reply); + return set_clipboard_data(data); + case GET_CLIPBOARD_DATA: + CHECK_INTERFACE(IPlatformService, data, reply); + return get_clipboard_data(data, reply); default: break; } diff --git a/android/service/platform_service_interface.h b/android/service/platform_service_interface.h index dac8643..db110ee 100644 --- a/android/service/platform_service_interface.h +++ b/android/service/platform_service_interface.h @@ -37,11 +37,15 @@ public: BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, UPDATE_WINDOW_STATE = IBinder::FIRST_CALL_TRANSACTION + 1, UPDATE_APPLICATION_LIST = IBinder::FIRST_CALL_TRANSACTION + 2, + SET_CLIPBOARD_DATA = IBinder::FIRST_CALL_TRANSACTION + 3, + GET_CLIPBOARD_DATA = IBinder::FIRST_CALL_TRANSACTION + 4, }; virtual status_t boot_finished() = 0; virtual status_t update_window_state(const Parcel &data) = 0; virtual status_t update_application_list(const Parcel &data) = 0; + virtual status_t set_clipboard_data(const Parcel &data) = 0; + virtual status_t get_clipboard_data(const Parcel &data, Parcel *reply) = 0; }; class BpPlatformService : public BpInterface { @@ -51,6 +55,8 @@ public: status_t boot_finished() override; status_t update_window_state(const Parcel &data) override; status_t update_application_list(const Parcel &data) override; + status_t set_clipboard_data(const Parcel &data) override; + status_t get_clipboard_data(const Parcel &data, Parcel *reply) override; }; class BnPlatformService : public BnInterface { diff --git a/src/anbox/bridge/platform_api_skeleton.cpp b/src/anbox/bridge/platform_api_skeleton.cpp index e63f3d6..c28a0ca 100644 --- a/src/anbox/bridge/platform_api_skeleton.cpp +++ b/src/anbox/bridge/platform_api_skeleton.cpp @@ -17,9 +17,10 @@ #include "anbox/bridge/platform_api_skeleton.h" #include "anbox/application/launcher_storage.h" -#include "anbox/logger.h" +#include "anbox/platform/policy.h" #include "anbox/wm/manager.h" #include "anbox/wm/window_state.h" +#include "anbox/logger.h" #include "anbox_bridge.pb.h" @@ -27,14 +28,40 @@ namespace anbox { namespace bridge { PlatformApiSkeleton::PlatformApiSkeleton( const std::shared_ptr &pending_calls, + const std::shared_ptr &platform_policy, const std::shared_ptr &window_manager, const std::shared_ptr &launcher_storage) : pending_calls_(pending_calls), + platform_policy_(platform_policy), window_manager_(window_manager), launcher_storage_(launcher_storage) {} PlatformApiSkeleton::~PlatformApiSkeleton() {} + +void PlatformApiSkeleton::set_clipboard_data(anbox::protobuf::bridge::ClipboardData const *request, + anbox::protobuf::rpc::Void *response, + google::protobuf::Closure *done) { + (void)response; + + if (request->has_text()) + platform_policy_->set_clipboard_data(platform::Policy::ClipboardData{request->text()}); + + done->Run(); +} + +void PlatformApiSkeleton::get_clipboard_data(anbox::protobuf::rpc::Void const *request, + anbox::protobuf::bridge::ClipboardData *response, + google::protobuf::Closure *done) { + (void)request; + + auto data = platform_policy_->get_clipboard_data(); + if (!data.text.empty()) + response->set_text(data.text); + + done->Run(); +} + void PlatformApiSkeleton::handle_boot_finished_event( const anbox::protobuf::bridge::BootFinishedEvent &event) { (void)event; diff --git a/src/anbox/bridge/platform_api_skeleton.h b/src/anbox/bridge/platform_api_skeleton.h index 02531c3..6b4e25b 100644 --- a/src/anbox/bridge/platform_api_skeleton.h +++ b/src/anbox/bridge/platform_api_skeleton.h @@ -32,11 +32,15 @@ namespace rpc { class Void; } // namespace rpc namespace bridge { +class ClipboardData; class BootFinishedEvent; class WindowStateUpdateEvent; class ApplicationListUpdateEvent; } // namespace bridge } // namespace protobuf +namespace platform { +class Policy; +} // namespace platform namespace rpc { class PendingCallCache; } // namespace rpc @@ -51,10 +55,18 @@ class PlatformApiSkeleton { public: PlatformApiSkeleton( const std::shared_ptr &pending_calls, + const std::shared_ptr &platform_policy, const std::shared_ptr &window_manager, const std::shared_ptr &launcher_storage); virtual ~PlatformApiSkeleton(); + void set_clipboard_data(anbox::protobuf::bridge::ClipboardData const *request, + anbox::protobuf::rpc::Void *response, + google::protobuf::Closure *done); + void get_clipboard_data(anbox::protobuf::rpc::Void const *request, + anbox::protobuf::bridge::ClipboardData *response, + google::protobuf::Closure *done); + void handle_boot_finished_event( const anbox::protobuf::bridge::BootFinishedEvent &event); void handle_window_state_update_event( @@ -66,6 +78,7 @@ class PlatformApiSkeleton { private: std::shared_ptr pending_calls_; + std::shared_ptr platform_policy_; std::shared_ptr window_manager_; std::shared_ptr launcher_storage_; std::function boot_finished_handler_; diff --git a/src/anbox/bridge/platform_message_processor.cpp b/src/anbox/bridge/platform_message_processor.cpp index ebeab86..7642ab5 100644 --- a/src/anbox/bridge/platform_message_processor.cpp +++ b/src/anbox/bridge/platform_message_processor.cpp @@ -32,7 +32,12 @@ PlatformMessageProcessor::PlatformMessageProcessor( PlatformMessageProcessor::~PlatformMessageProcessor() {} -void PlatformMessageProcessor::dispatch(rpc::Invocation const &invocation) {} +void PlatformMessageProcessor::dispatch(rpc::Invocation const &invocation) { + if (invocation.method_name() == "set_clipboard_data") + invoke(this, server_.get(), &PlatformApiSkeleton::set_clipboard_data, invocation); + else if (invocation.method_name() == "get_clipboard_data") + invoke(this, server_.get(), &PlatformApiSkeleton::get_clipboard_data, invocation); +} void PlatformMessageProcessor::process_event_sequence( const std::string &raw_events) { diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index 87c2d17..c9209ad 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -146,7 +146,7 @@ anbox::cmds::Run::Run(const BusFactory &bus_factory) android_api_stub->set_rpc_channel(rpc_channel); auto server = std::make_shared( - pending_calls, window_manager, launcher_storage); + pending_calls, policy, window_manager, launcher_storage); server->register_boot_finished_handler( [&]() { DEBUG("Android successfully booted"); }); return std::make_shared( diff --git a/src/anbox/platform/default_policy.cpp b/src/anbox/platform/default_policy.cpp index d82c75c..d07e4df 100644 --- a/src/anbox/platform/default_policy.cpp +++ b/src/anbox/platform/default_policy.cpp @@ -37,6 +37,16 @@ std::shared_ptr DefaultPolicy::create_window( return std::make_shared<::NullWindow>(task, frame); } +void DefaultPolicy::set_clipboard_data(const ClipboardData &data) { + (void)data; + ERROR("Not implemented"); +} + +DefaultPolicy::ClipboardData DefaultPolicy::get_clipboard_data() { + ERROR("Not implemented"); + return ClipboardData{}; +} + std::shared_ptr DefaultPolicy::create_audio_sink() { ERROR("Not implemented"); return nullptr; diff --git a/src/anbox/platform/default_policy.h b/src/anbox/platform/default_policy.h index 45f96b5..65a09e3 100644 --- a/src/anbox/platform/default_policy.h +++ b/src/anbox/platform/default_policy.h @@ -28,6 +28,8 @@ class DefaultPolicy : public Policy { std::shared_ptr create_window( const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) override; + void set_clipboard_data(const ClipboardData &data) override; + ClipboardData get_clipboard_data() override; std::shared_ptr create_audio_sink() override; std::shared_ptr create_audio_source() override; }; diff --git a/src/anbox/platform/policy.h b/src/anbox/platform/policy.h index 3daf4c9..a7fbfb2 100644 --- a/src/anbox/platform/policy.h +++ b/src/anbox/platform/policy.h @@ -39,6 +39,13 @@ class Policy { virtual std::shared_ptr create_window( const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) = 0; + struct ClipboardData { + std::string text; + }; + + virtual void set_clipboard_data(const ClipboardData &data) = 0; + virtual ClipboardData get_clipboard_data() = 0; + virtual std::shared_ptr create_audio_sink() = 0; virtual std::shared_ptr create_audio_source() = 0; }; diff --git a/src/anbox/protobuf/anbox_bridge.proto b/src/anbox/protobuf/anbox_bridge.proto index 8a919dc..e57649e 100644 --- a/src/anbox/protobuf/anbox_bridge.proto +++ b/src/anbox/protobuf/anbox_bridge.proto @@ -50,6 +50,13 @@ message ResizeTask { required Rect rect = 3; } +message ClipboardData { + optional string text = 1; + + optional string error = 127; + optional StructuredError structured_error = 128; +} + message BootFinishedEvent { } diff --git a/src/anbox/ubuntu/platform_policy.cpp b/src/anbox/ubuntu/platform_policy.cpp index 4ca2f44..c1c9f5d 100644 --- a/src/anbox/ubuntu/platform_policy.cpp +++ b/src/anbox/ubuntu/platform_policy.cpp @@ -265,6 +265,25 @@ DisplayManager::DisplayInfo PlatformPolicy::display_info() const { return display_info_; } +void PlatformPolicy::set_clipboard_data(const ClipboardData &data) { + if (data.text.empty()) + return; + SDL_SetClipboardText(data.text.c_str()); +} + +PlatformPolicy::ClipboardData PlatformPolicy::get_clipboard_data() { + if (!SDL_HasClipboardText()) + return ClipboardData{}; + + auto text = SDL_GetClipboardText(); + if (!text) + return ClipboardData{}; + + auto data = ClipboardData{text}; + SDL_free(text); + return data; +} + std::shared_ptr PlatformPolicy::create_audio_sink() { return std::make_shared(); } diff --git a/src/anbox/ubuntu/platform_policy.h b/src/anbox/ubuntu/platform_policy.h index 8695f7f..44e1d02 100644 --- a/src/anbox/ubuntu/platform_policy.h +++ b/src/anbox/ubuntu/platform_policy.h @@ -63,6 +63,9 @@ class PlatformPolicy : public std::enable_shared_from_this, void set_renderer(const std::shared_ptr &renderer); + void set_clipboard_data(const ClipboardData &data) override; + ClipboardData get_clipboard_data() override; + std::shared_ptr create_audio_sink() override; std::shared_ptr create_audio_source() override;