diff --git a/Android.mk b/Android.mk index 7da57f7..d476f9e 100644 --- a/Android.mk +++ b/Android.mk @@ -29,6 +29,7 @@ LOCAL_SRC_FILES := \ android/service/host_connector.cpp \ android/service/local_socket_connection.cpp \ android/service/message_processor.cpp \ + android/service/activity_manager_interface.cpp \ android/service/android_api_skeleton.cpp \ android/service/platform_service_interface.cpp \ android/service/platform_service.cpp \ diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt index 3e86232..86103d8 100644 --- a/android/CMakeLists.txt +++ b/android/CMakeLists.txt @@ -7,6 +7,7 @@ set(ANBOXD_SOURCES ${CMAKE_SOURCE_DIR}/src/anbox/rpc/message_processor.cpp ${CMAKE_SOURCE_DIR}/src/anbox/rpc/pending_call_cache.cpp ${CMAKE_SOURCE_DIR}/src/anbox/common/fd.cpp + service/activity_manager_interface.cpp service/platform_service.cpp service/platform_service_interface.cpp service/platform_api_stub.cpp diff --git a/android/service/activity_manager_interface.cpp b/android/service/activity_manager_interface.cpp new file mode 100644 index 0000000..84dce86 --- /dev/null +++ b/android/service/activity_manager_interface.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#define LOG_TAG "Anboxd" + +#include "android/service/activity_manager_interface.h" + +namespace android { +BpActivityManager::BpActivityManager(const sp &binder) : + BpInterface(binder) { +} + +status_t BpActivityManager::setFocusedTask(int32_t id) { + Parcel data, reply; + data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); + data.writeInt32(id); + return remote()->transact(IActivityManager::SET_FOCUSED_TASK, data, &reply); +} + +IMPLEMENT_META_INTERFACE(ActivityManager, "android.app.IActivityManager"); +} // namespace android diff --git a/android/service/activity_manager_interface.h b/android/service/activity_manager_interface.h new file mode 100644 index 0000000..655fdb6 --- /dev/null +++ b/android/service/activity_manager_interface.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_ANDROID_ACTIVITY_MANAGER_INTERFACE_H_ +#define ANBOX_ANDROID_ACTIVITY_MANAGER_INTERFACE_H_ + +#include +#include +#include + +#include +#include + +#include + +namespace android { +class IActivityManager : public IInterface { +public: + DECLARE_META_INTERFACE(ActivityManager); + + enum { + // This needs to stay synchronized with frameworks/base/core/java/android/app/IActivityManager.java + SET_FOCUSED_TASK = IBinder::FIRST_CALL_TRANSACTION + 130, + }; + + virtual status_t setFocusedTask(int32_t id) = 0; +}; + +class BpActivityManager : public BpInterface { +public: + BpActivityManager(const sp &binder); + + status_t setFocusedTask(int32_t id) override; +}; +} // namespace android +#endif diff --git a/android/service/android_api_skeleton.cpp b/android/service/android_api_skeleton.cpp index 3181787..f692721 100644 --- a/android/service/android_api_skeleton.cpp +++ b/android/service/android_api_skeleton.cpp @@ -15,6 +15,8 @@ * */ +#define LOG_TAG "Anboxd" + #include "android/service/android_api_skeleton.h" #include "anbox_rpc.pb.h" @@ -23,6 +25,8 @@ #include #include +#include + namespace { std::map common_env = { {"ANDROID_DATA", "/data"}, @@ -48,6 +52,14 @@ void AndroidApiSkeleton::wait_for_process(core::posix::ChildProcess &process, } } +void AndroidApiSkeleton::connect_services() { + if (!activity_manager_.get()) { + auto am = android::defaultServiceManager()->getService(android::String16("activity")); + if (am.get()) + activity_manager_ = new android::BpActivityManager(am); + } +} + void AndroidApiSkeleton::install_application(anbox::protobuf::bridge::InstallApplication const *request, anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done) { @@ -106,4 +118,19 @@ void AndroidApiSkeleton::set_dns_servers(anbox::protobuf::bridge::SetDnsServers done->Run(); } + +void AndroidApiSkeleton::set_focused_task(anbox::protobuf::bridge::SetFocusedTask const *request, + anbox::protobuf::rpc::Void *response, + google::protobuf::Closure *done) { + (void) response; + + connect_services(); + + if (activity_manager_.get()) + activity_manager_->setFocusedTask(request->id()); + else + response->set_error("ActivityManager is not available"); + + done->Run(); +} } // namespace anbox diff --git a/android/service/android_api_skeleton.h b/android/service/android_api_skeleton.h index 8e8787b..4cdd582 100644 --- a/android/service/android_api_skeleton.h +++ b/android/service/android_api_skeleton.h @@ -18,6 +18,8 @@ #ifndef ANBOX_PLATFORM_API_SKELETON_H_ #define ANBOX_PLATFORM_API_SKELETON_H_ +#include "android/service/activity_manager_interface.h" + namespace google { namespace protobuf { class Closure; @@ -36,6 +38,7 @@ namespace bridge { class InstallApplication; class LaunchApplication; class SetDnsServers; +class SetFocusedTask; } // namespace bridge namespace rpc { class Void; @@ -58,9 +61,17 @@ public: anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done); + void set_focused_task(anbox::protobuf::bridge::SetFocusedTask const *request, + anbox::protobuf::rpc::Void *response, + google::protobuf::Closure *done); + private: void wait_for_process(core::posix::ChildProcess &process, anbox::protobuf::rpc::Void *response); + + void connect_services(); + + android::sp activity_manager_; }; } // namespace anbox diff --git a/android/service/message_processor.cpp b/android/service/message_processor.cpp index 3a035be..4036917 100644 --- a/android/service/message_processor.cpp +++ b/android/service/message_processor.cpp @@ -41,6 +41,8 @@ void MessageProcessor::dispatch(rpc::Invocation const& invocation) { invoke(this, platform_api_.get(), &AndroidApiSkeleton::launch_application, invocation); else if (invocation.method_name() == "set_dns_servers") invoke(this, platform_api_.get(), &AndroidApiSkeleton::set_dns_servers, invocation); + else if (invocation.method_name() == "set_focused_task") + invoke(this, platform_api_.get(), &AndroidApiSkeleton::set_focused_task, invocation); } void MessageProcessor::process_event_sequence(const std::string&) { diff --git a/src/anbox/bridge/android_api_stub.cpp b/src/anbox/bridge/android_api_stub.cpp index e7bb5f7..92c4370 100644 --- a/src/anbox/bridge/android_api_stub.cpp +++ b/src/anbox/bridge/android_api_stub.cpp @@ -82,6 +82,7 @@ void AndroidApiStub::install(const std::string &path) { } void AndroidApiStub::application_installed(Request *request) { + (void) request; install_wait_handle_.result_received(); } @@ -110,6 +111,7 @@ void AndroidApiStub::launch(const std::string &package, const std::string &activ } void AndroidApiStub::application_launched(Request *request) { + (void) request; launch_wait_handle_.result_received(); } @@ -143,7 +145,37 @@ void AndroidApiStub::set_dns_servers(const std::string &domain, const std::vecto } void AndroidApiStub::dns_servers_set(Request *request) { + (void) request; set_dns_servers_wait_handle_.result_received(); } + +void AndroidApiStub::set_focused_task(const std::int32_t &id) { + ensure_rpc_channel(); + + auto c = std::make_shared>(); + + protobuf::bridge::SetFocusedTask message; + message.set_id(id); + + { + std::lock_guard lock(mutex_); + set_focused_task_handle_.expect_result(); + } + + channel_->call_method("set_focused_task", + &message, + c->response.get(), + google::protobuf::NewCallback(this, &AndroidApiStub::focused_task_set, c.get())); + + set_focused_task_handle_.wait_for_all(); + + if (c->response->has_error()) + throw std::runtime_error(c->response->error()); +} + +void AndroidApiStub::focused_task_set(Request *request) { + (void) request; + set_focused_task_handle_.result_received(); +} } // namespace bridge } // namespace anbox diff --git a/src/anbox/bridge/android_api_stub.h b/src/anbox/bridge/android_api_stub.h index 58e1a92..73cff7c 100644 --- a/src/anbox/bridge/android_api_stub.h +++ b/src/anbox/bridge/android_api_stub.h @@ -46,6 +46,7 @@ public: void launch(const std::string &package, const std::string &activity) override; void set_dns_servers(const std::string &domain, const std::vector &servers); + void set_focused_task(const std::int32_t &id); private: void ensure_rpc_channel(); @@ -60,12 +61,14 @@ private: void application_installed(Request *request); void application_launched(Request *request); void dns_servers_set(Request *request); + void focused_task_set(Request *request); mutable std::mutex mutex_; std::shared_ptr channel_; common::WaitHandle install_wait_handle_; common::WaitHandle launch_wait_handle_; common::WaitHandle set_dns_servers_wait_handle_; + common::WaitHandle set_focused_task_handle_; }; } // namespace bridge } // namespace anbox diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index d2841ca..f32c522 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -89,7 +89,9 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory) auto input_manager = std::make_shared(rt); - auto policy = std::make_shared(input_manager); + auto android_api_stub = std::make_shared(); + + auto policy = std::make_shared(input_manager, android_api_stub); // FIXME this needs to be removed and solved differently behind the scenes registerDisplayManager(policy); @@ -116,7 +118,6 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory) renderer->socket_path(), icon_)); - auto android_api_stub = std::make_shared(); auto bridge_connector = std::make_shared( utils::string_format("%s/anbox_bridge", config::socket_path()), diff --git a/src/anbox/protobuf/anbox_bridge.proto b/src/anbox/protobuf/anbox_bridge.proto index 0a3375a..382a2b8 100644 --- a/src/anbox/protobuf/anbox_bridge.proto +++ b/src/anbox/protobuf/anbox_bridge.proto @@ -32,6 +32,9 @@ message SetDnsServers { repeated Server servers = 2; } +message SetFocusedTask { + required int32 id = 1; +} message BootFinishedEvent { } diff --git a/src/anbox/ubuntu/platform_policy.cpp b/src/anbox/ubuntu/platform_policy.cpp index 0045b61..2eefe38 100644 --- a/src/anbox/ubuntu/platform_policy.cpp +++ b/src/anbox/ubuntu/platform_policy.cpp @@ -20,6 +20,7 @@ #include "anbox/ubuntu/keycode_converter.h" #include "anbox/input/manager.h" #include "anbox/input/device.h" +#include "anbox/bridge/android_api_stub.h" #include "anbox/logger.h" #include @@ -199,6 +200,15 @@ void PlatformPolicy::window_deleted(const Window::Id &id) { windows_.erase(w); } +void PlatformPolicy::window_wants_focus(const Window::Id &id) { + auto w = windows_.find(id); + if (w == windows_.end()) + return; + + if (auto window = w->second.lock()) + android_api_->set_focused_task(window->task()); +} + DisplayManager::DisplayInfo PlatformPolicy::display_info() const { return display_info_; } diff --git a/src/anbox/ubuntu/platform_policy.h b/src/anbox/ubuntu/platform_policy.h index 242c5c8..7bab173 100644 --- a/src/anbox/ubuntu/platform_policy.h +++ b/src/anbox/ubuntu/platform_policy.h @@ -33,18 +33,23 @@ namespace input { class Device; class Manager; } // namespace input +namespace bridge { +class AndroidApiStub; +} // namespace bridge namespace ubuntu { class PlatformPolicy : public std::enable_shared_from_this, public wm::PlatformPolicy, public Window::Observer, public DisplayManager { public: - PlatformPolicy(const std::shared_ptr &input_manager); + PlatformPolicy(const std::shared_ptr &input_manager, + const std::shared_ptr &android_api); ~PlatformPolicy(); std::shared_ptr create_window(const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) override; void window_deleted(const Window::Id &id) override; + void window_wants_focus(const Window::Id &id) override; DisplayInfo display_info() const override; @@ -55,6 +60,7 @@ private: static Window::Id next_window_id(); std::shared_ptr input_manager_; + std::shared_ptr android_api_; // We don't own the windows anymore after the got created by us so we // need to be careful once we try to use them again. std::map> windows_; diff --git a/src/anbox/ubuntu/window.cpp b/src/anbox/ubuntu/window.cpp index b85f213..1864dcd 100644 --- a/src/anbox/ubuntu/window.cpp +++ b/src/anbox/ubuntu/window.cpp @@ -62,7 +62,6 @@ Window::Window(const Id &id, SDL_GetWindowWMInfo(window_, &info); switch (info.subsystem) { case SDL_SYSWM_X11: - DEBUG("Running on X11"); native_display_ = static_cast(info.info.x11.display); native_window_ = static_cast(info.info.x11.window); break; @@ -75,41 +74,6 @@ Window::Window(const Id &id, int actual_x = 0, actual_y = 0; SDL_GetWindowSize(window_, &actual_width, &actual_height); SDL_GetWindowPosition(window_, &actual_x, &actual_y); - DEBUG("Window created {%d,%d,%d,%d}", actual_x, actual_y, actual_width, actual_height); -} - -Window::Window(int x, int y, int width, int height) : - wm::Window(0, graphics::Rect{x,y,x + width,y + height}), - native_display_(0), - native_window_(0) { - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); - - window_ = SDL_CreateWindow("anbox", x, y, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS); - if (!window_) { - const auto message = utils::string_format("Failed to create window: %s", SDL_GetError()); - BOOST_THROW_EXCEPTION(std::runtime_error(message)); - } - - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - SDL_GetWindowWMInfo(window_, &info); - switch (info.subsystem) { - case SDL_SYSWM_X11: - DEBUG("Running on X11"); - native_display_ = static_cast(info.info.x11.display); - native_window_ = static_cast(info.info.x11.window); - break; - default: - ERROR("Unknown subsystem (%d)", info.subsystem); - BOOST_THROW_EXCEPTION(std::runtime_error("SDL subsystem not suported")); - } - - int actual_width = 0, actual_height = 0; - int actual_x = 0, actual_y = 0; - SDL_GetWindowSize(window_, &actual_width, &actual_height); - SDL_GetWindowPosition(window_, &actual_x, &actual_y); - DEBUG("Window created {%d,%d,%d,%d}", actual_x, actual_y, actual_width, actual_height); } Window::~Window() { @@ -129,8 +93,10 @@ void Window::update_position(int x, int y) { } void Window::process_event(const SDL_Event &event) { - switch (event.window.type) { + switch (event.window.event) { case SDL_WINDOWEVENT_FOCUS_GAINED: + if (observer_) + observer_->window_wants_focus(id_); break; case SDL_WINDOWEVENT_FOCUS_LOST: break; diff --git a/src/anbox/ubuntu/window.h b/src/anbox/ubuntu/window.h index a92ea85..a2fb444 100644 --- a/src/anbox/ubuntu/window.h +++ b/src/anbox/ubuntu/window.h @@ -39,10 +39,10 @@ public: public: virtual ~Observer(); virtual void window_deleted(const Id &id) = 0; + virtual void window_wants_focus(const Id &id) = 0; }; Window(const Id &id, const wm::Task::Id &task, const std::shared_ptr &observer, const graphics::Rect &frame); - Window(int x, int y, int width, int height); ~Window(); void process_event(const SDL_Event &event);