From 3d0d453861798dc8038eb58bb7de190dc0389dc2 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Thu, 16 Mar 2017 17:03:50 +0100 Subject: [PATCH] Implement simple app database which maintains app information at runtime This helps us to collect information about an app (title, ..) we can reuse for certain other things like window construction. --- .../src/org/anbox/appmgr/PlatformService.java | 7 ++- src/CMakeLists.txt | 2 +- src/anbox/application/database.cpp | 58 +++++++++++++++++++ src/anbox/application/database.h | 58 +++++++++++++++++++ src/anbox/application/launcher_storage.cpp | 17 ++---- src/anbox/application/launcher_storage.h | 16 ++--- src/anbox/bridge/platform_api_skeleton.cpp | 19 +++--- src/anbox/bridge/platform_api_skeleton.h | 6 +- src/anbox/cmds/session_manager.cpp | 10 ++-- src/anbox/config.cpp | 6 ++ src/anbox/config.h | 1 + src/anbox/wm/manager.cpp | 13 ++++- src/anbox/wm/manager.h | 7 ++- tests/anbox/graphics/layer_composer_tests.cpp | 13 +++-- 14 files changed, 180 insertions(+), 53 deletions(-) create mode 100644 src/anbox/application/database.cpp create mode 100644 src/anbox/application/database.h diff --git a/android/appmgr/src/org/anbox/appmgr/PlatformService.java b/android/appmgr/src/org/anbox/appmgr/PlatformService.java index 3602f0e..68581aa 100644 --- a/android/appmgr/src/org/anbox/appmgr/PlatformService.java +++ b/android/appmgr/src/org/anbox/appmgr/PlatformService.java @@ -116,7 +116,12 @@ public final class PlatformService { if (icon == null) continue; - data.writeString(appInfo.name); + String name = appInfo.name; + CharSequence label = appInfo.loadLabel(mPm); + if (label != null) + name = label.toString(); + + data.writeString(name); data.writeString(appInfo.packageName); data.writeString(launchIntent.getAction()); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c43be36..6f80342 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,7 +60,6 @@ set(SOURCES anbox/daemon.cpp anbox/config.cpp anbox/not_reachable.cpp - anbox/application_manager.h anbox/android/intent.cpp @@ -187,6 +186,7 @@ set(SOURCES anbox/dbus/stub/application_manager.cpp anbox/application/launcher_storage.cpp + anbox/application/database.cpp anbox/cmds/version.cpp anbox/cmds/session_manager.cpp diff --git a/src/anbox/application/database.cpp b/src/anbox/application/database.cpp new file mode 100644 index 0000000..6010cf5 --- /dev/null +++ b/src/anbox/application/database.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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 . + * + */ + +#include "anbox/application/database.h" +#include "anbox/application/launcher_storage.h" +#include "anbox/config.h" +#include "anbox/logger.h" + +namespace anbox { +namespace application { +const Database::Item Database::Unknown{}; + +Database::Database() : + storage_(std::make_shared(SystemConfiguration::instance().application_item_dir())) { + storage_->reset(); +} + +Database::~Database() {} + +void Database::store_or_update(const Item &item) { + storage_->add_or_update(item); + items_[item.package] = item; + + // We don't need to store the icon data anymore at this point as the + // launcher is already stored it on the disk. + items_[item.package].icon.clear(); +} + +void Database::remove(const Item &item) { + auto iter = items_.find(item.package); + if (iter == items_.end()) + return; + storage_->remove(item); + items_.erase(iter); +} + +const Database::Item& Database::find_by_package(const std::string &package) const { + auto iter = items_.find(package); + if (iter == items_.end()) + return Unknown; + return iter->second; +} +} // namespace application +} // namespace anbox diff --git a/src/anbox/application/database.h b/src/anbox/application/database.h new file mode 100644 index 0000000..02aee1e --- /dev/null +++ b/src/anbox/application/database.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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_APPLICATION_DATABASE_H_ +#define ANBOX_APPLICATION_DATABASE_H_ + +#include "anbox/android/intent.h" + +#include +#include +#include + +namespace anbox { +namespace application { +class LauncherStorage; +class Database { + public: + struct Item { + std::string name; + std::string package; + android::Intent launch_intent; + std::vector icon; + + bool valid() const { return package.length() > 0; } + }; + + static const Item Unknown; + + Database(); + ~Database(); + + void store_or_update(const Item &item); + void remove(const Item &item); + + const Item& find_by_package(const std::string &package) const; + + private: + std::shared_ptr storage_; + std::map items_; +}; +} // namespace application +} // namespace anbox + +#endif diff --git a/src/anbox/application/launcher_storage.cpp b/src/anbox/application/launcher_storage.cpp index a94602d..2d038dd 100644 --- a/src/anbox/application/launcher_storage.cpp +++ b/src/anbox/application/launcher_storage.cpp @@ -33,18 +33,14 @@ constexpr const char *snap_exe_path{"/snap/bin/anbox"}; namespace anbox { namespace application { -LauncherStorage::LauncherStorage(const fs::path &path, - const boost::filesystem::path &icon_path) : path_(path), icon_path_(icon_path) { -} +LauncherStorage::LauncherStorage(const fs::path &path) : + path_(path) {} LauncherStorage::~LauncherStorage() {} void LauncherStorage::reset() { if (fs::exists(path_)) fs::remove_all(path_); - - if (fs::exists(icon_path_)) - fs::remove_all(icon_path_); } std::string LauncherStorage::clean_package_name(const std::string &package_name) { @@ -58,12 +54,11 @@ fs::path LauncherStorage::path_for_item(const std::string &package_name) { } fs::path LauncherStorage::path_for_item_icon(const std::string &package_name) { - return icon_path_ / utils::string_format("anbox-%s.png", package_name); + return path_ / utils::string_format("anbox-%s.png", package_name); } -void LauncherStorage::add_or_update(const Item &item) { +void LauncherStorage::add_or_update(const Database::Item &item) { if (!fs::exists(path_)) fs::create_directories(path_); - if (!fs::exists(icon_path_)) fs::create_directories(icon_path_); auto package_name = item.package; std::replace(package_name.begin(), package_name.end(), '.', '-'); @@ -92,7 +87,7 @@ void LauncherStorage::add_or_update(const Item &item) { const auto item_icon_path = path_for_item_icon(package_name); if (auto desktop_item = std::ofstream(path_for_item(package_name).string())) { desktop_item << "[Desktop Entry]" << std::endl - << "Name=" << item.package << std::endl + << "Name=" << item.name << std::endl << "Exec=" << exec << std::endl << "Terminal=false" << std::endl << "Type=Application" << std::endl @@ -107,7 +102,7 @@ void LauncherStorage::add_or_update(const Item &item) { BOOST_THROW_EXCEPTION(std::runtime_error("Failed to write icon")); } -void LauncherStorage::remove(const Item &item) { +void LauncherStorage::remove(const Database::Item &item) { auto package_name = clean_package_name(item.package); const auto item_path = path_for_item(package_name); diff --git a/src/anbox/application/launcher_storage.h b/src/anbox/application/launcher_storage.h index e045ea2..d7c5e79 100644 --- a/src/anbox/application/launcher_storage.h +++ b/src/anbox/application/launcher_storage.h @@ -18,6 +18,7 @@ #ifndef ANBOX_APPLICATION_LAUNCHER_STORAGE_H_ #define ANBOX_APPLICATION_LAUNCHER_STORAGE_H_ +#include "anbox/application/database.h" #include "anbox/android/intent.h" #include @@ -29,20 +30,12 @@ namespace anbox { namespace application { class LauncherStorage { public: - LauncherStorage(const boost::filesystem::path &path, - const boost::filesystem::path &icon_path); + LauncherStorage(const boost::filesystem::path &path); ~LauncherStorage(); - struct Item { - std::string name; - std::string package; - android::Intent launch_intent; - std::vector icon; - }; - void reset(); - void add_or_update(const Item &item); - void remove(const Item &item); + void add_or_update(const Database::Item &item); + void remove(const Database::Item &item); private: std::string clean_package_name(const std::string &package_name); @@ -50,7 +43,6 @@ class LauncherStorage { boost::filesystem::path path_for_item_icon(const std::string &package_name); boost::filesystem::path path_; - boost::filesystem::path icon_path_; }; } // namespace application } // namespace anbox diff --git a/src/anbox/bridge/platform_api_skeleton.cpp b/src/anbox/bridge/platform_api_skeleton.cpp index 221577d..c8eb9e2 100644 --- a/src/anbox/bridge/platform_api_skeleton.cpp +++ b/src/anbox/bridge/platform_api_skeleton.cpp @@ -16,7 +16,7 @@ */ #include "anbox/bridge/platform_api_skeleton.h" -#include "anbox/application/launcher_storage.h" +#include "anbox/application/database.h" #include "anbox/platform/policy.h" #include "anbox/wm/manager.h" #include "anbox/wm/window_state.h" @@ -30,11 +30,11 @@ 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) + const std::shared_ptr &app_db) : pending_calls_(pending_calls), platform_policy_(platform_policy), window_manager_(window_manager), - launcher_storage_(launcher_storage) {} + app_db_(app_db) {} PlatformApiSkeleton::~PlatformApiSkeleton() {} @@ -62,10 +62,7 @@ void PlatformApiSkeleton::get_clipboard_data(anbox::protobuf::rpc::Void const *r done->Run(); } -void PlatformApiSkeleton::handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event) { - if (event.first_boot_done()) - launcher_storage_->reset(); - +void PlatformApiSkeleton::handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent&) { if (boot_finished_handler_) boot_finished_handler_(); } @@ -99,7 +96,7 @@ void PlatformApiSkeleton::handle_window_state_update_event(const anbox::protobuf void PlatformApiSkeleton::handle_application_list_update_event(const anbox::protobuf::bridge::ApplicationListUpdateEvent &event) { for (int n = 0; n < event.removed_applications_size(); n++) { - application::LauncherStorage::Item item; + application::Database::Item item; const auto app = event.removed_applications(n); item.package = app.package(); @@ -107,11 +104,11 @@ void PlatformApiSkeleton::handle_application_list_update_event(const anbox::prot if (item.package.empty()) continue; - launcher_storage_->remove(item); + app_db_->remove(item); } for (int n = 0; n < event.applications_size(); n++) { - application::LauncherStorage::Item item; + application::Database::Item item; const auto app = event.applications(n); item.name = app.name(); @@ -132,7 +129,7 @@ void PlatformApiSkeleton::handle_application_list_update_event(const anbox::prot if (item.package.empty()) continue; - launcher_storage_->add_or_update(item); + app_db_->store_or_update(item); } } diff --git a/src/anbox/bridge/platform_api_skeleton.h b/src/anbox/bridge/platform_api_skeleton.h index 6b4e25b..7a9891b 100644 --- a/src/anbox/bridge/platform_api_skeleton.h +++ b/src/anbox/bridge/platform_api_skeleton.h @@ -48,7 +48,7 @@ namespace wm { class Manager; } // namespace wm namespace application { -class LauncherStorage; +class Database; } // namespace application namespace bridge { class PlatformApiSkeleton { @@ -57,7 +57,7 @@ class 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); + const std::shared_ptr &app_db); virtual ~PlatformApiSkeleton(); void set_clipboard_data(anbox::protobuf::bridge::ClipboardData const *request, @@ -80,7 +80,7 @@ class PlatformApiSkeleton { std::shared_ptr pending_calls_; std::shared_ptr platform_policy_; std::shared_ptr window_manager_; - std::shared_ptr launcher_storage_; + std::shared_ptr app_db_; std::function boot_finished_handler_; }; } // namespace bridge diff --git a/src/anbox/cmds/session_manager.cpp b/src/anbox/cmds/session_manager.cpp index a408fdd..15de80c 100644 --- a/src/anbox/cmds/session_manager.cpp +++ b/src/anbox/cmds/session_manager.cpp @@ -22,6 +22,7 @@ #include "core/posix/signal.h" #include "anbox/application/launcher_storage.h" +#include "anbox/application/database.h" #include "anbox/audio/server.h" #include "anbox/bridge/android_api_stub.h" #include "anbox/bridge/platform_api_skeleton.h" @@ -139,11 +140,8 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) // FIXME this needs to be removed and solved differently behind the scenes registerDisplayManager(policy); - auto window_manager = std::make_shared(policy); - - auto launcher_storage = std::make_shared( - xdg::data().home() / "applications" / "anbox", - xdg::data().home() / "anbox" / "icons"); + auto app_db = std::make_shared(); + auto window_manager = std::make_shared(policy, app_db); auto gl_server = std::make_shared( graphics::GLRendererServer::Config{gles_driver_}, window_manager); @@ -175,7 +173,7 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) android_api_stub->set_rpc_channel(rpc_channel); auto server = std::make_shared( - pending_calls, policy, window_manager, launcher_storage); + pending_calls, policy, window_manager, app_db); server->register_boot_finished_handler([&]() { DEBUG("Android successfully booted"); android_api_stub->ready().set(true); diff --git a/src/anbox/config.cpp b/src/anbox/config.cpp index 134d10d..7c0961e 100644 --- a/src/anbox/config.cpp +++ b/src/anbox/config.cpp @@ -19,6 +19,7 @@ #include "anbox/config.h" #include "anbox/utils.h" +#include "external/xdg/xdg.h" #include @@ -70,6 +71,11 @@ std::string anbox::SystemConfiguration::input_device_dir() const { return dir; } +std::string anbox::SystemConfiguration::application_item_dir() const { + static auto dir = xdg::data().home() / "applications" / "anbox"; + return dir.string(); +} + anbox::SystemConfiguration& anbox::SystemConfiguration::instance() { static SystemConfiguration config; return config; diff --git a/src/anbox/config.h b/src/anbox/config.h index 6d1b19d..91f72c6 100644 --- a/src/anbox/config.h +++ b/src/anbox/config.h @@ -39,6 +39,7 @@ class SystemConfiguration { std::string container_config_dir() const; std::string container_socket_path() const; std::string input_device_dir() const; + std::string application_item_dir() const; protected: SystemConfiguration() = default; diff --git a/src/anbox/wm/manager.cpp b/src/anbox/wm/manager.cpp index f5b786c..779f257 100644 --- a/src/anbox/wm/manager.cpp +++ b/src/anbox/wm/manager.cpp @@ -16,6 +16,7 @@ */ #include "anbox/wm/manager.h" +#include "anbox/application/database.h" #include "anbox/platform/policy.h" #include "anbox/logger.h" @@ -23,8 +24,9 @@ namespace anbox { namespace wm { -Manager::Manager(const std::shared_ptr &policy) - : platform_policy_(policy) {} +Manager::Manager(const std::shared_ptr &policy, + const std::shared_ptr &app_db) + : platform_policy_(policy), app_db_(app_db) {} Manager::~Manager() {} @@ -60,7 +62,12 @@ void Manager::apply_window_state_update(const WindowState::List &updated, continue; } - auto platform_window = platform_policy_->create_window(window.task(), window.frame(), window.package_name()); + auto title = window.package_name(); + auto app = app_db_->find_by_package(window.package_name()); + if (app.valid()) + title = app.name; + + auto platform_window = platform_policy_->create_window(window.task(), window.frame(), title); platform_window->attach(); windows_.insert({window.task(), platform_window}); } diff --git a/src/anbox/wm/manager.h b/src/anbox/wm/manager.h index 5e81024..8fda1c9 100644 --- a/src/anbox/wm/manager.h +++ b/src/anbox/wm/manager.h @@ -26,13 +26,17 @@ #include namespace anbox { +namespace application { +class Database; +} // namespace application namespace platform { class Policy; } // namespace platform namespace wm { class Manager { public: - Manager(const std::shared_ptr &policy); + Manager(const std::shared_ptr &policy, + const std::shared_ptr &app_db); ~Manager(); void apply_window_state_update(const WindowState::List &updated, @@ -43,6 +47,7 @@ class Manager { private: std::mutex mutex_; std::shared_ptr platform_policy_; + std::shared_ptr app_db_; std::map> windows_; }; } // namespace wm diff --git a/tests/anbox/graphics/layer_composer_tests.cpp b/tests/anbox/graphics/layer_composer_tests.cpp index 2ed0394..b2ef1cc 100644 --- a/tests/anbox/graphics/layer_composer_tests.cpp +++ b/tests/anbox/graphics/layer_composer_tests.cpp @@ -20,6 +20,7 @@ #include #include +#include "anbox/application/database.h" #include "anbox/platform/default_policy.h" #include "anbox/wm/manager.h" #include "anbox/wm/window_state.h" @@ -44,7 +45,8 @@ TEST(LayerComposer, FindsNoSuitableWindowForLayer) { // The default policy will create a dumb window instance when requested // from the manager. auto platform_policy = std::make_shared(); - auto wm = std::make_shared(platform_policy); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform_policy, app_db); auto single_window = wm::WindowState{ wm::Display::Id{1}, @@ -77,7 +79,8 @@ TEST(LayerComposer, MapsLayersToWindows) { // The default policy will create a dumb window instance when requested // from the manager. auto platform_policy = std::make_shared(); - auto wm = std::make_shared(platform_policy); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform_policy, app_db); auto first_window = wm::WindowState{ wm::Display::Id{1}, @@ -136,7 +139,8 @@ TEST(LayerComposer, WindowPartiallyOffscreen) { // The default policy will create a dumb window instance when requested // from the manager. auto platform_policy = std::make_shared(); - auto wm = std::make_shared(platform_policy); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform_policy, app_db); auto window = wm::WindowState{ wm::Display::Id{1}, @@ -180,7 +184,8 @@ TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) { // The default policy will create a dumb window instance when requested // from the manager. auto platform_policy = std::make_shared(); - auto wm = std::make_shared(platform_policy); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform_policy, app_db); auto window = wm::WindowState{ wm::Display::Id{1},