A bunch more changes to get the whole system properly booted
This commit is contained in:
parent
3222551702
commit
720b71f1e8
58 changed files with 1835 additions and 532 deletions
|
|
@ -62,6 +62,7 @@ find_package(EGL REQUIRED)
|
|||
find_package(GLESv2 REQUIRED)
|
||||
|
||||
pkg_check_modules(MIRCLIENT REQUIRED mirclient)
|
||||
pkg_check_modules(LIBEVDEV REQUIRED libevdev)
|
||||
|
||||
#####################################################################
|
||||
# Enable code coverage calculation with gcov/gcovr/lcov
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
add_subdirectory(mir_support)
|
||||
add_subdirectory(GLESv1_dec)
|
||||
add_subdirectory(GLESv2_dec)
|
||||
add_subdirectory(libOpenGLESDispatch)
|
||||
|
|
|
|||
|
|
@ -14,5 +14,11 @@ add_custom_command(
|
|||
set(SOURCES
|
||||
GLESv1Decoder.cpp)
|
||||
|
||||
if ("${cmake_build_type_lower}" STREQUAL "debug")
|
||||
set(OPENGL_DEBUG "-DOPENGL_DEBUG_PRINTOUT -DCHECK_GL_ERROR")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPENGL_DEBUG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}")
|
||||
endif()
|
||||
|
||||
add_library(GLESv1_dec ${SOURCES} ${GENERATED_SOURCES})
|
||||
target_link_libraries(GLESv1_dec OpenglCodecCommon)
|
||||
|
|
|
|||
|
|
@ -14,5 +14,11 @@ add_custom_command(
|
|||
set(SOURCES
|
||||
GLESv2Decoder.cpp)
|
||||
|
||||
if ("${cmake_build_type_lower}" STREQUAL "debug")
|
||||
set(OPENGL_DEBUG "-DOPENGL_DEBUG_PRINTOUT -DCHECK_GL_ERROR")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPENGL_DEBUG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}")
|
||||
endif()
|
||||
|
||||
add_library(GLESv2_dec ${SOURCES} ${GENERATED_SOURCES})
|
||||
target_link_libraries(GLESv2_dec OpenglCodecCommon)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ set(SOURCES
|
|||
ColorBuffer.cpp
|
||||
FbConfig.cpp
|
||||
FrameBuffer.cpp
|
||||
NativeSubWindow_mir.cpp
|
||||
NativeSubWindow_delegate.cpp
|
||||
ReadBuffer.cpp
|
||||
RenderContext.cpp
|
||||
RenderControl.cpp
|
||||
|
|
@ -19,9 +19,6 @@ set(SOURCES
|
|||
UnixStream.cpp
|
||||
WindowSurface.cpp)
|
||||
|
||||
include_directories(BEFORE
|
||||
${MIRCLIENT_INCLUDE_DIRS})
|
||||
|
||||
add_library(OpenglRender ${SOURCES})
|
||||
target_link_libraries(OpenglRender
|
||||
emugl_common
|
||||
|
|
@ -30,8 +27,5 @@ target_link_libraries(OpenglRender
|
|||
renderControl_dec
|
||||
OpenGLESDispatch
|
||||
OpenglCodecCommon
|
||||
mir_support
|
||||
${EGL_LDFLAGS}
|
||||
${EGL_LIBRARIES}
|
||||
${MIRCLIENT_LDFLAGS}
|
||||
${MIRCLIENT_LIBRARIES})
|
||||
${EGL_LIBRARIES})
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mir_support/shared_state.h"
|
||||
|
||||
#define MID_AUBERGINE(x) (x)*0.368627451f, (x)*0.152941176f, (x)*0.31372549f
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper class to call the bind_locked() / unbind_locked() properly.
|
||||
|
|
@ -188,8 +184,7 @@ bool FrameBuffer::initialize(int width, int height, bool useSubWindow)
|
|||
//
|
||||
// Initialize backend EGL display
|
||||
//
|
||||
mir::support::SharedState::get()->ensure_connection();
|
||||
fb->m_eglDisplay = s_egl.eglGetDisplay(mir::support::SharedState::get()->native_display());
|
||||
fb->m_eglDisplay = s_egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (fb->m_eglDisplay == EGL_NO_DISPLAY) {
|
||||
ERR("Failed to Initialize backend EGL display\n");
|
||||
delete fb;
|
||||
|
|
@ -582,7 +577,6 @@ bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window,
|
|||
if (m_lastPostedColorBuffer) {
|
||||
post(m_lastPostedColorBuffer, false);
|
||||
} else {
|
||||
s_gles2.glClearColor(MID_AUBERGINE(1.0), 1.0);
|
||||
s_gles2.glClear(GL_COLOR_BUFFER_BIT |
|
||||
GL_DEPTH_BUFFER_BIT |
|
||||
GL_STENCIL_BUFFER_BIT);
|
||||
|
|
|
|||
|
|
@ -20,10 +20,21 @@
|
|||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
class SubWindowHandler {
|
||||
public:
|
||||
virtual ~SubWindowHandler() { }
|
||||
virtual EGLNativeWindowType create_window(int x, int y, int width, int height) = 0;
|
||||
virtual void destroy_window(EGLNativeWindowType win) = 0;
|
||||
};
|
||||
|
||||
void registerSubWindowHandler(const std::shared_ptr<SubWindowHandler> &handler);
|
||||
|
||||
typedef void (*SubWindowRepaintCallback)(void*);
|
||||
|
||||
// Create a new sub-window that will be used to display the content of the
|
||||
|
|
|
|||
72
external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_delegate.cpp
vendored
Normal file
72
external/android-emugl/host/libs/libOpenglRender/NativeSubWindow_delegate.cpp
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "NativeSubWindow.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace {
|
||||
static std::shared_ptr<SubWindowHandler> current_handler = nullptr;
|
||||
}
|
||||
|
||||
void registerSubWindowHandler(const std::shared_ptr<SubWindowHandler> &handler) {
|
||||
if (current_handler)
|
||||
throw std::runtime_error("A sub window handle is already registered");
|
||||
|
||||
current_handler = handler;
|
||||
}
|
||||
|
||||
EGLNativeWindowType createSubWindow(FBNativeWindowType p_window,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
SubWindowRepaintCallback repaint_callback,
|
||||
void* repaint_callback_param) {
|
||||
(void) p_window;
|
||||
(void) repaint_callback;
|
||||
(void) repaint_callback_param;
|
||||
|
||||
if (!current_handler)
|
||||
return (EGLNativeWindowType) 0;
|
||||
|
||||
return current_handler->create_window(x, y, width, height);
|
||||
}
|
||||
|
||||
void destroySubWindow(EGLNativeWindowType win) {
|
||||
if (!current_handler)
|
||||
return;
|
||||
|
||||
return current_handler->destroy_window(win);
|
||||
}
|
||||
|
||||
int moveSubWindow(FBNativeWindowType p_parent_window,
|
||||
EGLNativeWindowType p_sub_window,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
(void) p_parent_window;
|
||||
(void) p_sub_window;
|
||||
(void) x;
|
||||
(void) y;
|
||||
(void) width;
|
||||
(void) height;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
set(SOURCES
|
||||
shared_state.cpp)
|
||||
|
||||
include_directories(BEFORE
|
||||
${MIRCLIENT_INCLUDE_DIRS})
|
||||
|
||||
add_library(mir_support ${SOURCES})
|
||||
target_link_libraries(mir_support
|
||||
${MIRCLIENT_LDFLAGS}
|
||||
${MIRCLIENT_LIBRARIES})
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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 "mir_support/shared_state.h"
|
||||
|
||||
namespace mir {
|
||||
namespace support {
|
||||
|
||||
std::shared_ptr<SharedState> SharedState::get() {
|
||||
static auto instance = std::make_shared<SharedState>();
|
||||
return instance;
|
||||
}
|
||||
|
||||
SharedState::SharedState() :
|
||||
connection_(nullptr) {
|
||||
}
|
||||
|
||||
SharedState::~SharedState() {
|
||||
release_connection();
|
||||
}
|
||||
|
||||
void SharedState::ensure_connection() {
|
||||
if (connection_)
|
||||
return;
|
||||
|
||||
auto xdg_runtime_dir = ::getenv("XDG_RUNTIME_DIR");
|
||||
if (!xdg_runtime_dir)
|
||||
throw std::runtime_error("Failed to find XDG_RUNTIME_DIR");
|
||||
|
||||
std::string socket_path = xdg_runtime_dir;
|
||||
socket_path += "/mir_socket";
|
||||
|
||||
connection_ = mir_connect_sync(socket_path.c_str(), "anbox");
|
||||
if (!mir_connection_is_valid(connection_)) {
|
||||
std::string msg;
|
||||
msg += "Failed to connect with Mir server: ";
|
||||
msg += mir_connection_get_error_message(connection_);
|
||||
msg += "\n";
|
||||
throw std::runtime_error(msg.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void SharedState::release_connection() {
|
||||
if (!connection_)
|
||||
return;
|
||||
|
||||
mir_connection_release(connection_);
|
||||
connection_ = nullptr;
|
||||
}
|
||||
|
||||
MirConnection* SharedState::connection() const {
|
||||
return connection_;
|
||||
}
|
||||
|
||||
EGLNativeDisplayType SharedState::native_display() const {
|
||||
return mir_connection_get_egl_native_display(connection_);
|
||||
}
|
||||
|
||||
} // namespace support
|
||||
} // namespace mir
|
||||
|
|
@ -10,5 +10,11 @@ add_custom_command(
|
|||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS emugen)
|
||||
|
||||
if ("${cmake_build_type_lower}" STREQUAL "debug")
|
||||
set(OPENGL_DEBUG "-DOPENGL_DEBUG_PRINTOUT -DCHECK_GL_ERROR")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPENGL_DEBUG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}")
|
||||
endif()
|
||||
|
||||
add_library(renderControl_dec ${GENERATED_SOURCES})
|
||||
target_link_libraries(renderControl_dec OpenglCodecCommon)
|
||||
|
|
|
|||
138
external/bubblewrap/bubblewrap.c
vendored
138
external/bubblewrap/bubblewrap.c
vendored
|
|
@ -1319,10 +1319,6 @@ bwrap_main (int argc,
|
|||
/* Get the (optional) capabilities we need, drop root */
|
||||
acquire_caps ();
|
||||
|
||||
/* Never gain any more privs during exec */
|
||||
if (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
|
||||
die_with_error ("prctl(PR_SET_NO_NEW_CAPS) failed");
|
||||
|
||||
/* The initial code is run with high permissions
|
||||
(i.e. CAP_SYS_ADMIN), so take lots of care. */
|
||||
|
||||
|
|
@ -1390,9 +1386,7 @@ bwrap_main (int argc,
|
|||
/* We block sigchild here so that we can use signalfd in the monitor. */
|
||||
block_sigchild ();
|
||||
|
||||
clone_flags = SIGCHLD | CLONE_NEWNS;
|
||||
if (opt_unshare_user)
|
||||
clone_flags |= CLONE_NEWUSER;
|
||||
clone_flags = SIGCHLD;
|
||||
if (opt_unshare_pid)
|
||||
clone_flags |= CLONE_NEWPID;
|
||||
if (opt_unshare_net)
|
||||
|
|
@ -1423,14 +1417,6 @@ bwrap_main (int argc,
|
|||
pid = raw_clone (clone_flags, NULL);
|
||||
if (pid == -1)
|
||||
{
|
||||
if (opt_unshare_user)
|
||||
{
|
||||
if (errno == EINVAL)
|
||||
die ("Creating new namespace failed, likely because the kernel does not support user namespaces. bwrap must be installed setuid on such systems.");
|
||||
else if (errno == EPERM && !is_privileged)
|
||||
die ("No permissions to creating new namespace, likely because the kernel does not allow non-privileged user namespaces. On e.g. debian this can be enabled with 'sysctl kernel.unprivileged_userns_clone=1'.");
|
||||
}
|
||||
|
||||
die_with_error ("Creating new namespace failed");
|
||||
}
|
||||
|
||||
|
|
@ -1439,18 +1425,6 @@ bwrap_main (int argc,
|
|||
|
||||
if (pid != 0)
|
||||
{
|
||||
if (is_privileged && opt_unshare_user)
|
||||
{
|
||||
/* Map the uid/gid 0 if opt_needs_devpts, as otherwise
|
||||
* mounting it will fail.
|
||||
* Due to this non-direct mapping we need to have set[ug]id
|
||||
* caps in the parent namespaces, and thus we need to write
|
||||
* the map in the parent namespace, not the child. */
|
||||
write_uid_gid_map (ns_uid, uid,
|
||||
ns_gid, gid,
|
||||
pid, TRUE, opt_needs_devpts);
|
||||
}
|
||||
|
||||
/* Initial launched process, wait for exec:ed command to exit */
|
||||
|
||||
if (opt_pid_file) {
|
||||
|
|
@ -1464,9 +1438,6 @@ bwrap_main (int argc,
|
|||
close(pid_file_fd);
|
||||
}
|
||||
|
||||
/* We don't need any caps in the launcher, drop them immediately. */
|
||||
drop_caps ();
|
||||
|
||||
/* Let child run */
|
||||
val = 1;
|
||||
res = write (child_wait_fd, &val, 8);
|
||||
|
|
@ -1486,25 +1457,6 @@ bwrap_main (int argc,
|
|||
|
||||
ns_uid = opt_sandbox_uid;
|
||||
ns_gid = opt_sandbox_gid;
|
||||
if (!is_privileged && opt_unshare_user)
|
||||
{
|
||||
/* In the unprivileged case we have to write the uid/gid maps in
|
||||
* the child, because we have no caps in the parent */
|
||||
|
||||
if (opt_needs_devpts)
|
||||
{
|
||||
/* This is a bit hacky, but we need to first map the real uid/gid to
|
||||
0, otherwise we can't mount the devpts filesystem because root is
|
||||
not mapped. Later we will create another child user namespace and
|
||||
map back to the real uid */
|
||||
ns_uid = 0;
|
||||
ns_gid = 0;
|
||||
}
|
||||
|
||||
write_uid_gid_map (ns_uid, uid,
|
||||
ns_gid, gid,
|
||||
-1, TRUE, FALSE);
|
||||
}
|
||||
|
||||
old_umask = umask (0);
|
||||
|
||||
|
|
@ -1542,53 +1494,7 @@ bwrap_main (int argc,
|
|||
if (chdir ("/") != 0)
|
||||
die_with_error ("chdir / (base path)");
|
||||
|
||||
if (is_privileged)
|
||||
{
|
||||
pid_t child;
|
||||
int privsep_sockets[2];
|
||||
|
||||
if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, privsep_sockets) != 0)
|
||||
die_with_error ("Can't create privsep socket");
|
||||
|
||||
child = fork ();
|
||||
if (child == -1)
|
||||
die_with_error ("Can't fork unprivileged helper");
|
||||
|
||||
if (child == 0)
|
||||
{
|
||||
/* Unprivileged setup process */
|
||||
drop_caps ();
|
||||
close (privsep_sockets[0]);
|
||||
setup_newroot (opt_unshare_pid, privsep_sockets[1]);
|
||||
exit (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t buffer[2048]; /* 8k, but is int32 to guarantee nice alignment */
|
||||
uint32_t op, flags;
|
||||
const char *arg1, *arg2;
|
||||
cleanup_fd int unpriv_socket = -1;
|
||||
|
||||
unpriv_socket = privsep_sockets[0];
|
||||
close (privsep_sockets[1]);
|
||||
|
||||
do
|
||||
{
|
||||
op = read_priv_sec_op (unpriv_socket, buffer, sizeof (buffer),
|
||||
&flags, &arg1, &arg2);
|
||||
privileged_op (-1, op, flags, arg1, arg2);
|
||||
if (write (unpriv_socket, buffer, 1) != 1)
|
||||
die ("Can't write to op_socket");
|
||||
}
|
||||
while (op != PRIV_SEP_OP_DONE);
|
||||
|
||||
/* Continue post setup */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setup_newroot (opt_unshare_pid, -1);
|
||||
}
|
||||
setup_newroot (opt_unshare_pid, -1);
|
||||
|
||||
/* The old root better be rprivate or we will send unmount events to the parent namespace */
|
||||
if (mount ("oldroot", "oldroot", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
|
||||
|
|
@ -1597,21 +1503,6 @@ bwrap_main (int argc,
|
|||
if (umount2 ("oldroot", MNT_DETACH))
|
||||
die_with_error ("unmount old root");
|
||||
|
||||
if (opt_unshare_user &&
|
||||
(ns_uid != opt_sandbox_uid || ns_gid != opt_sandbox_gid))
|
||||
{
|
||||
/* Now that devpts is mounted and we've no need for mount
|
||||
permissions we can create a new userspace and map our uid
|
||||
1:1 */
|
||||
|
||||
if (unshare (CLONE_NEWUSER))
|
||||
die_with_error ("unshare user ns");
|
||||
|
||||
write_uid_gid_map (opt_sandbox_uid, ns_uid,
|
||||
opt_sandbox_gid, ns_gid,
|
||||
-1, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/* Now make /newroot the real root */
|
||||
if (chdir ("/newroot") != 0)
|
||||
die_with_error ("chdir newroot");
|
||||
|
|
@ -1620,31 +1511,6 @@ bwrap_main (int argc,
|
|||
if (chdir ("/") != 0)
|
||||
die_with_error ("chdir /");
|
||||
|
||||
/* Now we have everything we need CAP_SYS_ADMIN for, so drop it */
|
||||
drop_caps ();
|
||||
|
||||
if (opt_seccomp_fd != -1)
|
||||
{
|
||||
cleanup_free char *seccomp_data = NULL;
|
||||
size_t seccomp_len;
|
||||
struct sock_fprog prog;
|
||||
|
||||
seccomp_data = load_file_data (opt_seccomp_fd, &seccomp_len);
|
||||
if (seccomp_data == NULL)
|
||||
die_with_error ("Can't read seccomp data");
|
||||
|
||||
if (seccomp_len % 8 != 0)
|
||||
die ("Invalide seccomp data, must be multiple of 8");
|
||||
|
||||
prog.len = seccomp_len / 8;
|
||||
prog.filter = (struct sock_filter *) seccomp_data;
|
||||
|
||||
close (opt_seccomp_fd);
|
||||
|
||||
if (prctl (PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) != 0)
|
||||
die_with_error ("prctl(PR_SET_SECCOMP)");
|
||||
}
|
||||
|
||||
umask (old_umask);
|
||||
|
||||
new_cwd = "/";
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ include_directories(
|
|||
${GLIB_INCLUDE_DIRS}
|
||||
${GIO_INCLUDE_DIRS}
|
||||
${GIO-UNIX_INCLUDE_DIRS}
|
||||
${MIRCLIENT_INCLUDE_DIRS}
|
||||
${LIBEVDEV_INCLUDE_DIRS}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/external/process-cpp-minimal/include
|
||||
${CMAKE_SOURCE_DIR}/external/android-emugl/host/include
|
||||
|
|
@ -16,9 +19,12 @@ set(SOURCES
|
|||
anbox/version.cpp
|
||||
anbox/daemon.cpp
|
||||
anbox/config.cpp
|
||||
anbox/not_reachable.cpp
|
||||
anbox/pid_persister.cpp
|
||||
anbox/namespace_attacher.cpp
|
||||
anbox/container.cpp
|
||||
anbox/container_connector.cpp
|
||||
anbox/input_channel.cpp
|
||||
|
||||
anbox/common/fd.cpp
|
||||
anbox/common/fd_sets.h
|
||||
|
|
@ -37,11 +43,18 @@ set(SOURCES
|
|||
anbox/network/delegate_message_processor.h
|
||||
|
||||
anbox/graphics/opengles_message_processor.cpp
|
||||
anbox/graphics/mir_display_connection.cpp
|
||||
anbox/graphics/mir_window.cpp
|
||||
anbox/graphics/mir_native_window_creator.cpp
|
||||
anbox/graphics/gl_renderer_server.cpp
|
||||
|
||||
anbox/support/null_message_processor.cpp
|
||||
anbox/support/qemud_message_processor.cpp
|
||||
anbox/support/boot_properties_message_processor.cpp
|
||||
anbox/support/hwcontrol_message_processor.cpp
|
||||
anbox/support/sensors_message_processor.cpp
|
||||
anbox/support/camera_message_processor.cpp
|
||||
anbox/support/fingerprint_message_processor.cpp
|
||||
|
||||
anbox/cmds/version.cpp
|
||||
anbox/cmds/run.cpp
|
||||
|
|
@ -55,15 +68,22 @@ add_library(anbox-core ${SOURCES})
|
|||
target_link_libraries(anbox-core
|
||||
${Boost_LDFLAGS}
|
||||
${Boost_LIBRARIES}
|
||||
${MIRCLIENT_LDFLAGS}
|
||||
${MIRCLIENT_LIBRARIES}
|
||||
${LIBEVDEV_LDFLAGS}
|
||||
${LIBEVDEV_LIBRARIES}
|
||||
pthread
|
||||
process-cpp
|
||||
bwrap
|
||||
OpenglRender)
|
||||
|
||||
add_executable(anbox main.cpp)
|
||||
target_link_libraries(anbox
|
||||
anbox-core)
|
||||
|
||||
add_executable(anbox-container container_main.cpp)
|
||||
target_link_libraries(anbox-container
|
||||
bwrap)
|
||||
|
||||
install(
|
||||
TARGETS anbox
|
||||
RUNTIME DESTINATION sbin
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "anbox/network/published_socket_connector.h"
|
||||
#include "anbox/network/qemu_pipe_connection_creator.h"
|
||||
#include "anbox/graphics/gl_renderer_server.h"
|
||||
#include "anbox/input_channel.h"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
|
|
@ -66,7 +67,9 @@ anbox::cmds::Run::Run()
|
|||
|
||||
auto rt = Runtime::create();
|
||||
|
||||
auto renderer = std::make_shared<graphics::GLRendererServer>();
|
||||
auto input_channel = std::make_shared<InputChannel>();
|
||||
|
||||
auto renderer = std::make_shared<graphics::GLRendererServer>(input_channel);
|
||||
renderer->start();
|
||||
|
||||
// Socket which will be used by the qemud service inside the Android
|
||||
|
|
@ -87,7 +90,11 @@ anbox::cmds::Run::Run()
|
|||
spec.rootfs_path = rootfs_;
|
||||
spec.bind_paths.insert({qemud_connector->socket_file(), "/dev/qemud"});
|
||||
spec.bind_paths.insert({qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"});
|
||||
|
||||
spec.temporary_dirs.push_back("/data");
|
||||
spec.temporary_dirs.push_back("/cache");
|
||||
spec.temporary_dirs.push_back("/storage");
|
||||
spec.temporary_dirs.push_back("/dev/input");
|
||||
// We isolate the container from accessing binder nodes of the host
|
||||
// through the IPC namespace which gets support for binder with extra
|
||||
// patches we require.
|
||||
|
|
@ -95,6 +102,11 @@ anbox::cmds::Run::Run()
|
|||
// Required for shared memory allocations. TODO(morphis): Letting the guest
|
||||
// access should be ok but needs more investigation.
|
||||
spec.dev_bind_paths.push_back("/dev/ashmem");
|
||||
// Our uinput based event node should get root:android_input assigned on Ubuntu
|
||||
// which is enough for our phablet user (being root inside the container) to
|
||||
// read event data from it.
|
||||
spec.dev_bind_paths.push_back({input_channel->dev_path()});
|
||||
spec.dev_bind_paths.push_back({"/dev/input/event7"});
|
||||
|
||||
auto container = Container::create(spec);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@
|
|||
namespace fs = boost::filesystem;
|
||||
|
||||
anbox::cmds::Shell::Shell()
|
||||
: CommandWithFlagsAndAction{cli::Name{"shell"}, cli::Usage{"shell"}, cli::Description{"Open a shell within the Anbox container"}}
|
||||
: CommandWithFlagsAndAction{cli::Name{"shell"}, cli::Usage{"shell"}, cli::Description{"Open a shell within the Anbox container"}},
|
||||
pid_(-1)
|
||||
{
|
||||
action([this](const cli::Command::Context &ctx) {
|
||||
ContainerConnector connector;
|
||||
flag(cli::make_flag(cli::Name{"pid"}, cli::Description{"PID of container to attach to"}, pid_));
|
||||
action([this](const cli::Command::Context &) {
|
||||
ContainerConnector connector(pid_);
|
||||
return connector.run("/system/bin/sh");
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public:
|
|||
Shell();
|
||||
|
||||
private:
|
||||
std::string rootfs_;
|
||||
int pid_;
|
||||
};
|
||||
} // namespace cmds
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "core/posix/fork.h"
|
||||
#include "core/posix/exec.h"
|
||||
|
||||
|
|
@ -28,14 +31,15 @@
|
|||
#include "anbox/container.h"
|
||||
#include "anbox/common/fd.h"
|
||||
|
||||
extern "C" int bwrap_main(int argc, char **argv);
|
||||
#include <grp.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace anbox {
|
||||
|
||||
Container::Spec Container::Spec::Default() {
|
||||
Spec spec;
|
||||
spec.init_command = "/init";
|
||||
spec.init_command = "/anbox-init.sh";
|
||||
spec.environment.insert({"PATH", "/system/bin:/system/sbin:/system/xbin"});
|
||||
return spec;
|
||||
}
|
||||
|
|
@ -53,66 +57,76 @@ Container::~Container() {
|
|||
stop();
|
||||
}
|
||||
|
||||
std::vector<Container::IdMapping> Container::read_id_mappings() {
|
||||
std::vector<Container::IdMapping> mappings;
|
||||
|
||||
static const std::string subuid_path = "/etc/subuid";
|
||||
static const std::string subgid_path = "/etc/subgid";
|
||||
|
||||
std::ifstream subuid_file(subuid_path);
|
||||
|
||||
return mappings;
|
||||
}
|
||||
|
||||
void Container::start() {
|
||||
std::vector<std::string> arguments = {
|
||||
"--ro-bind", spec_.rootfs_path, "/",
|
||||
DEBUG("uid %d gid %d", getuid(), getgid());
|
||||
std::vector<std::string> args = {
|
||||
// We need to setup user mapping here as lxc-usernsexec will not
|
||||
// map our current user to root which we need to allow our container
|
||||
// to access files we've created.
|
||||
"-m", utils::string_format("u:0:%d:1", getuid()),
|
||||
"-m", utils::string_format("g:0:%d:1", getgid()),
|
||||
// FIXME(morphis): We need to determine those things dynamically and
|
||||
// error out if not subui range is set for our current user.
|
||||
"-m", "u:1:100000:100000",
|
||||
"-m", "g:1:100000:100000",
|
||||
"--",
|
||||
// FIXME(morphis): use system or in-click path
|
||||
"/home/phablet/anbox-container",
|
||||
"--bind", spec_.rootfs_path, "/",
|
||||
"--dev", "/dev",
|
||||
"--proc", "/proc",
|
||||
"--unshare-user",
|
||||
"--unshare-ipc",
|
||||
"--unshare-pid",
|
||||
"--unshare-net",
|
||||
"--unshare-uts",
|
||||
// We will take UID 0 (root) inside the container
|
||||
"--uid", "0",
|
||||
// We will take GID 0 (root) inside the container
|
||||
"--gid", "0",
|
||||
"--chdir", "/",
|
||||
"--pid-file", utils::string_format("%s/pid", config::data_path()),
|
||||
};
|
||||
|
||||
for (const auto &dir : spec_.temporary_dirs) {
|
||||
arguments.push_back("--tmpfs");
|
||||
arguments.push_back(dir);
|
||||
args.push_back("--tmpfs");
|
||||
args.push_back(dir);
|
||||
}
|
||||
|
||||
for (const auto &path : spec_.dev_bind_paths) {
|
||||
arguments.push_back("--dev-bind");
|
||||
arguments.push_back(path);
|
||||
arguments.push_back(path);
|
||||
args.push_back("--dev-bind");
|
||||
args.push_back(path);
|
||||
args.push_back(path);
|
||||
}
|
||||
|
||||
for (const auto &path : spec_.bind_paths) {
|
||||
arguments.push_back("--bind");
|
||||
arguments.push_back(path.first);
|
||||
arguments.push_back(path.second);
|
||||
args.push_back("--bind");
|
||||
args.push_back(path.first);
|
||||
args.push_back(path.second);
|
||||
}
|
||||
|
||||
for (const auto &env : spec_.environment) {
|
||||
arguments.push_back("--setenv");
|
||||
arguments.push_back(env.first);
|
||||
arguments.push_back(env.second);
|
||||
args.push_back("--setenv");
|
||||
args.push_back(env.first);
|
||||
args.push_back(env.second);
|
||||
}
|
||||
|
||||
arguments.push_back(spec_.init_command);
|
||||
args.push_back(spec_.init_command);
|
||||
|
||||
child_ = core::posix::fork([&]() {
|
||||
char **it, **pargv;
|
||||
it = pargv = new char*[arguments.size() + 2];
|
||||
*it = strdup("bwrap");
|
||||
it++;
|
||||
for (auto arg : arguments) {
|
||||
*it = ::strdup(arg.c_str());
|
||||
it++;
|
||||
}
|
||||
*it = nullptr;
|
||||
|
||||
if (bwrap_main(arguments.size() + 1, pargv))
|
||||
return core::posix::exit::Status::failure;
|
||||
|
||||
return core::posix::exit::Status::success;
|
||||
}, core::posix::StandardStream::empty);
|
||||
std::map<std::string,std::string> env = {
|
||||
// lxc-usernsexec needs this as otherwise it doesn't find the
|
||||
// newuidmap/newgidmap utilities it uses to setup the user
|
||||
// namespace
|
||||
{ "PATH", "/usr/bin" },
|
||||
};
|
||||
|
||||
child_ = core::posix::exec("/usr/bin/lxc-usernsexec", args, env, core::posix::StandardStream::empty);
|
||||
child_group_ = child_.process_group_or_throw();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,20 @@ public:
|
|||
private:
|
||||
Container(const Container::Spec &spec);
|
||||
|
||||
struct IdMapping {
|
||||
enum class Type {
|
||||
UID,
|
||||
GID
|
||||
};
|
||||
|
||||
Type type;
|
||||
int hostid;
|
||||
int nsid;
|
||||
int range;
|
||||
};
|
||||
|
||||
std::vector<IdMapping> read_id_mappings();
|
||||
|
||||
Spec spec_;
|
||||
core::posix::ChildProcess child_;
|
||||
core::posix::ProcessGroup child_group_;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "anbox/container_connector.h"
|
||||
#include "anbox/namespace_attacher.h"
|
||||
#include "anbox/config.h"
|
||||
#include "anbox/utils.h"
|
||||
#include "anbox/logger.h"
|
||||
|
|
@ -32,101 +33,36 @@
|
|||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace {
|
||||
class NamespaceAttacher {
|
||||
public:
|
||||
enum class ns_type {
|
||||
user,
|
||||
pid,
|
||||
uts,
|
||||
mount,
|
||||
ipc,
|
||||
net,
|
||||
};
|
||||
|
||||
static std::string ns_type_to_string(ns_type type) {
|
||||
switch (type) {
|
||||
case ns_type::user:
|
||||
return "user";
|
||||
case ns_type::pid:
|
||||
return "pid";
|
||||
case ns_type::uts:
|
||||
return "uts";
|
||||
case ns_type::mount:
|
||||
return "mnt";
|
||||
case ns_type::ipc:
|
||||
return "ipc";
|
||||
case ns_type::net:
|
||||
return "net";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unknown namespace type"));
|
||||
}
|
||||
|
||||
NamespaceAttacher(const std::vector<ns_type> &types, pid_t pid) :
|
||||
pid_(pid) {
|
||||
|
||||
attach(types);
|
||||
}
|
||||
|
||||
~NamespaceAttacher() {
|
||||
}
|
||||
|
||||
private:
|
||||
void attach(const std::vector<ns_type> &types) {
|
||||
std::vector<int> fds;
|
||||
for (const auto &type : types) {
|
||||
const auto path = anbox::utils::string_format("/proc/%lu/ns/%s", pid_, ns_type_to_string(type));
|
||||
if (!fs::exists(fs::path(path)))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to open namespace file"));
|
||||
|
||||
const auto fd = ::open(path.c_str(), O_RDONLY);
|
||||
if (fd < 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to open namespace file"));
|
||||
|
||||
fds.push_back(fd);
|
||||
}
|
||||
|
||||
for (const auto &fd : fds) {
|
||||
if (::setns(fd, 0) == -1)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Could not attach to namespace"));
|
||||
|
||||
::close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
pid_t pid_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace anbox {
|
||||
ContainerConnector::ContainerConnector() {
|
||||
ContainerConnector::ContainerConnector(int pid) :
|
||||
pid_(pid) {
|
||||
}
|
||||
|
||||
ContainerConnector::~ContainerConnector() {
|
||||
}
|
||||
|
||||
int ContainerConnector::run(const std::string &path) {
|
||||
const auto pid = std::stol(utils::read_file_if_exists_or_throw(
|
||||
int pid = pid_;
|
||||
if (pid == -1)
|
||||
pid = std::stol(utils::read_file_if_exists_or_throw(
|
||||
utils::string_format("%s/pid", config::data_path())));
|
||||
|
||||
if (!fs::is_directory(fs::path(utils::string_format("/proc/%i", pid))))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Container isn't running"));
|
||||
|
||||
namespaces_ = std::make_shared<NamespaceAttacher>(std::vector<NamespaceAttacher::ns_type>{
|
||||
NamespaceAttacher::ns_type::user,
|
||||
NamespaceAttacher::ns_type::mount,
|
||||
NamespaceAttacher::ns_type::pid,
|
||||
NamespaceAttacher::ns_type::uts,
|
||||
NamespaceAttacher::ns_type::ipc,
|
||||
NamespaceAttacher::ns_type::net,
|
||||
namespaces_ = std::make_shared<NamespaceAttacher>(std::vector<NamespaceType>{
|
||||
NamespaceType::user,
|
||||
NamespaceType::mount,
|
||||
NamespaceType::pid,
|
||||
NamespaceType::uts,
|
||||
NamespaceType::ipc,
|
||||
NamespaceType::net,
|
||||
}, pid);
|
||||
|
||||
// A few things we want to preset in our env within the container shell
|
||||
std::map<std::string, std::string> env = {
|
||||
{ "ANDROID_ROOT", "/" }
|
||||
{ "ANDROID_ROOT", "/system" },
|
||||
{ "ANDROID_DATA", "/data" },
|
||||
};
|
||||
|
||||
auto child = core::posix::exec(path, {}, env, core::posix::StandardStream::empty, [this]() {
|
||||
|
|
@ -137,6 +73,9 @@ int ContainerConnector::run(const std::string &path) {
|
|||
if (::chroot("/newroot") != 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to enter container root filesystem"));
|
||||
|
||||
setuid(0);
|
||||
setgid(0);
|
||||
|
||||
chdir("/");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -20,19 +20,17 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
namespace {
|
||||
class NamespaceAttacher;
|
||||
}
|
||||
|
||||
namespace anbox {
|
||||
class NamespaceAttacher;
|
||||
class ContainerConnector {
|
||||
public:
|
||||
ContainerConnector();
|
||||
ContainerConnector(int pid = -1);
|
||||
~ContainerConnector();
|
||||
|
||||
int run(const std::string &path);
|
||||
|
||||
private:
|
||||
int pid_;
|
||||
std::shared_ptr<NamespaceAttacher> namespaces_;
|
||||
};
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ try {
|
|||
}
|
||||
catch(std::exception &err) {
|
||||
ERROR("%s", err.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
void Daemon::ensure_data_path() {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "anbox/logger.h"
|
||||
#include "anbox/graphics/gl_renderer_server.h"
|
||||
#include "anbox/graphics/mir_native_window_creator.h"
|
||||
|
||||
#include "OpenglRender/render_api.h"
|
||||
|
||||
|
|
@ -26,7 +27,9 @@
|
|||
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
GLRendererServer::GLRendererServer() {
|
||||
GLRendererServer::GLRendererServer(const std::shared_ptr<InputChannel> &input_channel) :
|
||||
window_creator_(std::make_shared<MirNativeWindowCreator>(input_channel)) {
|
||||
|
||||
// Force the host EGL/GLES libraries as translator implementation
|
||||
::setenv("ANDROID_EGL_LIB", "libEGL.so.1", 1);
|
||||
::setenv("ANDROID_GLESv1_LIB", "libGLESv1_CM.so.1", 1);
|
||||
|
|
@ -36,6 +39,8 @@ GLRendererServer::GLRendererServer() {
|
|||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
|
||||
|
||||
setStreamMode(RENDER_API_STREAM_MODE_UNIX);
|
||||
|
||||
registerSubWindowHandler(window_creator_);
|
||||
}
|
||||
|
||||
GLRendererServer::~GLRendererServer() {
|
||||
|
|
|
|||
|
|
@ -19,13 +19,16 @@
|
|||
#define ANBOX_GRAPHICS_GL_RENDERER_SERVER_H_
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace anbox {
|
||||
class InputChannel;
|
||||
namespace graphics {
|
||||
class MirNativeWindowCreator;
|
||||
|
||||
class GLRendererServer {
|
||||
public:
|
||||
GLRendererServer();
|
||||
GLRendererServer(const std::shared_ptr<InputChannel> &input_channel);
|
||||
~GLRendererServer();
|
||||
|
||||
void start();
|
||||
|
|
@ -34,6 +37,7 @@ public:
|
|||
|
||||
private:
|
||||
std::string socket_path_;
|
||||
std::shared_ptr<MirNativeWindowCreator> window_creator_;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
|
|
|
|||
122
src/anbox/graphics/mir_display_connection.cpp
Normal file
122
src/anbox/graphics/mir_display_connection.cpp
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/graphics/mir_display_connection.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
static const MirDisplayOutput *find_active_output(
|
||||
const MirDisplayConfiguration *conf)
|
||||
{
|
||||
const MirDisplayOutput *output = NULL;
|
||||
int d;
|
||||
|
||||
for (d = 0; d < (int)conf->num_outputs; d++)
|
||||
{
|
||||
const MirDisplayOutput *out = conf->outputs + d;
|
||||
|
||||
if (out->used &&
|
||||
out->connected &&
|
||||
out->num_modes &&
|
||||
out->current_mode < out->num_modes)
|
||||
{
|
||||
output = out;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
MirDisplayConnection::MirDisplayConnection() :
|
||||
connection_(nullptr),
|
||||
output_id_(-1),
|
||||
vertical_resolution_(0),
|
||||
horizontal_resolution_(0) {
|
||||
|
||||
auto xdg_runtime_dir = ::getenv("XDG_RUNTIME_DIR");
|
||||
if (!xdg_runtime_dir)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to find XDG_RUNTIME_DIR"));
|
||||
|
||||
std::string socket_path = xdg_runtime_dir;
|
||||
socket_path += "/mir_socket";
|
||||
|
||||
connection_ = mir_connect_sync(socket_path.c_str(), "anbox");
|
||||
if (!mir_connection_is_valid(connection_)) {
|
||||
std::string msg;
|
||||
msg += "Failed to connect with Mir server: ";
|
||||
msg += mir_connection_get_error_message(connection_);
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(msg.c_str()));
|
||||
}
|
||||
|
||||
MirDisplayConfiguration* display_config =
|
||||
mir_connection_create_display_config(connection_);
|
||||
|
||||
const MirDisplayOutput *output = find_active_output(display_config);
|
||||
if (!output)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to find active output display"));
|
||||
|
||||
DEBUG("Selecting output id %d", output->output_id);
|
||||
|
||||
output_id_ = output->output_id;
|
||||
|
||||
const MirDisplayMode *mode = &output->modes[output->current_mode];
|
||||
vertical_resolution_ = mode->vertical_resolution;
|
||||
horizontal_resolution_ = mode->horizontal_resolution;
|
||||
|
||||
mir_display_config_destroy(display_config);
|
||||
}
|
||||
|
||||
MirDisplayConnection::~MirDisplayConnection() {
|
||||
mir_connection_release(connection_);
|
||||
}
|
||||
|
||||
MirConnection* MirDisplayConnection::connection() const {
|
||||
return connection_;
|
||||
}
|
||||
|
||||
MirPixelFormat MirDisplayConnection::default_pixel_format() const {
|
||||
MirPixelFormat format;
|
||||
unsigned int nformats;
|
||||
mir_connection_get_available_surface_formats(connection_, &format, 1, &nformats);
|
||||
return format;
|
||||
}
|
||||
|
||||
EGLNativeDisplayType MirDisplayConnection::native_display() const {
|
||||
return mir_connection_get_egl_native_display(connection_);
|
||||
}
|
||||
|
||||
int MirDisplayConnection::output_id() const {
|
||||
return output_id_;
|
||||
}
|
||||
|
||||
int MirDisplayConnection::vertical_resolution() const {
|
||||
return vertical_resolution_;
|
||||
}
|
||||
|
||||
int MirDisplayConnection::horizontal_resolution() const {
|
||||
return horizontal_resolution_;
|
||||
}
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef MIR_SUPPORT_SHARED_STATE_H_
|
||||
#define MIR_SUPPORT_SHARED_STATE_H_
|
||||
#ifndef ANBOX_GRAPHICS_MIR_DISPLAY_CONNECTION_H_
|
||||
#define ANBOX_GRAPHICS_MIR_DISPLAY_CONNECTION_H_
|
||||
|
||||
#define MIR_EGL_PLATFORM
|
||||
|
||||
|
|
@ -24,27 +24,31 @@
|
|||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <memory>
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
|
||||
namespace mir {
|
||||
namespace support {
|
||||
class SharedState {
|
||||
class MirDisplayConnection {
|
||||
public:
|
||||
static std::shared_ptr<SharedState> get();
|
||||
MirDisplayConnection();
|
||||
~MirDisplayConnection();
|
||||
|
||||
SharedState();
|
||||
~SharedState();
|
||||
|
||||
void ensure_connection();
|
||||
void release_connection();
|
||||
MirPixelFormat default_pixel_format() const;
|
||||
|
||||
MirConnection* connection() const;
|
||||
EGLNativeDisplayType native_display() const;
|
||||
|
||||
int output_id() const;
|
||||
int vertical_resolution() const;
|
||||
int horizontal_resolution() const;
|
||||
|
||||
private:
|
||||
MirConnection *connection_;
|
||||
int output_id_;
|
||||
int vertical_resolution_;
|
||||
int horizontal_resolution_;
|
||||
};
|
||||
} // namespace support
|
||||
} // namespace mir
|
||||
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
61
src/anbox/graphics/mir_native_window_creator.cpp
Normal file
61
src/anbox/graphics/mir_native_window_creator.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/graphics/mir_native_window_creator.h"
|
||||
#include "anbox/graphics/mir_display_connection.h"
|
||||
#include "anbox/graphics/mir_window.h"
|
||||
#include "anbox/input_channel.h"
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
MirNativeWindowCreator::MirNativeWindowCreator(const std::shared_ptr<InputChannel> &input_channel) :
|
||||
input_channel_(input_channel),
|
||||
display_connection_(std::make_shared<MirDisplayConnection>()) {
|
||||
|
||||
input_channel_->setup(display_connection_->horizontal_resolution(),
|
||||
display_connection_->vertical_resolution());
|
||||
}
|
||||
|
||||
MirNativeWindowCreator::~MirNativeWindowCreator() {
|
||||
}
|
||||
|
||||
EGLNativeWindowType MirNativeWindowCreator::create_window(int x, int y, int width, int height) {
|
||||
(void) x;
|
||||
(void) y;
|
||||
(void) width;
|
||||
(void) height;
|
||||
|
||||
if (windows_.size() > 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("We currently only allow a single native window"));
|
||||
|
||||
auto window = std::make_shared<MirWindow>(display_connection_, input_channel_);
|
||||
windows_.insert({window->native_window(), window});
|
||||
|
||||
return window->native_window();
|
||||
}
|
||||
|
||||
void MirNativeWindowCreator::destroy_window(EGLNativeWindowType win) {
|
||||
auto iter = windows_.find(win);
|
||||
if (iter == windows_.end())
|
||||
return;
|
||||
|
||||
windows_.erase(iter);
|
||||
}
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
51
src/anbox/graphics/mir_native_window_creator.h
Normal file
51
src/anbox/graphics/mir_native_window_creator.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_GRAPHICS_MIR_NATIVE_WINDOW_CREATOR_H_
|
||||
#define ANBOX_GRAPHICS_MIR_NATIVE_WINDOW_CREATOR_H_
|
||||
|
||||
#include "external/android-emugl/host/libs/libOpenglRender/NativeSubWindow.h"
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
namespace anbox {
|
||||
class InputChannel;
|
||||
|
||||
namespace graphics {
|
||||
|
||||
class MirDisplayConnection;
|
||||
class MirWindow;
|
||||
|
||||
class MirNativeWindowCreator : public SubWindowHandler {
|
||||
public:
|
||||
MirNativeWindowCreator(const std::shared_ptr<InputChannel> &input_channel);
|
||||
virtual ~MirNativeWindowCreator();
|
||||
|
||||
EGLNativeWindowType create_window(int x, int y, int width, int height) override;
|
||||
void destroy_window(EGLNativeWindowType win) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<InputChannel> input_channel_;
|
||||
std::shared_ptr<MirDisplayConnection> display_connection_;
|
||||
std::map<EGLNativeWindowType,std::shared_ptr<MirWindow>> windows_;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
107
src/anbox/graphics/mir_window.cpp
Normal file
107
src/anbox/graphics/mir_window.cpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/graphics/mir_window.h"
|
||||
#include "anbox/graphics/mir_display_connection.h"
|
||||
#include "anbox/logger.h"
|
||||
#include "anbox/input_channel.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace graphics {
|
||||
MirWindow::MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<InputChannel> &input_channel) :
|
||||
input_channel_(input_channel),
|
||||
native_window_(0),
|
||||
surface_(nullptr) {
|
||||
|
||||
const auto pixel_format = display->default_pixel_format();
|
||||
|
||||
DEBUG("Selected pixel format %i", pixel_format);
|
||||
|
||||
auto spec = mir_connection_create_spec_for_normal_surface(
|
||||
display->connection(),
|
||||
display->vertical_resolution(),
|
||||
display->horizontal_resolution(),
|
||||
pixel_format);
|
||||
|
||||
mir_surface_spec_set_name(spec, "anbox");
|
||||
mir_surface_spec_set_event_handler(spec, handle_surface_event, this);
|
||||
mir_surface_spec_set_fullscreen_on_output(spec, display->output_id());
|
||||
mir_surface_spec_set_buffer_usage(spec, mir_buffer_usage_hardware);
|
||||
|
||||
surface_ = mir_surface_create_sync(spec);
|
||||
mir_surface_spec_release(spec);
|
||||
|
||||
if (!mir_surface_is_valid(surface_)) {
|
||||
DEBUG("surface error: %s", mir_surface_get_error_message(surface_));
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create a Mir surface"));
|
||||
}
|
||||
|
||||
MirSurfaceParameters parameters;
|
||||
mir_surface_get_parameters(surface_, ¶meters);
|
||||
DEBUG("width %i height %i output id %i",
|
||||
parameters.width,
|
||||
parameters.height,
|
||||
parameters.output_id);
|
||||
|
||||
auto surface_buffer_stream = mir_surface_get_buffer_stream(surface_);
|
||||
native_window_ = reinterpret_cast<EGLNativeWindowType>(
|
||||
mir_buffer_stream_get_egl_native_window(surface_buffer_stream));
|
||||
}
|
||||
|
||||
MirWindow::~MirWindow() {
|
||||
}
|
||||
|
||||
void MirWindow::handle_touch_event(MirTouchEvent const* touch_event) {
|
||||
const auto action = mir_touch_event_action(touch_event, 0);
|
||||
}
|
||||
|
||||
void MirWindow::handle_input_event(MirInputEvent const* input_event) {
|
||||
const auto type = mir_input_event_get_type(input_event);
|
||||
MirTouchEvent const* touch_event = nullptr;
|
||||
MirKeyboardEvent const* key_event = nullptr;
|
||||
|
||||
switch (type) {
|
||||
case mir_input_event_type_touch:
|
||||
touch_event = mir_input_event_get_touch_event(input_event);
|
||||
handle_touch_event(touch_event);
|
||||
break;
|
||||
case mir_input_event_type_pointer:
|
||||
break;
|
||||
case mir_input_event_type_key:
|
||||
key_event = mir_input_event_get_keyboard_event(input_event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MirWindow::handle_surface_event(MirSurface *surface, MirEvent const* event, void *context) {
|
||||
const auto event_type = mir_event_get_type(event);
|
||||
auto thiz = static_cast<MirWindow*>(context);
|
||||
|
||||
switch (event_type) {
|
||||
case mir_event_type_input:
|
||||
thiz->handle_input_event(mir_event_get_input_event(event));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EGLNativeWindowType MirWindow::native_window() const {
|
||||
return native_window_;
|
||||
}
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
56
src/anbox/graphics/mir_window.h
Normal file
56
src/anbox/graphics/mir_window.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_GRAPHICS_MIR_WINDOW_H_
|
||||
#define ANBOX_GRAPHICS_MIR_WINDOW_H_
|
||||
|
||||
#define MIR_EGL_PLATFORM
|
||||
|
||||
#include <mirclient/mir_toolkit/mir_client_library.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace anbox {
|
||||
class InputChannel;
|
||||
|
||||
namespace graphics {
|
||||
class MirDisplayConnection;
|
||||
|
||||
class MirWindow {
|
||||
public:
|
||||
MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<InputChannel> &input_channel);
|
||||
~MirWindow();
|
||||
|
||||
EGLNativeWindowType native_window() const;
|
||||
|
||||
private:
|
||||
static void handle_surface_event(MirSurface *surface, MirEvent const* event, void *context);
|
||||
|
||||
void handle_input_event(MirInputEvent const* input_event);
|
||||
void handle_touch_event(MirTouchEvent const* touch_event);
|
||||
|
||||
std::shared_ptr<InputChannel> input_channel_;
|
||||
EGLNativeWindowType native_window_;
|
||||
MirSurface *surface_;
|
||||
};
|
||||
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
282
src/anbox/id_map_writer.cpp
Normal file
282
src/anbox/id_map_writer.cpp
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/id_map_writer.h"
|
||||
#include "anbox/not_reachable.h"
|
||||
#include "anbox/utils.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <pwd.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
#define getid(type) ((unsigned) ((type) == GID ? getgid() : getuid()))
|
||||
#define idfile(type) ((type) == GID ? "gid_map" : "uid_map")
|
||||
#define idname(type) ((type) == GID ? "GID" : "UID")
|
||||
#define subpath(type) ((type) == GID ? "/etc/subgid" : "/etc/subuid")
|
||||
|
||||
namespace {
|
||||
char *append(char **destination, const char *format, ...) {
|
||||
char *extra, *result;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
if (vasprintf(&extra, format, args) < 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
va_end(args);
|
||||
|
||||
if (*destination == NULL) {
|
||||
*destination = extra;
|
||||
return extra;
|
||||
}
|
||||
|
||||
if (asprintf(&result, "%s%s", *destination, extra) < 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
free(*destination);
|
||||
free(extra);
|
||||
*destination = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
char *string(const char *format, ...) {
|
||||
char *result;
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
if (vasprintf(&result, format, args) < 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *getmap(pid_t pid, int type) {
|
||||
char *line = NULL, *result = NULL, *path;
|
||||
size_t size;
|
||||
unsigned count, first, lower;
|
||||
FILE *file;
|
||||
|
||||
if (pid == -1)
|
||||
path = string("/proc/self/%s", idfile(type));
|
||||
else
|
||||
path = string("/proc/%d/%s", pid, idfile(type));
|
||||
if (!(file = fopen(path, "r")))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
|
||||
while (getline(&line, &size, file) >= 0) {
|
||||
if (sscanf(line, " %u %u %u", &first, &lower, &count) != 3)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
append(&result, "%s%u:%u:%u", result ? "," : "", first, lower, count);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
|
||||
fclose(file);
|
||||
free(line);
|
||||
free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *mapitem(char *map, unsigned *first, unsigned *lower,
|
||||
unsigned *count) {
|
||||
ssize_t skip;
|
||||
|
||||
while (map && *map && strchr(",;", *map))
|
||||
map++;
|
||||
if (map == NULL || *map == '\0')
|
||||
return NULL;
|
||||
if (sscanf(map, "%u:%u:%u%zn", first, lower, count, &skip) < 3)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
return map + skip;
|
||||
}
|
||||
|
||||
static char *rangeitem(char *range, unsigned *start, unsigned *length) {
|
||||
ssize_t skip;
|
||||
|
||||
while (range && *range && strchr(",;", *range))
|
||||
range++;
|
||||
if (range == NULL || *range == '\0')
|
||||
return NULL;
|
||||
if (sscanf(range, "%u:%u%zn", start, length, &skip) < 2)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
return range + skip;
|
||||
}
|
||||
|
||||
static char *readranges(int type) {
|
||||
char *line = NULL, *range, *user;
|
||||
size_t end, size;
|
||||
struct passwd *passwd;
|
||||
unsigned length, start;
|
||||
FILE *file;
|
||||
|
||||
range = string("%u:1", getid(type));
|
||||
if (!(file = fopen(subpath(type), "r")))
|
||||
return range;
|
||||
|
||||
user = getenv("USER");
|
||||
user = user ? user : getenv("LOGNAME");
|
||||
user = user ? user : getlogin();
|
||||
if (!user || !(passwd = getpwnam(user)) || passwd->pw_uid != getuid()) {
|
||||
if (!(passwd = getpwuid(getuid())))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(""));
|
||||
user = passwd->pw_name;
|
||||
}
|
||||
endpwent();
|
||||
|
||||
while (getline(&line, &size, file) >= 0) {
|
||||
if (strncmp(line, user, strlen(user)))
|
||||
continue;
|
||||
if (sscanf(line + strlen(user), ":%u:%u%zn", &start, &length, &end) < 2)
|
||||
continue;
|
||||
if (strchr(":\n", line[end + strlen(user) + 1]))
|
||||
append(&range, ",%u:%u", start, length);
|
||||
}
|
||||
|
||||
free(line);
|
||||
fclose(file);
|
||||
return range;
|
||||
}
|
||||
|
||||
static char *rootdefault(int type) {
|
||||
char *cursor, *map, *result;
|
||||
unsigned count, first, last = INVALID, lower;
|
||||
|
||||
cursor = map = getmap(-1, type);
|
||||
while ((cursor = mapitem(cursor, &first, &lower, &count)))
|
||||
if (last == INVALID || last < first + count - 1)
|
||||
last = first + count - 1;
|
||||
result = string("0:%u:1", last);
|
||||
|
||||
cursor = map;
|
||||
while ((cursor = mapitem(cursor, &first, &lower, &count))) {
|
||||
if (first == 0) {
|
||||
if (count == 1 && first >= last)
|
||||
error(1, 0, "No unprivileged %s available\n", idname(type));
|
||||
first++, lower++, count--;
|
||||
}
|
||||
|
||||
if (last <= first + count - 1 && count > 0)
|
||||
count--;
|
||||
|
||||
if (count > 0)
|
||||
append(&result, "%s%u:%u:%u", result ? "," : "", first, first, count);
|
||||
}
|
||||
|
||||
free(map);
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *userdefault(int type) {
|
||||
char *cursor, *map, *range, *result = NULL;
|
||||
unsigned count, first, index = 0, length, lower, start;
|
||||
|
||||
if (geteuid() != 0)
|
||||
return string("0:%u:1", getid(type));
|
||||
|
||||
map = getmap(-1, type);
|
||||
range = readranges(type);
|
||||
|
||||
while ((range = rangeitem(range, &start, &length))) {
|
||||
cursor = map;
|
||||
while ((cursor = mapitem(cursor, &first, &lower, &count))) {
|
||||
if (start + length <= first || first + count <= start)
|
||||
continue;
|
||||
if (first + count < start + length)
|
||||
length = start - first + count;
|
||||
if (start < first) {
|
||||
index += first - start;
|
||||
length -= first - start;
|
||||
start = first;
|
||||
}
|
||||
append(&result, "%s%u:%u:%u", result ? "," : "", index, start, length);
|
||||
index += length;
|
||||
}
|
||||
}
|
||||
|
||||
free(map);
|
||||
free(range);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void validate(char *range, unsigned first, unsigned count) {
|
||||
unsigned length, start;
|
||||
|
||||
while ((range = rangeitem(range, &start, &length)))
|
||||
if (first < start + length && start < first + count) {
|
||||
if (first < start)
|
||||
validate(range, first, start - first);
|
||||
if (first + count > start + length)
|
||||
validate(range, start + length, first + count - start - length);
|
||||
return;
|
||||
}
|
||||
error(1, 0, "Cannot map onto IDs that are not delegated to you");
|
||||
}
|
||||
|
||||
static void verifymap(char *map, char *range) {
|
||||
unsigned count, first, lower;
|
||||
|
||||
while ((map = mapitem(map, &first, &lower, &count)))
|
||||
validate(range, lower, count);
|
||||
}
|
||||
|
||||
static void writemap(pid_t pid, int type, char *map) {
|
||||
char *path, *range, *text = NULL;
|
||||
int fd;
|
||||
unsigned count, first, lower;
|
||||
|
||||
if (!map) {
|
||||
map = (getuid() == 0 ? rootdefault : userdefault)(type);
|
||||
} else if (getuid() != 0) {
|
||||
range = readranges(type);
|
||||
verifymap(map, range);
|
||||
free(range);
|
||||
}
|
||||
|
||||
while ((map = mapitem(map, &first, &lower, &count)))
|
||||
append(&text, "%u %u %u\n", first, lower, count);
|
||||
|
||||
path = string("/proc/%d/%s", pid, idfile(type));
|
||||
if ((fd = open(path, O_WRONLY)) < 0)
|
||||
error(1, 0, "Failed to set container %s map", idname(type));
|
||||
else if (write(fd, text, strlen(text)) != (ssize_t) strlen(text))
|
||||
error(1, 0, "Failed to set container %s map", idname(type));
|
||||
|
||||
close(fd);
|
||||
free(path);
|
||||
free(text);
|
||||
}
|
||||
}
|
||||
|
||||
namespace anbox {
|
||||
IdMapWriter::IdMapWriter(const Type &type, const pid_t &pid) :
|
||||
type_(type),
|
||||
pid_(pid) {
|
||||
}
|
||||
|
||||
IdMapWriter::~IdMapWriter() {
|
||||
}
|
||||
|
||||
void IdMapWriter::apply() {
|
||||
const auto map = retrieve_mappings();
|
||||
}
|
||||
|
||||
} // namespace anbox
|
||||
43
src/anbox/id_map_writer.h
Normal file
43
src/anbox/id_map_writer.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_ID_MAP_WRITER_H_
|
||||
#define ANBOX_ID_MAP_WRITER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace anbox {
|
||||
class IdMapWriter {
|
||||
public:
|
||||
enum class Type {
|
||||
UID,
|
||||
GID
|
||||
};
|
||||
|
||||
IdMapWriter(const Type &type, const pid_t &pid = -1);
|
||||
~IdMapWriter();
|
||||
|
||||
void apply();
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
pid_t pid_;
|
||||
};
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
75
src/anbox/input_channel.cpp
Normal file
75
src/anbox/input_channel.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/input_channel.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <libevdev/libevdev.h>
|
||||
#include <libevdev/libevdev-uinput.h>
|
||||
|
||||
namespace anbox {
|
||||
InputChannel::InputChannel() :
|
||||
dev_(nullptr) {
|
||||
}
|
||||
|
||||
InputChannel::~InputChannel() {
|
||||
if (dev_)
|
||||
libevdev_uinput_destroy(dev_);
|
||||
}
|
||||
|
||||
void InputChannel::setup(int width, int height) {
|
||||
DEBUG("");
|
||||
auto dev = libevdev_new();
|
||||
libevdev_set_name(dev, "anbox-tp");
|
||||
|
||||
libevdev_enable_event_type(dev, EV_ABS);
|
||||
struct input_absinfo mt_tracking_id = { 0, 0, 255, 0, 0, 0 };
|
||||
libevdev_enable_event_code(dev, EV_ABS, ABS_MT_TRACKING_ID, &mt_tracking_id);
|
||||
struct input_absinfo mt_slot = { 0, 0, 255, 0, 0, 0 };
|
||||
libevdev_enable_event_code(dev, EV_ABS, ABS_MT_SLOT, &mt_slot);
|
||||
struct input_absinfo mt_pos_x = { 0, 0, width, 0, 0, 0 };
|
||||
libevdev_enable_event_code(dev, EV_ABS, ABS_MT_POSITION_X, &mt_pos_x);
|
||||
struct input_absinfo mt_pos_y = { 0, 0, height, 0, 0, 0 };
|
||||
libevdev_enable_event_code(dev, EV_ABS, ABS_MT_POSITION_Y, &mt_pos_y);
|
||||
struct input_absinfo mt_pressure = { 0, 0, 5, 0, 0, 0 };
|
||||
libevdev_enable_event_code(dev, EV_ABS, ABS_MT_PRESSURE, &mt_pressure);
|
||||
|
||||
libevdev_enable_event_type(dev, EV_SYN);
|
||||
|
||||
libevdev_enable_property(dev, INPUT_PROP_DIRECT);
|
||||
|
||||
if (libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &dev_) < 0) {
|
||||
libevdev_free(dev);
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create uinput based device"));
|
||||
}
|
||||
}
|
||||
|
||||
void InputChannel::push_event(const Event &event) {
|
||||
libevdev_uinput_write_event(dev_, event.type, event.code, event.value);
|
||||
}
|
||||
|
||||
std::string InputChannel::dev_path() const {
|
||||
if (!dev_)
|
||||
return "";
|
||||
|
||||
return std::string(libevdev_uinput_get_devnode(dev_));
|
||||
}
|
||||
} // namespace anbox
|
||||
47
src/anbox/input_channel.h
Normal file
47
src/anbox/input_channel.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_INPUT_CHANNEL_H_
|
||||
#define ANBOX_INPUT_CHANNEL_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
struct libevdev_uinput;
|
||||
|
||||
namespace anbox {
|
||||
class InputChannel {
|
||||
public:
|
||||
InputChannel();
|
||||
~InputChannel();
|
||||
|
||||
struct Event {
|
||||
int type;
|
||||
int code;
|
||||
int value;
|
||||
};
|
||||
|
||||
void setup(int width, int height);
|
||||
void push_event(const Event &event);
|
||||
|
||||
std::string dev_path() const;
|
||||
|
||||
private:
|
||||
struct libevdev_uinput *dev_;
|
||||
};
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
81
src/anbox/namespace_attacher.cpp
Normal file
81
src/anbox/namespace_attacher.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/namespace_attacher.h"
|
||||
#include "anbox/utils.h"
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace anbox {
|
||||
std::string NamespaceAttacher::ns_type_to_string(NamespaceType type) {
|
||||
switch (type) {
|
||||
case NamespaceType::user:
|
||||
return "user";
|
||||
case NamespaceType::pid:
|
||||
return "pid";
|
||||
case NamespaceType::uts:
|
||||
return "uts";
|
||||
case NamespaceType::mount:
|
||||
return "mnt";
|
||||
case NamespaceType::ipc:
|
||||
return "ipc";
|
||||
case NamespaceType::net:
|
||||
return "net";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Unknown namespace type"));
|
||||
}
|
||||
|
||||
NamespaceAttacher::NamespaceAttacher(const std::vector<NamespaceType> &types, pid_t pid) :
|
||||
pid_(pid) {
|
||||
|
||||
attach(types);
|
||||
}
|
||||
|
||||
NamespaceAttacher::~NamespaceAttacher() {
|
||||
}
|
||||
|
||||
void NamespaceAttacher::attach(const std::vector<NamespaceType> &types) {
|
||||
std::vector<int> fds;
|
||||
for (const auto &type : types) {
|
||||
const auto path = anbox::utils::string_format("/proc/%lu/ns/%s", pid_, ns_type_to_string(type));
|
||||
if (!fs::exists(fs::path(path)))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to open namespace file"));
|
||||
|
||||
const auto fd = ::open(path.c_str(), O_RDONLY);
|
||||
if (fd < 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to open namespace file"));
|
||||
|
||||
fds.push_back(fd);
|
||||
}
|
||||
|
||||
for (const auto &fd : fds) {
|
||||
if (::setns(fd, 0) == -1)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Could not attach to namespace"));
|
||||
|
||||
::close(fd);
|
||||
}
|
||||
}
|
||||
} // namespace anbox
|
||||
49
src/anbox/namespace_attacher.h
Normal file
49
src/anbox/namespace_attacher.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_NAMESPACE_ATTACHER_H_
|
||||
#define ANBOX_NAMESPACE_ATTACHER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace anbox {
|
||||
enum class NamespaceType {
|
||||
user,
|
||||
pid,
|
||||
uts,
|
||||
mount,
|
||||
ipc,
|
||||
net,
|
||||
};
|
||||
|
||||
class NamespaceAttacher {
|
||||
public:
|
||||
static std::string ns_type_to_string(NamespaceType type);
|
||||
|
||||
NamespaceAttacher(const std::vector<NamespaceType> &types, pid_t pid);
|
||||
~NamespaceAttacher();
|
||||
|
||||
private:
|
||||
void attach(const std::vector<NamespaceType> &types);
|
||||
|
||||
pid_t pid_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
|
@ -23,6 +23,10 @@
|
|||
#include "anbox/graphics/opengles_message_processor.h"
|
||||
#include "anbox/support/boot_properties_message_processor.h"
|
||||
#include "anbox/support/null_message_processor.h"
|
||||
#include "anbox/support/hwcontrol_message_processor.h"
|
||||
#include "anbox/support/sensors_message_processor.h"
|
||||
#include "anbox/support/camera_message_processor.h"
|
||||
#include "anbox/support/fingerprint_message_processor.h"
|
||||
|
||||
namespace ba = boost::asio;
|
||||
|
||||
|
|
@ -81,6 +85,14 @@ QemuPipeConnectionCreator::client_type QemuPipeConnectionCreator::identify_clien
|
|||
// take this as a own service instance as that is what it is.
|
||||
else if (utils::string_starts_with(identifier_and_args, "pipe:qemud:boot-properties"))
|
||||
return client_type::qemud_boot_properties;
|
||||
else if (utils::string_starts_with(identifier_and_args, "pipe:qemud:hw-control"))
|
||||
return client_type::qemud_hw_control;
|
||||
else if (utils::string_starts_with(identifier_and_args, "pipe:qemud:sensors"))
|
||||
return client_type::qemud_sensors;
|
||||
else if (utils::string_starts_with(identifier_and_args, "pipe:qemud:camera"))
|
||||
return client_type::qemud_camera;
|
||||
else if (utils::string_starts_with(identifier_and_args, "pipe:qemud:fingerprintlisten"))
|
||||
return client_type::qemud_fingerprint;
|
||||
|
||||
return client_type::invalid;
|
||||
}
|
||||
|
|
@ -90,6 +102,14 @@ std::shared_ptr<MessageProcessor> QemuPipeConnectionCreator::create_processor(co
|
|||
return std::make_shared<graphics::OpenGlesMessageProcessor>(renderer_socket_path_, runtime_, messenger);
|
||||
else if (type == client_type::qemud_boot_properties)
|
||||
return std::make_shared<support::BootPropertiesMessageProcessor>(messenger);
|
||||
else if (type == client_type::qemud_hw_control)
|
||||
return std::make_shared<support::HwControlMessageProcessor>(messenger);
|
||||
else if (type == client_type::qemud_sensors)
|
||||
return std::make_shared<support::SensorsMessageProcessor>(messenger);
|
||||
else if (type == client_type::qemud_camera)
|
||||
return std::make_shared<support::CameraMessageProcessor>(messenger);
|
||||
else if (type == client_type::qemud_fingerprint)
|
||||
return std::make_shared<support::FingerprintMessageProcessor>(messenger);
|
||||
|
||||
return std::make_shared<support::NullMessageProcessor>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@ public:
|
|||
invalid,
|
||||
opengles,
|
||||
qemud_boot_properties,
|
||||
qemud_hw_control,
|
||||
qemud_sensors,
|
||||
qemud_camera,
|
||||
qemud_fingerprint,
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -51,14 +51,22 @@ void SocketMessenger::send(char const* data, size_t length)
|
|||
VariableLengthArray<serialization_buffer_size> whole_message{length};
|
||||
std::copy(data, data + length, whole_message.data());
|
||||
|
||||
try {
|
||||
std::unique_lock<std::mutex> lg(message_lock);
|
||||
ba::write(*socket,
|
||||
ba::buffer(whole_message.data(), whole_message.size()),
|
||||
boost::asio::transfer_all());
|
||||
}
|
||||
catch (std::exception &err) {
|
||||
ERROR("Failed to write message: %s", err.what());
|
||||
while (true) {
|
||||
try {
|
||||
std::unique_lock<std::mutex> lg(message_lock);
|
||||
ba::write(*socket,
|
||||
ba::buffer(whole_message.data(), whole_message.size()),
|
||||
boost::asio::transfer_all());
|
||||
}
|
||||
catch (const boost::system::system_error &err) {
|
||||
if (err.code() == boost::asio::error::try_again)
|
||||
continue;
|
||||
}
|
||||
catch (const std::exception &err) {
|
||||
ERROR("Could not write message: %s", err.what());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
32
src/anbox/not_reachable.cpp
Normal file
32
src/anbox/not_reachable.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Canonical, Ltd.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Authored by: Thomas Voß <thomas.voss@canonical.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "anbox/not_reachable.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
anbox::util::NotReachable::NotReachable(const std::string& function, const std::string& file, std::uint32_t line)
|
||||
: std::logic_error{(boost::format{"Code should not be reachable: %1% in %2%:%3%"} % function % file % line).str()}
|
||||
{
|
||||
}
|
||||
|
||||
void anbox::util::not_reachable(const std::string& function, const std::string& file, std::uint32_t line)
|
||||
{
|
||||
throw NotReachable{function, file, line};
|
||||
}
|
||||
40
src/anbox/not_reachable.h
Normal file
40
src/anbox/not_reachable.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Canonical, Ltd.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Authored by: Thomas Voß <thomas.voss@canonical.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_UTIL_NOT_REACHABLE_H_
|
||||
#define ANBOX_UTIL_NOT_REACHABLE_H_
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace anbox {
|
||||
namespace util {
|
||||
/// @brief NotReachable is thrown from not_reachable.
|
||||
struct NotReachable : public std::logic_error
|
||||
{
|
||||
/// @brief NotImplemented initializes a new instance for the given function name.
|
||||
NotReachable(const std::string& function, const std::string& file, std::uint32_t line);
|
||||
};
|
||||
|
||||
/// @brief not_reachable throws NotReachable.
|
||||
[[noreturn]] void not_reachable(const std::string& function, const std::string& file, std::uint32_t line);
|
||||
} // namespace util
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -38,7 +38,7 @@ void exception_safe_run(boost::asio::io_service& service) {
|
|||
break;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "test" << e.what();
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "Unknown exception caught while executing boost::asio::io_service";
|
||||
|
|
|
|||
|
|
@ -15,67 +15,24 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "anbox/logger.h"
|
||||
#include "anbox/support/boot_properties_message_processor.h"
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
#include "anbox/network/connections.h"
|
||||
#include "anbox/network/delegate_message_processor.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace ba = boost::asio;
|
||||
|
||||
namespace {
|
||||
static constexpr const long header_size{4};
|
||||
}
|
||||
#include "anbox/logger.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
BootPropertiesMessageProcessor::BootPropertiesMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger) :
|
||||
messenger_(messenger) {
|
||||
QemudMessageProcessor(messenger) {
|
||||
}
|
||||
|
||||
BootPropertiesMessageProcessor::~BootPropertiesMessageProcessor() {
|
||||
}
|
||||
|
||||
bool BootPropertiesMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
|
||||
for (const auto &byte : data)
|
||||
buffer_.push_back(byte);
|
||||
|
||||
process_commands();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BootPropertiesMessageProcessor::process_commands() {
|
||||
while (true) {
|
||||
if (buffer_.size() < header_size)
|
||||
break;
|
||||
|
||||
char header[header_size] = { 0 };
|
||||
::memcpy(header, buffer_.data(), header_size);
|
||||
|
||||
unsigned int body_size = 0;
|
||||
::sscanf(header, "%04x", &body_size);
|
||||
if (body_size != buffer_.size() - header_size)
|
||||
break;
|
||||
|
||||
std::string command;
|
||||
// Make sure we only copy as much bytes as we have to and not more
|
||||
command.insert(0, reinterpret_cast<const char*>(buffer_.data()) + header_size, body_size);
|
||||
|
||||
if (command == "list")
|
||||
list_properties();
|
||||
else
|
||||
DEBUG("Unknown command '%s'", command);
|
||||
|
||||
const auto consumed = header_size + body_size;
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin() + consumed);
|
||||
|
||||
const auto remaining = buffer_.size() - consumed;
|
||||
if (remaining <= 0)
|
||||
break;
|
||||
}
|
||||
void BootPropertiesMessageProcessor::handle_command(const std::string &command) {
|
||||
if (command == "list")
|
||||
list_properties();
|
||||
else
|
||||
DEBUG("Unknown command '%s'", command);
|
||||
}
|
||||
|
||||
void BootPropertiesMessageProcessor::list_properties() {
|
||||
|
|
@ -96,18 +53,20 @@ void BootPropertiesMessageProcessor::list_properties() {
|
|||
|
||||
// TODO(morphis): Using HDPI here for now but should be adjusted to the device
|
||||
// we're running on.
|
||||
"qemu.sf.lcd_density=240"
|
||||
"qemu.sf.lcd_density=240",
|
||||
|
||||
// libhwui detects that we support certain GLESv3 extensions which
|
||||
// we don't yet support in our host channel so we have to disable
|
||||
// those things here.
|
||||
"ro.hwui.use_gpu_pixel_buffers=0",
|
||||
};
|
||||
|
||||
for (const auto &prop : properties) {
|
||||
char header[header_size + 1];
|
||||
std::snprintf(header, header_size + 1, "%04x", prop.length());
|
||||
messenger_->send(header, header_size);
|
||||
send_header(prop.length());
|
||||
messenger_->send(prop.c_str(), prop.length());
|
||||
}
|
||||
|
||||
// Send terminating NULL byte
|
||||
messenger_->send(static_cast<const char*>(""), 1);
|
||||
finish_message();
|
||||
}
|
||||
} // namespace support
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -18,30 +18,20 @@
|
|||
#ifndef ANBOX_SUPPORT_BOOT_PROPERTIES_MESSAGE_PROCESSOR_H_
|
||||
#define ANBOX_SUPPORT_BOOT_PROPERTIES_MESSAGE_PROCESSOR_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/network/message_processor.h"
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
#include "anbox/network/socket_connection.h"
|
||||
#include "anbox/support/qemud_message_processor.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
class BootPropertiesMessageProcessor : public network::MessageProcessor {
|
||||
class BootPropertiesMessageProcessor : public QemudMessageProcessor {
|
||||
public:
|
||||
BootPropertiesMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger);
|
||||
~BootPropertiesMessageProcessor();
|
||||
|
||||
bool process_data(const std::vector<std::uint8_t> &data) override;
|
||||
protected:
|
||||
void handle_command(const std::string &command) override;
|
||||
|
||||
private:
|
||||
void process_commands();
|
||||
void list_properties();
|
||||
|
||||
std::shared_ptr<network::SocketMessenger> messenger_;
|
||||
std::vector<std::uint8_t> buffer_;
|
||||
};
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
|
|
|||
68
src/anbox/support/camera_message_processor.cpp
Normal file
68
src/anbox/support/camera_message_processor.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/logger.h"
|
||||
#include "anbox/support/camera_message_processor.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
CameraMessageProcessor::CameraMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger) :
|
||||
messenger_(messenger) {
|
||||
}
|
||||
|
||||
CameraMessageProcessor::~CameraMessageProcessor() {
|
||||
}
|
||||
|
||||
bool CameraMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
|
||||
DEBUG("Received: %s", utils::hex_dump(data.data(), data.size()));
|
||||
|
||||
for (const auto &byte : data)
|
||||
buffer_.push_back(byte);
|
||||
|
||||
process_commands();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CameraMessageProcessor::process_commands() {
|
||||
while (true) {
|
||||
size_t size;
|
||||
for (size = 0; size < buffer_.size(); size++) {
|
||||
if (buffer_.at(size) == 0x0)
|
||||
break;
|
||||
}
|
||||
|
||||
std::string command;
|
||||
command.insert(0, reinterpret_cast<const char*>(buffer_.data()), size);
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin() + size);
|
||||
|
||||
handle_command(command);
|
||||
}
|
||||
}
|
||||
|
||||
void CameraMessageProcessor::handle_command(const std::string &command) {
|
||||
if (command == "list")
|
||||
list();
|
||||
}
|
||||
|
||||
void CameraMessageProcessor::list() {
|
||||
char buf[5];
|
||||
snprintf(buf, 5, "\n");
|
||||
messenger_->send(buf, strlen(buf));
|
||||
}
|
||||
} // namespace support
|
||||
} // namespace anbox
|
||||
45
src/anbox/support/camera_message_processor.h
Normal file
45
src/anbox/support/camera_message_processor.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_SUPPORT_CAMERA_MESSAGE_PROCESSOR_H_
|
||||
#define ANBOX_SUPPORT_CAMERA_MESSAGE_PROCESSOR_H_
|
||||
|
||||
#include "anbox/network/message_processor.h"
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
class CameraMessageProcessor : public network::MessageProcessor {
|
||||
public:
|
||||
CameraMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger);
|
||||
~CameraMessageProcessor();
|
||||
|
||||
bool process_data(const std::vector<std::uint8_t> &data) override;
|
||||
|
||||
private:
|
||||
void process_commands();
|
||||
|
||||
void handle_command(const std::string &command);
|
||||
void list();
|
||||
|
||||
std::shared_ptr<network::SocketMessenger> messenger_;
|
||||
std::vector<std::uint8_t> buffer_;
|
||||
};
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
43
src/anbox/support/fingerprint_message_processor.cpp
Normal file
43
src/anbox/support/fingerprint_message_processor.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/logger.h"
|
||||
#include "anbox/support/fingerprint_message_processor.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
FingerprintMessageProcessor::FingerprintMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger) :
|
||||
QemudMessageProcessor(messenger) {
|
||||
}
|
||||
|
||||
FingerprintMessageProcessor::~FingerprintMessageProcessor() {
|
||||
}
|
||||
|
||||
void FingerprintMessageProcessor::handle_command(const std::string &command) {
|
||||
if (command == "listen")
|
||||
listen();
|
||||
}
|
||||
|
||||
void FingerprintMessageProcessor::listen() {
|
||||
char buf[12];
|
||||
snprintf(buf, sizeof(buf), "off");
|
||||
send_header(strlen(buf));
|
||||
messenger_->send(buf, strlen(buf));
|
||||
finish_message();
|
||||
}
|
||||
} // namespace support
|
||||
} // namespace anbox
|
||||
39
src/anbox/support/fingerprint_message_processor.h
Normal file
39
src/anbox/support/fingerprint_message_processor.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_SUPPORT_FINGERPRINT_MESSAGE_PROCESSOR_H_
|
||||
#define ANBOX_SUPPORT_FINGERPRINT_MESSAGE_PROCESSOR_H_
|
||||
|
||||
#include "anbox/support/qemud_message_processor.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
class FingerprintMessageProcessor : public QemudMessageProcessor {
|
||||
public:
|
||||
FingerprintMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger);
|
||||
~FingerprintMessageProcessor();
|
||||
|
||||
protected:
|
||||
void handle_command(const std::string &command) override;
|
||||
|
||||
private:
|
||||
void listen();
|
||||
};
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -15,68 +15,27 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "anbox/logger.h"
|
||||
#include "anbox/support/hwcontrol_message_processor.h"
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
#include "anbox/network/connections.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace ba = boost::asio;
|
||||
|
||||
namespace {
|
||||
static constexpr const long header_size{4};
|
||||
}
|
||||
#include "anbox/logger.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
HwControlMessageProcessor::HwControlMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger) :
|
||||
messenger_(messenger) {
|
||||
QemudMessageProcessor(messenger) {
|
||||
}
|
||||
|
||||
HwControlMessageProcessor::~HwControlMessageProcessor() {
|
||||
}
|
||||
|
||||
bool HwControlMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
|
||||
for (const auto &byte : data)
|
||||
buffer_.push_back(byte);
|
||||
|
||||
process_commands();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HwControlMessageProcessor::process_commands() {
|
||||
while (true) {
|
||||
if (buffer_.size() < header_size)
|
||||
break;
|
||||
|
||||
char header[header_size] = { 0 };
|
||||
::memcpy(header, buffer_.data(), header_size);
|
||||
|
||||
unsigned int body_size = 0;
|
||||
::sscanf(header, "%04x", &body_size);
|
||||
if (body_size != buffer_.size() - header_size)
|
||||
break;
|
||||
|
||||
std::string command;
|
||||
// Make sure we only copy as much bytes as we have to and not more
|
||||
command.insert(0, reinterpret_cast<const char*>(buffer_.data()) + header_size, body_size);
|
||||
|
||||
if (command == "power:screen_state:wake")
|
||||
DEBUG("Got screen wake command");
|
||||
else if (command == "power:screen_state:standby")
|
||||
DEBUG("Got screen standby command");
|
||||
else
|
||||
DEBUG("Unknown command '%s'", command);
|
||||
|
||||
const auto consumed = header_size + body_size;
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin() + consumed);
|
||||
|
||||
const auto remaining = buffer_.size() - consumed;
|
||||
if (remaining <= 0)
|
||||
break;
|
||||
}
|
||||
void HwControlMessageProcessor::handle_command(const std::string &command) {
|
||||
if (command == "power:screen_state:wake")
|
||||
DEBUG("Got screen wake command");
|
||||
else if (command == "power:screen_state:standby")
|
||||
DEBUG("Got screen standby command");
|
||||
else if (utils::string_starts_with(command, "power:light:brightness:lcd_backlight"))
|
||||
DEBUG("Got LCD backligh brightness control command");
|
||||
else
|
||||
DEBUG("Unknown command '%s'", command);
|
||||
}
|
||||
} // namespace support
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -18,29 +18,17 @@
|
|||
#ifndef ANBOX_SUPPORT_HWCONTROL_MESSAGE_PROCESSOR_H_
|
||||
#define ANBOX_SUPPORT_HWCONTROL_MESSAGE_PROCESSOR_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/network/message_processor.h"
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
#include "anbox/network/socket_connection.h"
|
||||
#include "anbox/support/qemud_message_processor.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
class HwControlMessageProcessor : public network::MessageProcessor {
|
||||
class HwControlMessageProcessor : public QemudMessageProcessor {
|
||||
public:
|
||||
HwControlMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger);
|
||||
~HwControlMessageProcessor();
|
||||
|
||||
bool process_data(const std::vector<std::uint8_t> &data) override;
|
||||
|
||||
private:
|
||||
void process_commands();
|
||||
|
||||
std::shared_ptr<network::SocketMessenger> messenger_;
|
||||
std::vector<std::uint8_t> buffer_;
|
||||
protected:
|
||||
void handle_command(const std::string &command) override;
|
||||
};
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
|
||||
#include "anbox/support/null_message_processor.h"
|
||||
#include "anbox/utils.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -27,7 +29,8 @@ NullMessageProcessor::NullMessageProcessor() {
|
|||
NullMessageProcessor::~NullMessageProcessor() {
|
||||
}
|
||||
|
||||
bool NullMessageProcessor::process_data(const std::vector<std::uint8_t>&) {
|
||||
bool NullMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
|
||||
DEBUG("Received: %s", utils::hex_dump(data.data(), data.size()));
|
||||
return true;
|
||||
}
|
||||
} // namespace support
|
||||
|
|
|
|||
|
|
@ -18,11 +18,6 @@
|
|||
#ifndef ANBOX_SUPPORT_NULL_MESSAGE_PROCESSOR_H_
|
||||
#define ANBOX_SUPPORT_NULL_MESSAGE_PROCESSOR_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/network/message_processor.h"
|
||||
|
||||
namespace anbox {
|
||||
|
|
|
|||
87
src/anbox/support/qemud_message_processor.cpp
Normal file
87
src/anbox/support/qemud_message_processor.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/support/qemud_message_processor.h"
|
||||
#include "anbox/utils.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace {
|
||||
static constexpr const long header_size{4};
|
||||
}
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
QemudMessageProcessor::QemudMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger) :
|
||||
messenger_(messenger) {
|
||||
}
|
||||
|
||||
QemudMessageProcessor::~QemudMessageProcessor() {
|
||||
}
|
||||
|
||||
bool QemudMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
|
||||
DEBUG("Received: %s", utils::hex_dump(data.data(), data.size()));
|
||||
|
||||
for (const auto &byte : data)
|
||||
buffer_.push_back(byte);
|
||||
|
||||
process_commands();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QemudMessageProcessor::process_commands() {
|
||||
while (true) {
|
||||
if (buffer_.size() < header_size)
|
||||
break;
|
||||
|
||||
char header[header_size] = { 0 };
|
||||
::memcpy(header, buffer_.data(), header_size);
|
||||
|
||||
unsigned int body_size = 0;
|
||||
::sscanf(header, "%04x", &body_size);
|
||||
if (body_size != buffer_.size() - header_size)
|
||||
break;
|
||||
|
||||
std::string command;
|
||||
// Make sure we only copy as much bytes as we have to and not more
|
||||
command.insert(0, reinterpret_cast<const char*>(buffer_.data()) + header_size, body_size);
|
||||
|
||||
handle_command(command);
|
||||
|
||||
const auto consumed = header_size + body_size;
|
||||
buffer_.erase(buffer_.begin(), buffer_.begin() + consumed);
|
||||
|
||||
const auto remaining = buffer_.size() - consumed;
|
||||
if (remaining <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QemudMessageProcessor::send_header(const size_t &size) {
|
||||
char header[header_size + 1];
|
||||
std::snprintf(header, header_size + 1, "%04x", size);
|
||||
messenger_->send(header, header_size);
|
||||
}
|
||||
|
||||
void QemudMessageProcessor::finish_message() {
|
||||
// Send terminating NULL byte
|
||||
messenger_->send(static_cast<const char*>(""), 1);
|
||||
}
|
||||
} // namespace support
|
||||
} // namespace anbox
|
||||
49
src/anbox/support/qemud_message_processor.h
Normal file
49
src/anbox/support/qemud_message_processor.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_SUPPORT_QEMUD_MESSAGE_PROCESSOR_H_
|
||||
#define ANBOX_SUPPORT_QEMUD_MESSAGE_PROCESSOR_H_
|
||||
|
||||
#include "anbox/network/message_processor.h"
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
class QemudMessageProcessor : public network::MessageProcessor {
|
||||
public:
|
||||
QemudMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger);
|
||||
~QemudMessageProcessor();
|
||||
|
||||
bool process_data(const std::vector<std::uint8_t> &data) override;
|
||||
|
||||
protected:
|
||||
virtual void handle_command(const std::string &command) = 0;
|
||||
|
||||
void send_header(const size_t &size);
|
||||
void finish_message();
|
||||
|
||||
std::shared_ptr<network::SocketMessenger> messenger_;
|
||||
|
||||
private:
|
||||
void process_commands();
|
||||
|
||||
std::vector<std::uint8_t> buffer_;
|
||||
};
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
46
src/anbox/support/sensors_message_processor.cpp
Normal file
46
src/anbox/support/sensors_message_processor.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/logger.h"
|
||||
#include "anbox/support/sensors_message_processor.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
SensorsMessageProcessor::SensorsMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger) :
|
||||
QemudMessageProcessor(messenger) {
|
||||
}
|
||||
|
||||
SensorsMessageProcessor::~SensorsMessageProcessor() {
|
||||
}
|
||||
|
||||
void SensorsMessageProcessor::handle_command(const std::string &command) {
|
||||
DEBUG("command %s", command);
|
||||
if (command == "list-sensors")
|
||||
list_sensors();
|
||||
}
|
||||
|
||||
void SensorsMessageProcessor::list_sensors() {
|
||||
// We don't support sensors yet so we mark all as disabled
|
||||
int mask = 0;
|
||||
char buf[12];
|
||||
snprintf(buf, sizeof(buf), "%d", mask);
|
||||
send_header(strlen(buf));
|
||||
messenger_->send(buf, strlen(buf));
|
||||
finish_message();
|
||||
}
|
||||
} // namespace support
|
||||
} // namespace anbox
|
||||
39
src/anbox/support/sensors_message_processor.h
Normal file
39
src/anbox/support/sensors_message_processor.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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_SUPPORT_SENSORS_MESSAGE_PROCESSOR_H_
|
||||
#define ANBOX_SUPPORT_SENSORS_MESSAGE_PROCESSOR_H_
|
||||
|
||||
#include "anbox/support/qemud_message_processor.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace support {
|
||||
class SensorsMessageProcessor : public QemudMessageProcessor {
|
||||
public:
|
||||
SensorsMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger);
|
||||
~SensorsMessageProcessor();
|
||||
|
||||
protected:
|
||||
void handle_command(const std::string &command) override;
|
||||
|
||||
private:
|
||||
void list_sensors();
|
||||
};
|
||||
} // namespace graphics
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -132,5 +132,12 @@ std::string hex_dump(const uint8_t *data, uint32_t size) {
|
|||
return buffer.str();
|
||||
}
|
||||
|
||||
std::string get_env_value(const std::string &name, const std::string &default_value) {
|
||||
char *value = getenv(name.c_str());
|
||||
if (!value)
|
||||
return default_value;
|
||||
return std::string(value);
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ bool string_starts_with(const std::string &text, const std::string &prefix);
|
|||
|
||||
std::string hex_dump(const uint8_t *data, uint32_t size);
|
||||
|
||||
std::string get_env_value(const std::string &name, const std::string &default_value = "");
|
||||
|
||||
template<typename... Types>
|
||||
static std::string string_format(const std::string& fmt_str, Types&&... args);
|
||||
} // namespace utils
|
||||
|
|
|
|||
22
src/container_main.cpp
Normal file
22
src/container_main.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C" int bwrap_main(int argc, char **argv);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return bwrap_main(argc, argv);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue