Merge pull request #62 from morphis/f/maintain-app-info

Implement simple app database which maintains app information at runtime
This commit is contained in:
Simon Fels 2017-03-17 07:13:52 +01:00 • committed by GitHub
commit 572c80c6a9
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},