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)
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());

View file

@ -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

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 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);

View file

@ -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 <string>
@ -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<char> 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

View file

@ -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<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<platform::Policy> &platform_policy,
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),
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);
}
}

View file

@ -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<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<platform::Policy> &platform_policy,
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();
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<platform::Policy> platform_policy_;
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_;
};
} // namespace bridge

View file

@ -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<wm::Manager>(policy);
auto launcher_storage = std::make_shared<application::LauncherStorage>(
xdg::data().home() / "applications" / "anbox",
xdg::data().home() / "anbox" / "icons");
auto app_db = std::make_shared<application::Database>();
auto window_manager = std::make_shared<wm::Manager>(policy, app_db);
auto gl_server = std::make_shared<graphics::GLRendererServer>(
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<bridge::PlatformApiSkeleton>(
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);

View file

@ -19,6 +19,7 @@
#include "anbox/config.h"
#include "anbox/utils.h"
#include "external/xdg/xdg.h"
#include <cstring>
@ -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;

View file

@ -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;

View file

@ -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<platform::Policy> &policy)
: platform_policy_(policy) {}
Manager::Manager(const std::shared_ptr<platform::Policy> &policy,
const std::shared_ptr<application::Database> &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});
}

View file

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

View file

@ -20,6 +20,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#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<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{
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<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{
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<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{
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<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{
wm::Display::Id{1},