b99941764893b769bb12335211668696385639ad
[iec.git] / src / type3_AndroidCloud / anbox-master / src / anbox / cmds / system_info.cpp
1 /*
2  * Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17
18 #include "anbox/cmds/system_info.h"
19 #include "anbox/graphics/emugl/RenderApi.h"
20 #include "anbox/graphics/emugl/DispatchTables.h"
21 #include "anbox/utils/environment_file.h"
22 #include "anbox/logger.h"
23
24 #include "anbox/build/config.h"
25
26 #include <sstream>
27 #include <fstream>
28
29 #include <boost/filesystem.hpp>
30
31 #include "OpenGLESDispatch/EGLDispatch.h"
32
33 #include "cpu_features_macros.h"
34 #if defined(CPU_FEATURES_ARCH_X86)
35 #include "cpuinfo_x86.h"
36 #endif
37
38 namespace fs = boost::filesystem;
39
40 namespace {
41 constexpr const char *os_release_path{"/etc/os-release"};
42 constexpr const char *host_os_release_path{"/var/lib/snapd/hostfs/etc/os-release"};
43 constexpr const char *proc_version_path{"/proc/version"};
44 constexpr const char *binder_path{"/dev/binder"};
45 constexpr const char *ashmem_path{"/dev/ashmem"};
46 constexpr const char *os_release_name{"NAME"};
47 constexpr const char *os_release_version{"VERSION"};
48
49 class SystemInformation {
50  public:
51   SystemInformation() {
52     collect_cpu_info();
53     collect_os_info();
54     collect_kernel_info();
55     collect_graphics_info();
56   }
57
58   std::string to_text() const {
59     std::stringstream s;
60
61     s << "version: "
62       << anbox::build::version
63       << std::endl;
64
65     if (anbox::utils::is_env_set("SNAP_REVISION")) {
66       s << "snap-revision: "
67         << anbox::utils::get_env_value("SNAP_REVISION")
68         << std::endl;
69     }
70
71     s << "cpu:" << std::endl
72       << "  arch:  " << cpu_info_.arch << std::endl
73       << "  brand: " << cpu_info_.brand << std::endl
74       << "  features: " << std::endl;
75     for (const auto& feature : cpu_info_.features)
76       s << "    - " << feature << std::endl;
77
78     s << "os:" << std::endl
79       << "  name: " << os_info_.name << std::endl
80       << "  version: " << os_info_.version << std::endl
81       << "  snap-based: " << std::boolalpha << os_info_.snap_based << std::endl;
82
83     s << "kernel:" << std::endl
84       << "  version: " << kernel_info_.version << std::endl
85       << "  binder: " << std::boolalpha << kernel_info_.binder << std::endl
86       << "  ashmem: " << std::boolalpha << kernel_info_.ashmem << std::endl;
87
88     auto print_extensions = [](const std::vector<std::string> &extensions) {
89       std::stringstream s;
90       if (extensions.size() > 0) {
91         s << std::endl;
92         for (const auto &ext : extensions) {
93           if (ext.length() == 0)
94             continue;
95           s << "      - " << ext << std::endl;
96         }
97       } else {
98         s << " []" << std::endl;
99       }
100       return s.str();
101     };
102
103     s << "graphics:" << std::endl
104       << "  egl:" << std::endl
105       << "    vendor: " << graphics_info_.egl_vendor << std::endl
106       << "    version: " << graphics_info_.egl_version << std::endl
107       << "    extensions:" << print_extensions(graphics_info_.egl_extensions)
108       << "  gles2:" << std::endl
109       << "    vendor: " << graphics_info_.gles2_vendor << std::endl
110       << "    vendor: " << graphics_info_.gles2_version << std::endl
111       << "    extensions:" << print_extensions(graphics_info_.gles2_extensions);
112
113     return s.str();
114   }
115
116  private:
117   void collect_cpu_info() {
118 #if defined(CPU_FEATURES_ARCH_X86)
119   cpu_info_.arch = "x86";
120
121   const auto info = cpu_features::GetX86Info();
122   if (info.features.aes)
123     cpu_info_.features.push_back("aes");
124   if (info.features.sse4_1)
125     cpu_info_.features.push_back("sse4_1");
126   if (info.features.sse4_2)
127     cpu_info_.features.push_back("sse4_2");
128   if (info.features.avx)
129     cpu_info_.features.push_back("avx");
130   if (info.features.avx2)
131     cpu_info_.features.push_back("avx2");
132
133   char brand_string[49];
134   cpu_features::FillX86BrandString(brand_string);
135   cpu_info_.brand = brand_string;
136 #endif
137   }
138
139   void collect_os_info() {
140     os_info_.snap_based = !anbox::utils::get_env_value("SNAP").empty();
141     fs::path path = os_release_path;
142     // If we're running from within a snap the best we can do is to
143     // access the hostfs and read the os-release file from there.
144     if (os_info_.snap_based && fs::exists(host_os_release_path))
145         path = host_os_release_path;
146
147     // Double check that there aren't any permission errors when trying
148     // to access the file (e.g. because of snap confinement)
149     if (fs::exists(path)) {
150       anbox::utils::EnvironmentFile os_release(path);
151       os_info_.name = os_release.value(os_release_name);
152       os_info_.version = os_release.value(os_release_version);
153     }
154   }
155
156   void collect_kernel_info() {
157     if (fs::exists(proc_version_path)) {
158       std::ifstream in(proc_version_path);
159       std::getline(in, kernel_info_.version);
160     }
161
162     kernel_info_.binder = fs::exists(binder_path);
163     kernel_info_.ashmem = fs::exists(ashmem_path);
164   }
165
166   void collect_graphics_info() {
167     auto gl_libs = anbox::graphics::emugl::default_gl_libraries();
168     if (!anbox::graphics::emugl::initialize(gl_libs, nullptr, nullptr)) {
169       return;
170     }
171
172     auto display = s_egl.eglGetDisplay(0);
173     if (display != EGL_NO_DISPLAY) {
174       s_egl.eglInitialize(display, nullptr, nullptr);
175
176       auto egl_safe_get_string = [display](EGLint item) {
177         auto str = s_egl.eglQueryString(display, item);
178         if (!str)
179           return std::string("n/a");
180         return std::string(reinterpret_cast<const char*>(str));
181       };
182
183       graphics_info_.egl_vendor = egl_safe_get_string(EGL_VENDOR);
184       graphics_info_.egl_version = egl_safe_get_string(EGL_VERSION);
185       const auto egl_extensions = egl_safe_get_string(EGL_EXTENSIONS);
186       graphics_info_.egl_extensions = anbox::utils::string_split(egl_extensions, ' ');
187
188       GLint config_attribs[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
189                                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
190                                 EGL_NONE};
191
192       EGLConfig config;
193       int n;
194       if (s_egl.eglChooseConfig(display, config_attribs, &config, 1, &n) && n > 0) {
195         GLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
196         auto context = s_egl.eglCreateContext(display, config, nullptr, attribs);
197         if (context != EGL_NO_CONTEXT) {
198           // We require surfaceless-context support here for now. If eglMakeCurrent fails
199           // glGetString will return null below which we handle correctly.
200           s_egl.eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context);
201
202           auto gl_safe_get_string = [](GLint item) {
203             auto str = s_gles2.glGetString(item);
204             if (!str)
205               return std::string("n/a");
206             return std::string(reinterpret_cast<const char*>(str));
207           };
208
209           graphics_info_.gles2_vendor = gl_safe_get_string(GL_VENDOR);
210           graphics_info_.gles2_version = gl_safe_get_string(GL_VERSION);
211           const auto gl_extensions = gl_safe_get_string(GL_EXTENSIONS);
212           graphics_info_.gles2_extensions = anbox::utils::string_split(gl_extensions, ' ');
213
214           s_egl.eglMakeCurrent(display, nullptr, nullptr, nullptr);
215           s_egl.eglDestroyContext(display, context);
216         }
217       }
218     }
219   }
220
221   struct {
222     std::string arch;
223     std::string brand;
224     std::vector<std::string> features;
225   } cpu_info_;
226
227   struct {
228     bool snap_based = false;
229     std::string name = "n/a";
230     std::string version = "n/a";
231   } os_info_;
232
233   struct {
234     std::string version = "n/a";
235     bool binder = false;
236     bool ashmem = false;
237   } kernel_info_;
238
239   struct {
240     std::string egl_vendor = "n/a";
241     std::string egl_version = "n/a";
242     std::vector<std::string> egl_extensions;
243     std::string gles2_vendor = "n/a";
244     std::string gles2_version = "n/a";
245     std::vector<std::string> gles2_extensions;
246   } graphics_info_;
247 };
248
249 std::ostream &operator<<(std::ostream &out, const SystemInformation &info) {
250   out << info.to_text();
251   return out;
252 }
253 }
254
255 anbox::cmds::SystemInfo::SystemInfo()
256     : CommandWithFlagsAndAction{
257           cli::Name{"system-info"}, cli::Usage{"system-info"},
258           cli::Description{"Print various information about the system we're running on"}} {
259   action([](const cli::Command::Context&) {
260     SystemInformation si;
261     std::cout << si;
262     return EXIT_SUCCESS;
263   });
264 }