2 * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "anbox/dbus/skeleton/application_manager.h"
19 #include "anbox/dbus/interface.h"
20 #include "anbox/dbus/sd_bus_helpers.hpp"
21 #include "anbox/android/intent.h"
22 #include "anbox/logger.h"
26 #include <core/property.h>
29 int parse_string_from_message(sd_bus_message *m, std::string &str) {
30 const char *contents = nullptr;
31 auto r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
36 r = sd_bus_message_read(m, "s", &value);
42 r = sd_bus_message_exit_container(m);
53 const sd_bus_vtable ApplicationManager::vtable[] = {
54 sdbus_vtable_create_start(0),
55 sdbus_vtable_create_method("Launch", "a{sv}s", "", ApplicationManager::method_launch, SD_BUS_VTABLE_UNPRIVILEGED),
56 sdbus_vtable_create_property("Ready", "b", ApplicationManager::property_ready_get, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
57 sdbus_vtable_create_end()
60 int ApplicationManager::method_launch(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
61 auto r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
65 android::Intent intent;
67 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
68 const char *key = nullptr;
70 r = sd_bus_message_read(m, "s", &key);
74 if (strcmp(key, "package") == 0) {
75 r = parse_string_from_message(m, intent.package);
78 } else if (strcmp(key, "component") == 0) {
79 r = parse_string_from_message(m, intent.component);
82 } else if (strcmp(key, "action") == 0) {
83 r = parse_string_from_message(m, intent.action);
86 } else if (strcmp(key, "type") == 0) {
87 r = parse_string_from_message(m, intent.type);
90 } else if (strcmp(key, "uri") == 0) {
91 r = parse_string_from_message(m, intent.uri);
96 r = sd_bus_message_exit_container(m);
101 r = sd_bus_message_exit_container(m);
105 const char *stack = nullptr;
106 r = sd_bus_message_read(m, "s", &stack);
110 wm::Stack::Id launch_stack = wm::Stack::Id::Default;
111 if (stack && strlen(stack) > 0) {
112 auto s = std::string(stack);
113 std::istringstream i(s);
117 if (intent.package.length() == 0) {
118 sd_bus_error_set_const(ret_error, "org.anbox.InvalidArgument", "No package specified");
122 auto thiz = static_cast<ApplicationManager*>(userdata);
124 thiz->launch(intent, graphics::Rect::Invalid, launch_stack);
125 } catch (std::exception &err) {
126 ERROR("Failed to launch application: %s", err.what());
127 sd_bus_error_set_const(ret_error, "org.anbox.InternalError", err.what());
131 return sd_bus_reply_method_return(m, "");
134 int ApplicationManager::property_ready_get(sd_bus *bus, const char *path, const char *interface,
135 const char *property, sd_bus_message *reply,
136 void *userdata, sd_bus_error *ret_error) {
144 auto thiz = static_cast<ApplicationManager*>(userdata);
146 return sd_bus_message_append(reply, "b", thiz->impl_->ready().get());
149 ApplicationManager::ApplicationManager(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl)
150 : bus_(bus), impl_(impl) {
152 const auto r = sd_bus_add_object_vtable(bus_->raw(),
154 interface::Service::path(),
155 interface::ApplicationManager::name(),
159 std::runtime_error("Failed to setup application manager DBus service");
161 impl_->ready().changed().connect([&](bool value) {
164 sd_bus_emit_properties_changed(bus_->raw(),
165 interface::Service::path(),
166 interface::ApplicationManager::name(),
167 interface::ApplicationManager::Properties::Ready::name(),
172 ApplicationManager::~ApplicationManager() {}
174 void ApplicationManager::launch(const android::Intent &intent,
175 const graphics::Rect &launch_bounds,
176 const wm::Stack::Id &stack) {
178 throw std::runtime_error("Anbox not yet ready to launch applications");
180 DEBUG("Launching %s", intent);
181 impl_->launch(intent, launch_bounds, stack);
184 core::Property<bool>& ApplicationManager::ready() {
185 return impl_->ready();
187 } // namespace skeleton