Add command to print various information about the system we're running on
This commit is contained in:
parent
241e3cfdfa
commit
c4004459dd
11 changed files with 356 additions and 8 deletions
|
|
@ -192,6 +192,9 @@ set(SOURCES
|
|||
anbox/cmds/session_manager.cpp
|
||||
anbox/cmds/container_manager.cpp
|
||||
anbox/cmds/launch.cpp
|
||||
anbox/cmds/system_info.cpp
|
||||
|
||||
anbox/utils/environment_file.cpp
|
||||
|
||||
anbox/do_not_copy_or_move.h
|
||||
anbox/optional.h
|
||||
|
|
|
|||
203
src/anbox/cmds/system_info.cpp
Normal file
203
src/anbox/cmds/system_info.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* 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 Lesser General Public License as published by
|
||||
* the Free Software Foundation; version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "anbox/cmds/system_info.h"
|
||||
#include "anbox/graphics/emugl/RenderApi.h"
|
||||
#include "anbox/graphics/emugl/DispatchTables.h"
|
||||
#include "anbox/utils/environment_file.h"
|
||||
#include "anbox/version.h"
|
||||
#include "anbox/logger.h"
|
||||
#include "anbox/version.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "OpenGLESDispatch/EGLDispatch.h"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace {
|
||||
constexpr const char *os_release_path{"/etc/os-release"};
|
||||
constexpr const char *proc_version_path{"/proc/version"};
|
||||
constexpr const char *binder_path{"/dev/binder"};
|
||||
constexpr const char *ashmem_path{"/dev/ashmem"};
|
||||
|
||||
class SystemInformation {
|
||||
public:
|
||||
SystemInformation() {
|
||||
collect_os_info();
|
||||
collect_kernel_info();
|
||||
collect_graphics_info();
|
||||
}
|
||||
|
||||
std::string to_text() const {
|
||||
std::stringstream s;
|
||||
|
||||
s << "version: "
|
||||
<< anbox::utils::string_format("%d.%d.%d",
|
||||
anbox::build::version_major,
|
||||
anbox::build::version_minor,
|
||||
anbox::build::version_patch)
|
||||
<< std::endl;
|
||||
|
||||
s << "os:" << std::endl
|
||||
<< " name: " << os_info_.name << std::endl
|
||||
<< " version: " << os_info_.version << std::endl
|
||||
<< " snap-based: " << std::boolalpha << os_info_.snap_based << std::endl;
|
||||
|
||||
s << "kernel:" << std::endl
|
||||
<< " version: " << kernel_info_.version << std::endl
|
||||
<< " binder: " << std::boolalpha << kernel_info_.binder << std::endl
|
||||
<< " ashmem: " << std::boolalpha << kernel_info_.ashmem << std::endl;
|
||||
|
||||
auto print_extensions = [](const std::vector<std::string> &extensions) {
|
||||
std::stringstream s;
|
||||
if (extensions.size() > 0) {
|
||||
s << std::endl;
|
||||
for (const auto &ext : extensions) {
|
||||
if (ext.length() == 0)
|
||||
continue;
|
||||
s << " - " << ext << std::endl;
|
||||
}
|
||||
} else {
|
||||
s << " []" << std::endl;
|
||||
}
|
||||
return s.str();
|
||||
};
|
||||
|
||||
s << "graphics:" << std::endl
|
||||
<< " egl:" << std::endl
|
||||
<< " vendor: " << graphics_info_.egl_vendor << std::endl
|
||||
<< " version: " << graphics_info_.egl_version << std::endl
|
||||
<< " extensions:" << print_extensions(graphics_info_.egl_extensions)
|
||||
<< " gles2:" << std::endl
|
||||
<< " vendor: " << graphics_info_.gles2_vendor << std::endl
|
||||
<< " vendor: " << graphics_info_.gles2_version << std::endl
|
||||
<< " extensions:" << print_extensions(graphics_info_.gles2_extensions);
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
private:
|
||||
void collect_os_info() {
|
||||
os_info_.snap_based = (getenv("SNAP") != nullptr);
|
||||
if (fs::exists(os_release_path)) {
|
||||
anbox::utils::EnvironmentFile os_release(os_release_path);
|
||||
os_info_.name = os_release.value("NAME");
|
||||
os_info_.version = os_release.value("VERSION");
|
||||
} else if (os_info_.snap_based) {
|
||||
// As we can't read /etc/os-release and we're snap-based this is the best we can guess
|
||||
os_info_.name = "Ubuntu";
|
||||
os_info_.version = "16";
|
||||
}
|
||||
}
|
||||
|
||||
void collect_kernel_info() {
|
||||
if (fs::exists(proc_version_path)) {
|
||||
std::ifstream in(proc_version_path);
|
||||
std::getline(in, kernel_info_.version);
|
||||
}
|
||||
|
||||
kernel_info_.binder = fs::exists(binder_path);
|
||||
kernel_info_.ashmem = fs::exists(ashmem_path);
|
||||
}
|
||||
|
||||
void collect_graphics_info() {
|
||||
auto gl_libs = anbox::graphics::emugl::default_gl_libraries(true);
|
||||
if (!anbox::graphics::emugl::initialize(gl_libs, nullptr, nullptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto display = s_egl.eglGetDisplay(0);
|
||||
if (display != EGL_NO_DISPLAY) {
|
||||
s_egl.eglInitialize(display, nullptr, nullptr);
|
||||
graphics_info_.egl_vendor = s_egl.eglQueryString(display, EGL_VENDOR);
|
||||
graphics_info_.egl_version = s_egl.eglQueryString(display, EGL_VERSION);
|
||||
graphics_info_.egl_extensions = anbox::utils::string_split(s_egl.eglQueryString(display, EGL_EXTENSIONS), ' ');
|
||||
|
||||
GLint config_attribs[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
|
||||
EGL_NONE};
|
||||
|
||||
EGLConfig config;
|
||||
int n;
|
||||
if (s_egl.eglChooseConfig(display, config_attribs, &config, 1, &n) && n > 0) {
|
||||
GLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE};
|
||||
auto context = s_egl.eglCreateContext(display, config, nullptr, attribs);
|
||||
if (context != EGL_NO_CONTEXT) {
|
||||
// We require surfaceless-context support here for now. If eglMakeCurrent fails
|
||||
// glGetString will return null below which we handle correctly.
|
||||
s_egl.eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context);
|
||||
|
||||
auto safe_get_string = [](GLint item) {
|
||||
auto str = s_gles2.glGetString(item);
|
||||
if (!str)
|
||||
return std::string("n/a");
|
||||
return std::string(reinterpret_cast<const char*>(str));
|
||||
};
|
||||
|
||||
graphics_info_.gles2_vendor = safe_get_string(GL_VENDOR);
|
||||
graphics_info_.gles2_version = safe_get_string(GL_VERSION);
|
||||
graphics_info_.gles2_extensions = anbox::utils::string_split(safe_get_string(GL_EXTENSIONS), ' ');
|
||||
|
||||
s_egl.eglMakeCurrent(display, nullptr, nullptr, nullptr);
|
||||
s_egl.eglDestroyContext(display, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
bool snap_based = false;
|
||||
std::string name = "n/a";
|
||||
std::string version = "n/a";
|
||||
} os_info_;
|
||||
|
||||
struct {
|
||||
std::string version = "n/a";
|
||||
bool binder = false;
|
||||
bool ashmem = false;
|
||||
} kernel_info_;
|
||||
|
||||
struct {
|
||||
std::string egl_vendor = "n/a";
|
||||
std::string egl_version = "n/a";
|
||||
std::vector<std::string> egl_extensions;
|
||||
std::string gles2_vendor = "n/a";
|
||||
std::string gles2_version = "n/a";
|
||||
std::vector<std::string> gles2_extensions;
|
||||
} graphics_info_;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const SystemInformation &info) {
|
||||
out << info.to_text();
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
anbox::cmds::SystemInfo::SystemInfo()
|
||||
: CommandWithFlagsAndAction{
|
||||
cli::Name{"system-info"}, cli::Usage{"system-info"},
|
||||
cli::Description{"Print various information about the system we're running on"}} {
|
||||
action([](const cli::Command::Context& ctxt) {
|
||||
SystemInformation si;
|
||||
std::cout << si;
|
||||
return EXIT_SUCCESS;
|
||||
});
|
||||
}
|
||||
36
src/anbox/cmds/system_info.h
Normal file
36
src/anbox/cmds/system_info.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 Lesser General Public License as published by
|
||||
* the Free Software Foundation; version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_CMDS_SYSTEM_INFO_H_
|
||||
#define ANBOX_CMDS_SYSTEM_INFO_H_
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "anbox/cli.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace cmds {
|
||||
class SystemInfo : public cli::CommandWithFlagsAndAction {
|
||||
public:
|
||||
SystemInfo();
|
||||
};
|
||||
} // namespace cmds
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "anbox/cmds/container_manager.h"
|
||||
#include "anbox/cmds/session_manager.h"
|
||||
#include "anbox/cmds/system_info.h"
|
||||
#include "anbox/cmds/launch.h"
|
||||
#include "anbox/cmds/version.h"
|
||||
|
||||
|
|
@ -38,12 +39,14 @@ Daemon::Daemon()
|
|||
cmd.command(std::make_shared<cmds::Version>())
|
||||
.command(std::make_shared<cmds::SessionManager>())
|
||||
.command(std::make_shared<cmds::Launch>())
|
||||
.command(std::make_shared<cmds::ContainerManager>());
|
||||
.command(std::make_shared<cmds::ContainerManager>())
|
||||
.command(std::make_shared<cmds::SystemInfo>());
|
||||
|
||||
|
||||
Log().Init(anbox::Logger::Severity::kWarning);
|
||||
|
||||
const auto log_level = utils::get_env_value("ANBOX_LOG_LEVEL", "");
|
||||
if (!log_level.empty() || !Log().SetSeverityFromString(log_level))
|
||||
if (!log_level.empty() && !Log().SetSeverityFromString(log_level))
|
||||
WARNING("Failed to set logging severity to '%s'", log_level);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,10 +49,12 @@ std::vector<GLLibrary> default_gl_libraries(bool no_glesv1) {
|
|||
};
|
||||
}
|
||||
|
||||
bool initialize(const std::vector<GLLibrary> &libs, emugl_logger_struct log_funcs, logger_t crash_func) {
|
||||
bool initialize(const std::vector<GLLibrary> &libs, emugl_logger_struct *log_funcs, logger_t crash_func) {
|
||||
set_emugl_crash_reporter(crash_func);
|
||||
set_emugl_logger(log_funcs.coarse);
|
||||
set_emugl_cxt_logger(log_funcs.fine);
|
||||
if (log_funcs) {
|
||||
set_emugl_logger(log_funcs->coarse);
|
||||
set_emugl_cxt_logger(log_funcs->fine);
|
||||
}
|
||||
|
||||
for (const auto &lib : libs) {
|
||||
const auto path = lib.path.c_str();
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ struct GLLibrary {
|
|||
|
||||
std::vector<GLLibrary> default_gl_libraries(bool no_glesv1 = false);
|
||||
|
||||
bool initialize(const std::vector<GLLibrary> &libs, emugl_logger_struct log_funcs, logger_t crash_func);
|
||||
bool initialize(const std::vector<GLLibrary> &libs, emugl_logger_struct *log_funcs, logger_t crash_func);
|
||||
} // namespace emugl
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ GLRendererServer::GLRendererServer(const Config &config, const std::shared_ptr<w
|
|||
wm_(wm),
|
||||
composer_(std::make_shared<LayerComposer>(renderer_, wm)) {
|
||||
|
||||
std::vector<emugl::GLLibrary> gl_libs = emugl::default_gl_libraries(true);
|
||||
auto gl_libs = emugl::default_gl_libraries(true);
|
||||
|
||||
if (config.driver == Config::Driver::Translator) {
|
||||
DEBUG("Using GLES-to-GL translator for rendering");
|
||||
|
|
@ -82,7 +82,7 @@ GLRendererServer::GLRendererServer(const Config &config, const std::shared_ptr<w
|
|||
log_funcs.coarse = logger_write;
|
||||
log_funcs.fine = logger_write;
|
||||
|
||||
if (!emugl::initialize(gl_libs, log_funcs, nullptr))
|
||||
if (!emugl::initialize(gl_libs, &log_funcs, nullptr))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
|
||||
|
||||
renderer_->initialize(0);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
|
@ -95,6 +97,18 @@ bool string_starts_with(const std::string &text, const std::string &prefix) {
|
|||
return text.compare(0, prefix.size(), prefix) == 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> string_split(const std::string &text, char sep) {
|
||||
std::vector<std::string> tokens;
|
||||
return boost::algorithm::split(tokens, text, boost::is_from_range(sep, sep), boost::algorithm::token_compress_on);
|
||||
}
|
||||
|
||||
std::string strip_surrounding_quotes(const std::string &text) {
|
||||
auto result = text;
|
||||
if (text[0] == '\"' && text[text.length() - 1] == '\"')
|
||||
result = text.substr(1, text.length() - 2);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string hex_dump(const uint8_t *data, uint32_t size) {
|
||||
unsigned char buff[17];
|
||||
const uint8_t *pc = data;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ int write_file_at(int dirfd, const char *path, const char *content);
|
|||
|
||||
bool string_starts_with(const std::string &text, const std::string &prefix);
|
||||
|
||||
std::vector<std::string> string_split(const std::string &text, char sep);
|
||||
|
||||
std::string strip_surrounding_quotes(const std::string &text);
|
||||
|
||||
std::string hex_dump(const uint8_t *data, uint32_t size);
|
||||
|
||||
std::string get_env_value(const std::string &name,
|
||||
|
|
|
|||
43
src/anbox/utils/environment_file.cpp
Normal file
43
src/anbox/utils/environment_file.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 Lesser General Public License as published by
|
||||
* the Free Software Foundation; version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "anbox/utils/environment_file.h"
|
||||
#include "anbox/utils.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace anbox {
|
||||
namespace utils {
|
||||
EnvironmentFile::EnvironmentFile(const boost::filesystem::path &path) {
|
||||
std::ifstream in(path.string());
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
auto tokens = utils::string_split(line, '=');
|
||||
if (tokens.size() != 2)
|
||||
continue;
|
||||
data_[tokens[0]] = utils::strip_surrounding_quotes(tokens[1]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string EnvironmentFile::value(const std::string &key, const std::string &default_value) const {
|
||||
auto iter = data_.find(key);
|
||||
if (iter == data_.end())
|
||||
return default_value;
|
||||
return iter->second;
|
||||
}
|
||||
} // namespace utils
|
||||
} // namespace anbox
|
||||
40
src/anbox/utils/environment_file.h
Normal file
40
src/anbox/utils/environment_file.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 Lesser General Public License as published by
|
||||
* the Free Software Foundation; version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_UTILS_ENVIRONMENT_FILE_H_
|
||||
#define ANBOX_UTILS_ENVIRONMENT_FILE_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace anbox {
|
||||
namespace utils {
|
||||
class EnvironmentFile {
|
||||
public:
|
||||
EnvironmentFile(const boost::filesystem::path &path);
|
||||
~EnvironmentFile() = default;
|
||||
|
||||
std::string value(const std::string &key, const std::string &default_value = "") const;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> data_;
|
||||
};
|
||||
} // namespace utils
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue