Merge pull request #214 from morphis/f/fork-session-mgr
Start session manager when not already running
This commit is contained in:
commit
da20611a6c
16 changed files with 290 additions and 40 deletions
|
|
@ -64,6 +64,7 @@ find_package(GLESv2 REQUIRED)
|
||||||
find_package(Protobuf REQUIRED)
|
find_package(Protobuf REQUIRED)
|
||||||
|
|
||||||
pkg_check_modules(SDL2 sdl2 REQUIRED)
|
pkg_check_modules(SDL2 sdl2 REQUIRED)
|
||||||
|
pkg_check_modules(SDL2_IMAGE SDL2_image REQUIRED)
|
||||||
pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED)
|
pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED)
|
||||||
pkg_check_modules(DBUS dbus-1 REQUIRED)
|
pkg_check_modules(DBUS dbus-1 REQUIRED)
|
||||||
pkg_check_modules(LXC lxc REQUIRED)
|
pkg_check_modules(LXC lxc REQUIRED)
|
||||||
|
|
@ -114,3 +115,6 @@ if (NOT "${HOST_CMAKE_C_COMPILER}" STREQUAL "")
|
||||||
message(STATUS "Host C compiler: ${HOST_CMAKE_C_COMPILER}")
|
message(STATUS "Host C compiler: ${HOST_CMAKE_C_COMPILER}")
|
||||||
message(STATUS "Host C compiler: ${HOST_CMAKE_CXX_COMPILER}")
|
message(STATUS "Host C compiler: ${HOST_CMAKE_CXX_COMPILER}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
install(FILES data/ui/loading-screen.png DESTINATION share/anbox/ui)
|
||||||
|
|
||||||
|
|
|
||||||
BIN
data/ui/loading-screen.png
Normal file
BIN
data/ui/loading-screen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
|
|
@ -114,6 +114,12 @@ public:
|
||||||
*/
|
*/
|
||||||
wait::Result wait_for(const wait::Flags& flags);
|
wait::Result wait_for(const wait::Flags& flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mark the child process to not to be killed when the ChildProcess
|
||||||
|
* instance goes away.
|
||||||
|
*/
|
||||||
|
void dont_kill_on_cleanup();
|
||||||
|
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
/**
|
/**
|
||||||
* @brief Access this process's stderr.
|
* @brief Access this process's stderr.
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ struct ChildProcess::Private
|
||||||
~Private()
|
~Private()
|
||||||
{
|
{
|
||||||
// Check if we are in the original parent process.
|
// Check if we are in the original parent process.
|
||||||
if (original_parent_pid == getpid())
|
if (original_parent_pid == getpid() && !dont_kill_on_cleanup)
|
||||||
{
|
{
|
||||||
// If so, check if we are considering a valid pid here.
|
// If so, check if we are considering a valid pid here.
|
||||||
// If so, we kill the original child.
|
// If so, we kill the original child.
|
||||||
|
|
@ -333,6 +333,8 @@ struct ChildProcess::Private
|
||||||
// is called from the child process.
|
// is called from the child process.
|
||||||
pid_t original_parent_pid;
|
pid_t original_parent_pid;
|
||||||
pid_t original_child_pid;
|
pid_t original_child_pid;
|
||||||
|
|
||||||
|
bool dont_kill_on_cleanup = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
ChildProcess ChildProcess::invalid()
|
ChildProcess ChildProcess::invalid()
|
||||||
|
|
@ -395,6 +397,11 @@ wait::Result ChildProcess::wait_for(const wait::Flags& flags)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChildProcess::dont_kill_on_cleanup()
|
||||||
|
{
|
||||||
|
d->dont_kill_on_cleanup = true;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
std::istream& ChildProcess::cerr()
|
std::istream& ChildProcess::cerr()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ apt-get install -qq -y \
|
||||||
libproperties-cpp-dev \
|
libproperties-cpp-dev \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libsdl2-dev \
|
libsdl2-dev \
|
||||||
|
libsdl2-image-dev \
|
||||||
lxc-dev \
|
lxc-dev \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
protobuf-compiler
|
protobuf-compiler
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ parts:
|
||||||
- libprotobuf-dev
|
- libprotobuf-dev
|
||||||
- libproperties-cpp-dev
|
- libproperties-cpp-dev
|
||||||
- libsdl2-dev
|
- libsdl2-dev
|
||||||
|
- libsdl2-image-dev
|
||||||
- pkg-config
|
- pkg-config
|
||||||
- protobuf-compiler
|
- protobuf-compiler
|
||||||
stage-packages:
|
stage-packages:
|
||||||
|
|
@ -128,4 +129,5 @@ parts:
|
||||||
make test
|
make test
|
||||||
prime:
|
prime:
|
||||||
- usr/bin/anbox
|
- usr/bin/anbox
|
||||||
|
- usr/share/anbox
|
||||||
- usr/lib/*-linux-*/
|
- usr/lib/*-linux-*/
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ include_directories(
|
||||||
${DBUS_CPP_INCLUDE_DIRS}
|
${DBUS_CPP_INCLUDE_DIRS}
|
||||||
${DBUS_INCLUDE_DIRS}
|
${DBUS_INCLUDE_DIRS}
|
||||||
${SDL2_INCLUDE_DIRS}
|
${SDL2_INCLUDE_DIRS}
|
||||||
|
${SDL2_IMAGE_INCLUDE_DIRS}
|
||||||
${LXC_INCLUDE_DIRS}
|
${LXC_INCLUDE_DIRS}
|
||||||
${MIRCLIENT_INCLUDE_DIRS}
|
${MIRCLIENT_INCLUDE_DIRS}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
|
@ -206,6 +207,8 @@ set(SOURCES
|
||||||
|
|
||||||
anbox/utils/environment_file.cpp
|
anbox/utils/environment_file.cpp
|
||||||
|
|
||||||
|
anbox/ui/splash_screen.cpp
|
||||||
|
|
||||||
anbox/do_not_copy_or_move.h
|
anbox/do_not_copy_or_move.h
|
||||||
anbox/optional.h
|
anbox/optional.h
|
||||||
anbox/defer_action.h)
|
anbox/defer_action.h)
|
||||||
|
|
@ -218,6 +221,8 @@ target_link_libraries(anbox-core
|
||||||
${DBUS_CPP_LIBRARIES}
|
${DBUS_CPP_LIBRARIES}
|
||||||
${SDL2_LDFLAGS}
|
${SDL2_LDFLAGS}
|
||||||
${SDL2_LIBRARIES}
|
${SDL2_LIBRARIES}
|
||||||
|
${SDL2_IMAGE_LDFLAGS}
|
||||||
|
${SDL2_IMAGE_LIBRARIES}
|
||||||
${LXC_LDFLAGS}
|
${LXC_LDFLAGS}
|
||||||
${LXC_LIBRARIES}
|
${LXC_LIBRARIES}
|
||||||
${MIRCLIENT_LDFLAGS}
|
${MIRCLIENT_LDFLAGS}
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,25 @@
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace android {
|
namespace android {
|
||||||
std::ostream &operator<<(std::ostream &out, const Intent &intent) {
|
std::ostream &operator<<(std::ostream &out, const Intent &intent) {
|
||||||
out << "["
|
out << "[";
|
||||||
<< "action=" << intent.action << " "
|
if (!intent.action.empty())
|
||||||
<< "uri=" << intent.uri << " "
|
out << " " << "action=" << intent.action << " ";
|
||||||
<< "type=" << intent.type << " "
|
if (!intent.uri.empty())
|
||||||
<< "flags=" << intent.flags << " "
|
out << " " << "uri=" << intent.uri << " ";
|
||||||
<< "package=" << intent.package << " "
|
if (!intent.type.empty())
|
||||||
<< "component=" << intent.component << " "
|
out << " " << "type=" << intent.type << " ";
|
||||||
<< "categories=[ ";
|
if (intent.flags > 0)
|
||||||
for (const auto &category : intent.categories) out << category << " ";
|
out << " " << "flags=" << intent.flags << " ";
|
||||||
out << "]]";
|
if (!intent.package.empty())
|
||||||
|
out << " " << "package=" << intent.package << " ";
|
||||||
|
if (!intent.component.empty())
|
||||||
|
out << "component=" << intent.component << " ";
|
||||||
|
if (intent.categories.size() > 0) {
|
||||||
|
out << "categories=[ ";
|
||||||
|
for (const auto &category : intent.categories) out << category << " ";
|
||||||
|
out << "] ";
|
||||||
|
}
|
||||||
|
out << "]";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
#include "anbox/common/wait_handle.h"
|
#include "anbox/common/wait_handle.h"
|
||||||
#include "anbox/dbus/stub/application_manager.h"
|
#include "anbox/dbus/stub/application_manager.h"
|
||||||
#include "anbox/common/dispatcher.h"
|
#include "anbox/common/dispatcher.h"
|
||||||
|
#include "anbox/ui/splash_screen.h"
|
||||||
|
#include "anbox/config.h"
|
||||||
#include "anbox/runtime.h"
|
#include "anbox/runtime.h"
|
||||||
#include "anbox/logger.h"
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
|
|
@ -26,12 +28,31 @@
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#include "core/posix/exec.h"
|
||||||
|
#include "core/posix/fork.h"
|
||||||
#include "core/posix/signal.h"
|
#include "core/posix/signal.h"
|
||||||
|
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const boost::posix_time::seconds max_wait_timeout{30};
|
const boost::posix_time::seconds max_wait_timeout{240};
|
||||||
|
const int max_restart_attempts{3};
|
||||||
|
const std::chrono::seconds restart_interval{5};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool anbox::cmds::Launch::try_launch_activity(const std::shared_ptr<dbus::stub::ApplicationManager> &stub) {
|
||||||
|
try {
|
||||||
|
DEBUG("Sending launch intent %s to Android ..", intent_);
|
||||||
|
stub->launch(intent_, graphics::Rect::Invalid, stack_);
|
||||||
|
} catch (const std::exception &err) {
|
||||||
|
ERROR("Failed to launch activity: %s", err.what());
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
ERROR("Failed to launch activity");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
anbox::cmds::Launch::Launch()
|
anbox::cmds::Launch::Launch()
|
||||||
|
|
@ -69,42 +90,91 @@ anbox::cmds::Launch::Launch()
|
||||||
auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
|
auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
|
||||||
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
|
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
|
||||||
|
|
||||||
|
const auto snap_path = utils::get_env_value("SNAP");
|
||||||
|
if (!snap_path.empty()) {
|
||||||
|
const auto resource_path = fs::path(snap_path) / "usr" / "share" / "anbox";
|
||||||
|
SystemConfiguration::instance().set_resource_path(resource_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ui::SplashScreen> ss;
|
||||||
|
|
||||||
|
// Instead of relying on the user session init system to start our
|
||||||
|
// session manager process we also attempt to start it on our own
|
||||||
|
// if not already running. This will help to mitigate problems with
|
||||||
|
// a crashing or a not yet started session manager instance.
|
||||||
std::shared_ptr<dbus::stub::ApplicationManager> stub;
|
std::shared_ptr<dbus::stub::ApplicationManager> stub;
|
||||||
try {
|
for (auto n = 0; n < max_restart_attempts; n++) {
|
||||||
stub = dbus::stub::ApplicationManager::create_for_bus(bus);
|
try {
|
||||||
} catch (...) {
|
stub = dbus::stub::ApplicationManager::create_for_bus(bus);
|
||||||
ERROR("Anbox session manager service isn't running!");
|
break;
|
||||||
|
} catch (std::exception &err) {
|
||||||
|
WARNING("Anbox session manager service isn't running, trying to start it.");
|
||||||
|
|
||||||
|
// Give us a splash screen as long as we're trying to connect
|
||||||
|
// with the session manager so the user knows something is
|
||||||
|
// happening after he started Anbox.
|
||||||
|
if (!ss)
|
||||||
|
ss = std::make_shared<ui::SplashScreen>();
|
||||||
|
|
||||||
|
std::vector<std::string> args = {"session-manager"};
|
||||||
|
|
||||||
|
std::map<std::string,std::string> env;
|
||||||
|
core::posix::this_process::env::for_each([&](const std::string &name, const std::string &value) {
|
||||||
|
env.insert({name, value});
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto exe_path = utils::process_get_exe_path(::getpid());
|
||||||
|
if (!fs::exists(exe_path)) {
|
||||||
|
ERROR("Can't find correct anbox executable to run. Found %s but does not exist", exe_path);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const auto flags = core::posix::StandardStream::stdout | core::posix::StandardStream::stderr;
|
||||||
|
auto child = core::posix::fork([&]() {
|
||||||
|
auto grandchild = core::posix::exec(exe_path, args, env, flags);
|
||||||
|
grandchild.dont_kill_on_cleanup();
|
||||||
|
return core::posix::exit::Status::success;
|
||||||
|
}, flags);
|
||||||
|
|
||||||
|
// We don't wait for the grandchild but the child as we use double forking
|
||||||
|
// here to break through the process hierarchy and make the grandchild a
|
||||||
|
// direct child of the init process so it keeps running on its own and
|
||||||
|
// indepent of our short living process here.
|
||||||
|
child.wait_for(core::posix::wait::Flags::untraced);
|
||||||
|
|
||||||
|
DEBUG("Started session manager, will now try to connect ..");
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
ERROR("Failed to start session manager instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(restart_interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stub) {
|
||||||
|
ERROR("Couldn't get a connection with the session manager");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
|
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
|
||||||
dispatcher->dispatch([&]() {
|
dispatcher->dispatch([&]() {
|
||||||
if (stub->ready()) {
|
if (stub->ready()) {
|
||||||
try {
|
ss.reset();
|
||||||
stub->launch(intent_, graphics::Rect::Invalid, stack_);
|
success = try_launch_activity(stub);
|
||||||
success = true;
|
|
||||||
} catch (std::exception &err) {
|
|
||||||
ERROR("err %s", err.what());
|
|
||||||
}
|
|
||||||
trap->stop();
|
trap->stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("Android hasn't fully booted yet. Waiting a bit..");
|
DEBUG("Android hasn't fully booted yet. Waiting a bit ..");
|
||||||
|
|
||||||
stub->ready().changed().connect([&](bool ready) {
|
stub->ready().changed().connect([&](bool ready) {
|
||||||
if (!ready)
|
if (!ready)
|
||||||
return;
|
return;
|
||||||
try {
|
ss.reset();
|
||||||
stub->launch(intent_, graphics::Rect::Invalid, stack_);
|
success = try_launch_activity(stub);
|
||||||
success = true;
|
|
||||||
} catch (std::exception &err) {
|
|
||||||
ERROR("Failed to launch activity: %s", err.what());
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
trap->stop();
|
trap->stop();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -112,8 +182,10 @@ anbox::cmds::Launch::Launch()
|
||||||
boost::asio::deadline_timer timer(rt->service());
|
boost::asio::deadline_timer timer(rt->service());
|
||||||
timer.expires_from_now(max_wait_timeout);
|
timer.expires_from_now(max_wait_timeout);
|
||||||
timer.async_wait([&](const boost::system::error_code&) {
|
timer.async_wait([&](const boost::system::error_code&) {
|
||||||
WARNING("Stop waiting as we're already waiting for too long. Something is wrong");
|
WARNING("Stopped waiting as we've already waited for too long. Something");
|
||||||
WARNING("with your setup and the container may have failed to boot.");
|
WARNING("is wrong with your setup or the container has failed to boot.");
|
||||||
|
WARNING("If you think you found a bug please don't hesitate to file on");
|
||||||
|
WARNING("at https://github.com/anbox/anbox/issues/new");
|
||||||
trap->stop();
|
trap->stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "anbox/android/intent.h"
|
#include "anbox/android/intent.h"
|
||||||
|
#include "anbox/dbus/stub/application_manager.h"
|
||||||
#include "anbox/wm/stack.h"
|
#include "anbox/wm/stack.h"
|
||||||
#include "anbox/cli.h"
|
#include "anbox/cli.h"
|
||||||
|
|
||||||
|
|
@ -33,6 +34,8 @@ class Launch : public cli::CommandWithFlagsAndAction {
|
||||||
Launch();
|
Launch();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool try_launch_activity(const std::shared_ptr<dbus::stub::ApplicationManager> &stub);
|
||||||
|
|
||||||
android::Intent intent_;
|
android::Intent intent_;
|
||||||
wm::Stack::Id stack_;
|
wm::Stack::Id stack_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,10 @@ void anbox::SystemConfiguration::set_data_path(const std::string &path) {
|
||||||
data_path = path;
|
data_path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void anbox::SystemConfiguration::set_resource_path(const fs::path &path) {
|
||||||
|
resource_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
fs::path anbox::SystemConfiguration::data_dir() const {
|
fs::path anbox::SystemConfiguration::data_dir() const {
|
||||||
return data_path;
|
return data_path;
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +80,10 @@ std::string anbox::SystemConfiguration::application_item_dir() const {
|
||||||
return dir.string();
|
return dir.string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string anbox::SystemConfiguration::resource_dir() const {
|
||||||
|
return resource_path.string();
|
||||||
|
}
|
||||||
|
|
||||||
anbox::SystemConfiguration& anbox::SystemConfiguration::instance() {
|
anbox::SystemConfiguration& anbox::SystemConfiguration::instance() {
|
||||||
static SystemConfiguration config;
|
static SystemConfiguration config;
|
||||||
return config;
|
return config;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ class SystemConfiguration {
|
||||||
virtual ~SystemConfiguration() = default;
|
virtual ~SystemConfiguration() = default;
|
||||||
|
|
||||||
void set_data_path(const std::string &path);
|
void set_data_path(const std::string &path);
|
||||||
|
void set_resource_path(const boost::filesystem::path &path);
|
||||||
|
|
||||||
boost::filesystem::path data_dir() const;
|
boost::filesystem::path data_dir() const;
|
||||||
std::string rootfs_dir() const;
|
std::string rootfs_dir() const;
|
||||||
|
|
@ -40,11 +41,13 @@ class SystemConfiguration {
|
||||||
std::string container_socket_path() const;
|
std::string container_socket_path() const;
|
||||||
std::string input_device_dir() const;
|
std::string input_device_dir() const;
|
||||||
std::string application_item_dir() const;
|
std::string application_item_dir() const;
|
||||||
|
std::string resource_dir() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SystemConfiguration() = default;
|
SystemConfiguration() = default;
|
||||||
|
|
||||||
boost::filesystem::path data_path = "/var/lib/anbox";
|
boost::filesystem::path data_path = "/var/lib/anbox";
|
||||||
|
boost::filesystem::path resource_path = "/usr/share/anbox";
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,8 @@ namespace skeleton {
|
||||||
std::shared_ptr<Service> Service::create_for_bus(
|
std::shared_ptr<Service> Service::create_for_bus(
|
||||||
const core::dbus::Bus::Ptr &bus,
|
const core::dbus::Bus::Ptr &bus,
|
||||||
const std::shared_ptr<anbox::application::Manager> &application_manager) {
|
const std::shared_ptr<anbox::application::Manager> &application_manager) {
|
||||||
auto service = core::dbus::Service::add_service(
|
auto service = core::dbus::Service::add_service(bus, anbox::dbus::interface::Service::name());
|
||||||
bus, anbox::dbus::interface::Service::name());
|
auto object = service->add_object_for_path(anbox::dbus::interface::Service::path());
|
||||||
auto object =
|
|
||||||
service->add_object_for_path(anbox::dbus::interface::Service::path());
|
|
||||||
return std::make_shared<Service>(bus, service, object, application_manager);
|
return std::make_shared<Service>(bus, service, object, application_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace dbus {
|
||||||
namespace stub {
|
namespace stub {
|
||||||
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const core::dbus::Bus::Ptr &bus) {
|
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const core::dbus::Bus::Ptr &bus) {
|
||||||
auto service = core::dbus::Service::use_service_or_throw_if_not_available(bus, anbox::dbus::interface::Service::name());
|
auto service = core::dbus::Service::use_service_or_throw_if_not_available(bus, anbox::dbus::interface::Service::name());
|
||||||
auto object = service->add_object_for_path(anbox::dbus::interface::Service::path());
|
auto object = service->object_for_path(anbox::dbus::interface::Service::path());
|
||||||
return std::make_shared<ApplicationManager>(bus, service, object);
|
return std::make_shared<ApplicationManager>(bus, service, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
90
src/anbox/ui/splash_screen.cpp
Normal file
90
src/anbox/ui/splash_screen.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "anbox/ui/splash_screen.h"
|
||||||
|
#include "anbox/config.h"
|
||||||
|
#include "anbox/utils.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_image.h>
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace ui {
|
||||||
|
SplashScreen::SplashScreen() {
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
|
||||||
|
const auto message = utils::string_format("Failed to initialize SDL: %s", SDL_GetError());
|
||||||
|
BOOST_THROW_EXCEPTION(std::runtime_error(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto width = 1024, height = 768;
|
||||||
|
window_ = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto surface = SDL_GetWindowSurface(window_);
|
||||||
|
if (!surface)
|
||||||
|
BOOST_THROW_EXCEPTION(std::runtime_error("Could not retrieve surface for our window"));
|
||||||
|
|
||||||
|
SDL_FillRect(surface, nullptr, SDL_MapRGB(surface->format, 0xee, 0xee, 0xee));
|
||||||
|
SDL_UpdateWindowSurface(window_);
|
||||||
|
|
||||||
|
auto renderer = SDL_CreateRenderer(window_, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
if (!renderer)
|
||||||
|
BOOST_THROW_EXCEPTION(std::runtime_error("Could not create renderer"));
|
||||||
|
|
||||||
|
const auto icon_path = utils::string_format("%s/ui/loading-screen.png", SystemConfiguration::instance().resource_dir());
|
||||||
|
auto img = IMG_LoadTexture(renderer, icon_path.c_str());
|
||||||
|
if (!img) {
|
||||||
|
const auto msg = utils::string_format("Failed to create texture from %s", icon_path);
|
||||||
|
BOOST_THROW_EXCEPTION(std::runtime_error(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
SDL_Rect r{0, 0, width, height};
|
||||||
|
SDL_RenderCopy(renderer, img, nullptr, &r);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
|
||||||
|
SDL_ShowWindow(window_);
|
||||||
|
|
||||||
|
event_thread_ = std::thread(&SplashScreen::process_events, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
SplashScreen::~SplashScreen() {
|
||||||
|
if (event_thread_running_) {
|
||||||
|
event_thread_running_ = false;
|
||||||
|
if (event_thread_.joinable())
|
||||||
|
event_thread_.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window_)
|
||||||
|
SDL_DestroyWindow(window_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::process_events() {
|
||||||
|
event_thread_running_ = true;
|
||||||
|
while (event_thread_running_) {
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_WaitEventTimeout(&event, 100)) {
|
||||||
|
// Keep running until we're terminated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace anbox
|
||||||
42
src/anbox/ui/splash_screen.h
Normal file
42
src/anbox/ui/splash_screen.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ANBOX_UI_SPLASH_SCREEN_H_
|
||||||
|
#define ANBOX_UI_SPLASH_SCREEN_H_
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
namespace anbox {
|
||||||
|
namespace ui {
|
||||||
|
class SplashScreen {
|
||||||
|
public:
|
||||||
|
SplashScreen();
|
||||||
|
~SplashScreen();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_events();
|
||||||
|
|
||||||
|
std::thread event_thread_;
|
||||||
|
bool event_thread_running_;
|
||||||
|
SDL_Window *window_;
|
||||||
|
};
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace anbox
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue