提交 c4004459 编写于 作者: S Simon Fels

Add command to print various information about the system we're running on

上级 241e3cfd
......@@ -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
......
/*
* 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;
});
}
/*
* 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,
......
/*
* 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
/*
* 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册