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.
This commit is contained in:
Simon Fels 2017-03-16 17:03:50 +01:00
commit 3d0d453861
14 changed files with 180 additions and 53 deletions

View file

@ -116,7 +116,12 @@ public final class PlatformService {
if (icon == null) if (icon == null)
continue; 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(appInfo.packageName);
data.writeString(launchIntent.getAction()); data.writeString(launchIntent.getAction());

View file

@ -60,7 +60,6 @@ set(SOURCES
anbox/daemon.cpp anbox/daemon.cpp
anbox/config.cpp anbox/config.cpp
anbox/not_reachable.cpp anbox/not_reachable.cpp
anbox/application_manager.h
anbox/android/intent.cpp anbox/android/intent.cpp
@ -187,6 +186,7 @@ set(SOURCES
anbox/dbus/stub/application_manager.cpp anbox/dbus/stub/application_manager.cpp
anbox/application/launcher_storage.cpp anbox/application/launcher_storage.cpp
anbox/application/database.cpp
anbox/cmds/version.cpp anbox/cmds/version.cpp
anbox/cmds/session_manager.cpp anbox/cmds/session_manager.cpp

View file

@ -0,0 +1,58 @@
/*
* 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/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<LauncherStorage>(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

View file

@ -0,0 +1,58 @@
/*
* 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_APPLICATION_DATABASE_H_
#define ANBOX_APPLICATION_DATABASE_H_
#include "anbox/android/intent.h"
#include <string>
#include <map>
#include <memory>
namespace anbox {
namespace application {
class LauncherStorage;
class Database {
public:
struct Item {
std::string name;
std::string package;
android::Intent launch_intent;
std::vector<char> 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<LauncherStorage> storage_;
std::map<std::string,Item> items_;
};
} // namespace application
} // namespace anbox
#endif

View file

@ -33,18 +33,14 @@ constexpr const char *snap_exe_path{"/snap/bin/anbox"};
namespace anbox { namespace anbox {
namespace application { namespace application {
LauncherStorage::LauncherStorage(const fs::path &path, LauncherStorage::LauncherStorage(const fs::path &path) :
const boost::filesystem::path &icon_path) : path_(path), icon_path_(icon_path) { path_(path) {}
}
LauncherStorage::~LauncherStorage() {} LauncherStorage::~LauncherStorage() {}
void LauncherStorage::reset() { void LauncherStorage::reset() {
if (fs::exists(path_)) if (fs::exists(path_))
fs::remove_all(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) { 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) { 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(path_)) fs::create_directories(path_);
if (!fs::exists(icon_path_)) fs::create_directories(icon_path_);
auto package_name = item.package; auto package_name = item.package;
std::replace(package_name.begin(), package_name.end(), '.', '-'); 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); const auto item_icon_path = path_for_item_icon(package_name);
if (auto desktop_item = std::ofstream(path_for_item(package_name).string())) { if (auto desktop_item = std::ofstream(path_for_item(package_name).string())) {
desktop_item << "[Desktop Entry]" << std::endl desktop_item << "[Desktop Entry]" << std::endl
<< "Name=" << item.package << std::endl << "Name=" << item.name << std::endl
<< "Exec=" << exec << std::endl << "Exec=" << exec << std::endl
<< "Terminal=false" << std::endl << "Terminal=false" << std::endl
<< "Type=Application" << 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")); 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); auto package_name = clean_package_name(item.package);
const auto item_path = path_for_item(package_name); const auto item_path = path_for_item(package_name);

View file

@ -18,6 +18,7 @@
#ifndef ANBOX_APPLICATION_LAUNCHER_STORAGE_H_ #ifndef ANBOX_APPLICATION_LAUNCHER_STORAGE_H_
#define ANBOX_APPLICATION_LAUNCHER_STORAGE_H_ #define ANBOX_APPLICATION_LAUNCHER_STORAGE_H_
#include "anbox/application/database.h"
#include "anbox/android/intent.h" #include "anbox/android/intent.h"
#include <string> #include <string>
@ -29,20 +30,12 @@ namespace anbox {
namespace application { namespace application {
class LauncherStorage { class LauncherStorage {
public: public:
LauncherStorage(const boost::filesystem::path &path, LauncherStorage(const boost::filesystem::path &path);
const boost::filesystem::path &icon_path);
~LauncherStorage(); ~LauncherStorage();
struct Item {
std::string name;
std::string package;
android::Intent launch_intent;
std::vector<char> icon;
};
void reset(); void reset();
void add_or_update(const Item &item); void add_or_update(const Database::Item &item);
void remove(const Item &item); void remove(const Database::Item &item);
private: private:
std::string clean_package_name(const std::string &package_name); 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_for_item_icon(const std::string &package_name);
boost::filesystem::path path_; boost::filesystem::path path_;
boost::filesystem::path icon_path_;
}; };
} // namespace application } // namespace application
} // namespace anbox } // namespace anbox

View file

@ -16,7 +16,7 @@
*/ */
#include "anbox/bridge/platform_api_skeleton.h" #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/platform/policy.h"
#include "anbox/wm/manager.h" #include "anbox/wm/manager.h"
#include "anbox/wm/window_state.h" #include "anbox/wm/window_state.h"
@ -30,11 +30,11 @@ PlatformApiSkeleton::PlatformApiSkeleton(
const std::shared_ptr<rpc::PendingCallCache> &pending_calls, const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<platform::Policy> &platform_policy, const std::shared_ptr<platform::Policy> &platform_policy,
const std::shared_ptr<wm::Manager> &window_manager, const std::shared_ptr<wm::Manager> &window_manager,
const std::shared_ptr<application::LauncherStorage> &launcher_storage) const std::shared_ptr<application::Database> &app_db)
: pending_calls_(pending_calls), : pending_calls_(pending_calls),
platform_policy_(platform_policy), platform_policy_(platform_policy),
window_manager_(window_manager), window_manager_(window_manager),
launcher_storage_(launcher_storage) {} app_db_(app_db) {}
PlatformApiSkeleton::~PlatformApiSkeleton() {} PlatformApiSkeleton::~PlatformApiSkeleton() {}
@ -62,10 +62,7 @@ void PlatformApiSkeleton::get_clipboard_data(anbox::protobuf::rpc::Void const *r
done->Run(); done->Run();
} }
void PlatformApiSkeleton::handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event) { void PlatformApiSkeleton::handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent&) {
if (event.first_boot_done())
launcher_storage_->reset();
if (boot_finished_handler_) if (boot_finished_handler_)
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) { void PlatformApiSkeleton::handle_application_list_update_event(const anbox::protobuf::bridge::ApplicationListUpdateEvent &event) {
for (int n = 0; n < event.removed_applications_size(); n++) { 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); const auto app = event.removed_applications(n);
item.package = app.package(); item.package = app.package();
@ -107,11 +104,11 @@ void PlatformApiSkeleton::handle_application_list_update_event(const anbox::prot
if (item.package.empty()) if (item.package.empty())
continue; continue;
launcher_storage_->remove(item); app_db_->remove(item);
} }
for (int n = 0; n < event.applications_size(); n++) { for (int n = 0; n < event.applications_size(); n++) {
application::LauncherStorage::Item item; application::Database::Item item;
const auto app = event.applications(n); const auto app = event.applications(n);
item.name = app.name(); item.name = app.name();
@ -132,7 +129,7 @@ void PlatformApiSkeleton::handle_application_list_update_event(const anbox::prot
if (item.package.empty()) if (item.package.empty())
continue; continue;
launcher_storage_->add_or_update(item); app_db_->store_or_update(item);
} }
} }

View file

@ -48,7 +48,7 @@ namespace wm {
class Manager; class Manager;
} // namespace wm } // namespace wm
namespace application { namespace application {
class LauncherStorage; class Database;
} // namespace application } // namespace application
namespace bridge { namespace bridge {
class PlatformApiSkeleton { class PlatformApiSkeleton {
@ -57,7 +57,7 @@ class PlatformApiSkeleton {
const std::shared_ptr<rpc::PendingCallCache> &pending_calls, const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<platform::Policy> &platform_policy, const std::shared_ptr<platform::Policy> &platform_policy,
const std::shared_ptr<wm::Manager> &window_manager, const std::shared_ptr<wm::Manager> &window_manager,
const std::shared_ptr<application::LauncherStorage> &launcher_storage); const std::shared_ptr<application::Database> &app_db);
virtual ~PlatformApiSkeleton(); virtual ~PlatformApiSkeleton();
void set_clipboard_data(anbox::protobuf::bridge::ClipboardData const *request, void set_clipboard_data(anbox::protobuf::bridge::ClipboardData const *request,
@ -80,7 +80,7 @@ class PlatformApiSkeleton {
std::shared_ptr<rpc::PendingCallCache> pending_calls_; std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<platform::Policy> platform_policy_; std::shared_ptr<platform::Policy> platform_policy_;
std::shared_ptr<wm::Manager> window_manager_; std::shared_ptr<wm::Manager> window_manager_;
std::shared_ptr<application::LauncherStorage> launcher_storage_; std::shared_ptr<application::Database> app_db_;
std::function<void()> boot_finished_handler_; std::function<void()> boot_finished_handler_;
}; };
} // namespace bridge } // namespace bridge

View file

@ -22,6 +22,7 @@
#include "core/posix/signal.h" #include "core/posix/signal.h"
#include "anbox/application/launcher_storage.h" #include "anbox/application/launcher_storage.h"
#include "anbox/application/database.h"
#include "anbox/audio/server.h" #include "anbox/audio/server.h"
#include "anbox/bridge/android_api_stub.h" #include "anbox/bridge/android_api_stub.h"
#include "anbox/bridge/platform_api_skeleton.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 // FIXME this needs to be removed and solved differently behind the scenes
registerDisplayManager(policy); registerDisplayManager(policy);
auto window_manager = std::make_shared<wm::Manager>(policy); auto app_db = std::make_shared<application::Database>();
auto window_manager = std::make_shared<wm::Manager>(policy, app_db);
auto launcher_storage = std::make_shared<application::LauncherStorage>(
xdg::data().home() / "applications" / "anbox",
xdg::data().home() / "anbox" / "icons");
auto gl_server = std::make_shared<graphics::GLRendererServer>( auto gl_server = std::make_shared<graphics::GLRendererServer>(
graphics::GLRendererServer::Config{gles_driver_}, window_manager); 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); android_api_stub->set_rpc_channel(rpc_channel);
auto server = std::make_shared<bridge::PlatformApiSkeleton>( auto server = std::make_shared<bridge::PlatformApiSkeleton>(
pending_calls, policy, window_manager, launcher_storage); pending_calls, policy, window_manager, app_db);
server->register_boot_finished_handler([&]() { server->register_boot_finished_handler([&]() {
DEBUG("Android successfully booted"); DEBUG("Android successfully booted");
android_api_stub->ready().set(true); android_api_stub->ready().set(true);

View file

@ -19,6 +19,7 @@
#include "anbox/config.h" #include "anbox/config.h"
#include "anbox/utils.h" #include "anbox/utils.h"
#include "external/xdg/xdg.h"
#include <cstring> #include <cstring>
@ -70,6 +71,11 @@ std::string anbox::SystemConfiguration::input_device_dir() const {
return dir; 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() { anbox::SystemConfiguration& anbox::SystemConfiguration::instance() {
static SystemConfiguration config; static SystemConfiguration config;
return config; return config;

View file

@ -39,6 +39,7 @@ class SystemConfiguration {
std::string container_config_dir() const; std::string container_config_dir() const;
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;
protected: protected:
SystemConfiguration() = default; SystemConfiguration() = default;

View file

@ -16,6 +16,7 @@
*/ */
#include "anbox/wm/manager.h" #include "anbox/wm/manager.h"
#include "anbox/application/database.h"
#include "anbox/platform/policy.h" #include "anbox/platform/policy.h"
#include "anbox/logger.h" #include "anbox/logger.h"
@ -23,8 +24,9 @@
namespace anbox { namespace anbox {
namespace wm { namespace wm {
Manager::Manager(const std::shared_ptr<platform::Policy> &policy) Manager::Manager(const std::shared_ptr<platform::Policy> &policy,
: platform_policy_(policy) {} const std::shared_ptr<application::Database> &app_db)
: platform_policy_(policy), app_db_(app_db) {}
Manager::~Manager() {} Manager::~Manager() {}
@ -60,7 +62,12 @@ void Manager::apply_window_state_update(const WindowState::List &updated,
continue; 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(); platform_window->attach();
windows_.insert({window.task(), platform_window}); windows_.insert({window.task(), platform_window});
} }

View file

@ -26,13 +26,17 @@
#include <mutex> #include <mutex>
namespace anbox { namespace anbox {
namespace application {
class Database;
} // namespace application
namespace platform { namespace platform {
class Policy; class Policy;
} // namespace platform } // namespace platform
namespace wm { namespace wm {
class Manager { class Manager {
public: public:
Manager(const std::shared_ptr<platform::Policy> &policy); Manager(const std::shared_ptr<platform::Policy> &policy,
const std::shared_ptr<application::Database> &app_db);
~Manager(); ~Manager();
void apply_window_state_update(const WindowState::List &updated, void apply_window_state_update(const WindowState::List &updated,
@ -43,6 +47,7 @@ class Manager {
private: private:
std::mutex mutex_; std::mutex mutex_;
std::shared_ptr<platform::Policy> platform_policy_; std::shared_ptr<platform::Policy> platform_policy_;
std::shared_ptr<application::Database> app_db_;
std::map<Task::Id, std::shared_ptr<Window>> windows_; std::map<Task::Id, std::shared_ptr<Window>> windows_;
}; };
} // namespace wm } // namespace wm

View file

@ -20,6 +20,7 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "anbox/application/database.h"
#include "anbox/platform/default_policy.h" #include "anbox/platform/default_policy.h"
#include "anbox/wm/manager.h" #include "anbox/wm/manager.h"
#include "anbox/wm/window_state.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 // The default policy will create a dumb window instance when requested
// from the manager. // from the manager.
auto platform_policy = std::make_shared<platform::DefaultPolicy>(); auto platform_policy = std::make_shared<platform::DefaultPolicy>();
auto wm = std::make_shared<wm::Manager>(platform_policy); auto app_db = std::make_shared<application::Database>();
auto wm = std::make_shared<wm::Manager>(platform_policy, app_db);
auto single_window = wm::WindowState{ auto single_window = wm::WindowState{
wm::Display::Id{1}, wm::Display::Id{1},
@ -77,7 +79,8 @@ TEST(LayerComposer, MapsLayersToWindows) {
// The default policy will create a dumb window instance when requested // The default policy will create a dumb window instance when requested
// from the manager. // from the manager.
auto platform_policy = std::make_shared<platform::DefaultPolicy>(); auto platform_policy = std::make_shared<platform::DefaultPolicy>();
auto wm = std::make_shared<wm::Manager>(platform_policy); auto app_db = std::make_shared<application::Database>();
auto wm = std::make_shared<wm::Manager>(platform_policy, app_db);
auto first_window = wm::WindowState{ auto first_window = wm::WindowState{
wm::Display::Id{1}, wm::Display::Id{1},
@ -136,7 +139,8 @@ TEST(LayerComposer, WindowPartiallyOffscreen) {
// The default policy will create a dumb window instance when requested // The default policy will create a dumb window instance when requested
// from the manager. // from the manager.
auto platform_policy = std::make_shared<platform::DefaultPolicy>(); auto platform_policy = std::make_shared<platform::DefaultPolicy>();
auto wm = std::make_shared<wm::Manager>(platform_policy); auto app_db = std::make_shared<application::Database>();
auto wm = std::make_shared<wm::Manager>(platform_policy, app_db);
auto window = wm::WindowState{ auto window = wm::WindowState{
wm::Display::Id{1}, wm::Display::Id{1},
@ -180,7 +184,8 @@ TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) {
// The default policy will create a dumb window instance when requested // The default policy will create a dumb window instance when requested
// from the manager. // from the manager.
auto platform_policy = std::make_shared<platform::DefaultPolicy>(); auto platform_policy = std::make_shared<platform::DefaultPolicy>();
auto wm = std::make_shared<wm::Manager>(platform_policy); auto app_db = std::make_shared<application::Database>();
auto wm = std::make_shared<wm::Manager>(platform_policy, app_db);
auto window = wm::WindowState{ auto window = wm::WindowState{
wm::Display::Id{1}, wm::Display::Id{1},