This commit is contained in:
Scott Edwards 2017-06-09 13:54:11 -07:00
commit ec926d13ae
112 changed files with 2167 additions and 525 deletions

View file

@ -1,15 +1,16 @@
Make sure you are running the latest version of Anbox before reporting an issue. Make sure you are running the latest version of Anbox before reporting an issue.
Please also check that no similar bug is already reported. Have a look on the Please also check that no similar bug is already reported. Have a look on the list of open bugs at https://github.com/anbox/anbox/issues
list of open bugs at https://github.com/anbox/anbox/issues
**Anbox release (`anbox version`) and system info (`anbox system-info`):** ** Please paste the result of `anbox system-info` below:**
```
[please paste printout of `anbox system-info` here]
```
**Please describe your problem:**
**Description of the problem:** **What were you expecting?:**
**Expected:**
**Additional info:** **Additional info:**

View file

@ -64,9 +64,11 @@ find_package(GLESv2 REQUIRED)
find_package(Protobuf REQUIRED) find_package(Protobuf REQUIRED)
pkg_check_modules(SDL2 sdl2 REQUIRED) pkg_check_modules(SDL2 sdl2 REQUIRED)
pkg_check_modules(SDL2_IMAGE SDL2_image REQUIRED)
pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED) pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED)
pkg_check_modules(DBUS dbus-1 REQUIRED) pkg_check_modules(DBUS dbus-1 REQUIRED)
pkg_check_modules(LXC lxc REQUIRED) pkg_check_modules(LXC lxc REQUIRED)
pkg_check_modules(PROPERTIES_CPP properties-cpp REQUIRED)
pkg_check_modules(MIRCLIENT mirclient) pkg_check_modules(MIRCLIENT mirclient)
if (MIRCLIENT_FOUND) if (MIRCLIENT_FOUND)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMIR_SUPPORT") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMIR_SUPPORT")
@ -94,6 +96,16 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fPIC")
set(ANBOX_TRANSLATOR_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/anbox/translators) set(ANBOX_TRANSLATOR_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/anbox/translators)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTRANSLATOR_INSTALL_DIR=\\\"${CMAKE_INSTALL_PREFIX}/${ANBOX_TRANSLATOR_INSTALL_DIR}\\\"") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTRANSLATOR_INSTALL_DIR=\\\"${CMAKE_INSTALL_PREFIX}/${ANBOX_TRANSLATOR_INSTALL_DIR}\\\"")
if (NOT ANBOX_VERSION)
exec_program("git" ${CMAKE_SOURCE_DIR} ARGS "rev-parse --short HEAD" OUTPUT_VARIABLE GIT_COMMIT_HASH)
set(ANBOX_VERSION "local-${GIT_COMMIT_HASH}")
endif()
if (ANBOX_VERSION_SUFFIX)
set(ANBOX_VERSION "${ANBOX_VERSION}-${ANBOX_VERSION_SUFFIX}")
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/anbox/build/version.h.in
${CMAKE_CURRENT_SOURCE_DIR}/src/anbox/build/version.h)
add_subdirectory(external) add_subdirectory(external)
add_subdirectory(src) add_subdirectory(src)
add_subdirectory(tests) add_subdirectory(tests)
@ -103,3 +115,6 @@ if (NOT "${HOST_CMAKE_C_COMPILER}" STREQUAL "")
message(STATUS "Host C compiler: ${HOST_CMAKE_C_COMPILER}") message(STATUS "Host C compiler: ${HOST_CMAKE_C_COMPILER}")
message(STATUS "Host C compiler: ${HOST_CMAKE_CXX_COMPILER}") message(STATUS "Host C compiler: ${HOST_CMAKE_CXX_COMPILER}")
endif() endif()
install(FILES data/ui/loading-screen.png DESTINATION share/anbox/ui)

View file

@ -1,18 +1,23 @@
[![Snap Status](https://build.snapcraft.io/badge/anbox/anbox.svg)](https://build.snapcraft.io/user/anbox/anbox)
[![Build Status](https://travis-ci.org/anbox/anbox.svg?branch=master)](https://travis-ci.org/anbox/anbox)
# Anbox # Anbox
Anbox is container based approach to boot a full Android system on a Anbox is a container-based approach to boot a full Android system on a
regular GNU Linux system like Ubuntu. regular GNU/Linux system like Ubuntu. In other words: Anbox will let
you run Android on your Linux system without the slowness of
virtualization.
## Overview ## Overview
Anbox uses Linux namespaces (user, pid, uts, net, mount, ipc) to run a Anbox uses Linux namespaces (user, pid, uts, net, mount, ipc) to run a
full Android system in a container and provide Android applications on full Android system in a container and provide Android applications on
any GNU Linux based platform. any GNU/Linux-based platform.
The Android inside the container has no direct access to any hardware. The Android inside the container has no direct access to any hardware.
All hardware access is going through the anbox daemon on the host. We're All hardware access is going through the anbox daemon on the host. We're
reusing what Android implemented within the QEMU based emulator for Open reusing what Android implemented within the QEMU-based emulator for OpenGL
GL ES accelerated rendering. The Android system inside the container uses ES accelerated rendering. The Android system inside the container uses
different pipes to communicate with the host system and sends all hardware different pipes to communicate with the host system and sends all hardware
access commands through these. access commands through these.
@ -128,8 +133,8 @@ $ sudo apt install build-essential cmake cmake-data debhelper dbus google-mock \
libboost-program-options-dev libboost-system-dev libboost-test-dev \ libboost-program-options-dev libboost-system-dev libboost-test-dev \
libboost-thread-dev libcap-dev libdbus-1-dev libdbus-cpp-dev libegl1-mesa-dev \ libboost-thread-dev libcap-dev libdbus-1-dev libdbus-cpp-dev libegl1-mesa-dev \
libgles2-mesa-dev libglib2.0-dev libglm-dev libgtest-dev liblxc1 \ libgles2-mesa-dev libglib2.0-dev libglm-dev libgtest-dev liblxc1 \
libproperties-cpp-dev libprotobuf-dev libsdl2-dev lxc-dev pkg-config \ libproperties-cpp-dev libprotobuf-dev libsdl2-dev libsdl2-image-dev lxc-dev \
protobuf-compiler pkg-config protobuf-compiler
``` ```
Afterwards you can build Anbox with Afterwards you can build Anbox with
@ -172,14 +177,11 @@ Running Anbox from a local build requires a few more things you need to know
about. Please have a look at the ["Runtime Setup"](docs/runtime-setup.md) about. Please have a look at the ["Runtime Setup"](docs/runtime-setup.md)
documentation. documentation.
An alias will save typing later.
``` ```
$ alias android='anbox launch --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity' $ anbox launch --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity'
$ alias android >> ~/.bashrc
$ android
``` ```
## documentation ## Documentation
You will find additional documentation for Anbox in the *docs* subdirectory You will find additional documentation for Anbox in the *docs* subdirectory
of the project source. of the project source.
@ -196,7 +198,7 @@ If you have found an issue with Anbox, please [file a bug](https://github.com/an
## Get in Touch ## Get in Touch
If you want to get in contact with the developers please feel free to join the If you want to get in contact with the developers please feel free to join the
*#anbox* IRC channel on [FreeNode](https://freenode.net/). *#anbox* IRC channel on [Freenode](https://freenode.net/).
## Copyright and Licensing ## Copyright and Licensing
@ -204,5 +206,5 @@ Anbox reuses code from other projects like the Android QEMU emulator. These
projects are available in the external/ subdirectory with the licensing terms projects are available in the external/ subdirectory with the licensing terms
included. included.
The anbox source itself, if not stated differently in the relevant source files, The Anbox source itself, if not stated differently in the relevant source files,
is licensed under the terms of the GPLv3 license. is licensed under the terms of the GPLv3 license.

92
cmake/FindGMock.cmake Normal file
View file

@ -0,0 +1,92 @@
# Copyright (C) 2014 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 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 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/>.
# Build with system gmock and embedded gtest
#
# Usage:
#
# find_package(GMock)
#
# ...
#
# target_link_libraries(
# my-target
# ${GTEST_BOTH_LIBRARIES}
# )
#
# NOTE: Due to the way this package finder is implemented, do not attempt
# to find the GMock package more than once.
find_package(Threads)
if (EXISTS "/usr/src/googletest")
# As of version 1.8.0
set(GMOCK_SOURCE_DIR "/usr/src/googletest/googlemock" CACHE PATH "gmock source directory")
set(GMOCK_INCLUDE_DIRS "${GMOCK_SOURCE_DIR}/include" CACHE PATH "gmock source include directory")
set(GTEST_INCLUDE_DIRS "/usr/src/googletest/googletest/include" CACHE PATH "gtest source include directory")
else()
set(GMOCK_SOURCE_DIR "/usr/src/gmock" CACHE PATH "gmock source directory")
set(GMOCK_INCLUDE_DIRS "/usr/include" CACHE PATH "gmock source include directory")
set(GTEST_INCLUDE_DIRS "/usr/include" CACHE PATH "gtest source include directory")
endif()
# We add -g so we get debug info for the gtest stack frames with gdb.
# The warnings are suppressed so we get a noise-free build for gtest and gmock if the caller
# has these warnings enabled.
set(findgmock_cxx_flags "${CMAKE_CXX_FLAGS} -g -Wno-old-style-cast -Wno-missing-field-initializers -Wno-ctor-dtor-privacy -Wno-switch-default")
set(findgmock_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/gmock")
set(findgmock_gtest_lib "${findgmock_bin_dir}/gtest/libgtest.a")
set(findgmock_gtest_main_lib "${findgmock_bin_dir}/gtest/libgtest_main.a")
set(findgmock_gmock_lib "${findgmock_bin_dir}/libgmock.a")
set(findgmock_gmock_main_lib "${findgmock_bin_dir}/libgmock_main.a")
include(ExternalProject)
ExternalProject_Add(GMock SOURCE_DIR "${GMOCK_SOURCE_DIR}"
BINARY_DIR "${findgmock_bin_dir}"
BUILD_BYPRODUCTS "${findgmock_gtest_lib}"
"${findgmock_gtest_main_lib}"
"${findgmock_gmock_lib}"
"${findgmock_gmock_main_lib}"
INSTALL_COMMAND ""
CMAKE_ARGS "-DCMAKE_CXX_FLAGS=${findgmock_cxx_flags}")
add_library(gtest INTERFACE)
target_include_directories(gtest INTERFACE ${GTEST_INCLUDE_DIRS})
target_link_libraries(gtest INTERFACE ${findgmock_gtest_lib} ${CMAKE_THREAD_LIBS_INIT})
add_dependencies(gtest GMock)
add_library(gtest_main INTERFACE)
target_include_directories(gtest_main INTERFACE ${GTEST_INCLUDE_DIRS})
target_link_libraries(gtest_main INTERFACE ${findgmock_gtest_main_lib} gtest)
add_library(gmock INTERFACE)
target_include_directories(gmock INTERFACE ${GMOCK_INCLUDE_DIRS})
target_link_libraries(gmock INTERFACE ${findgmock_gmock_lib} gtest)
add_library(gmock_main INTERFACE)
target_include_directories(gmock_main INTERFACE ${GMOCK_INCLUDE_DIRS})
target_link_libraries(gmock_main INTERFACE ${findgmock_gmock_main_lib} gmock)
set(GTEST_LIBRARIES gtest)
set(GTEST_MAIN_LIBRARIES gtest_main)
set(GMOCK_LIBRARIES gmock gmock_main)
set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
unset(findgmock_cxx_flags)
unset(findgmock_bin_dir)
unset(findgmock_gtest_lib)
unset(findgmock_gtest_main_lib)
unset(findgmock_gmock_lib)
unset(findgmock_gmock_main_lib)

View file

@ -2,7 +2,11 @@
Description=Anbox session manager Description=Anbox session manager
[Service] [Service]
Type=simple
ExecStart=@SNAP_MOUNT_DIR@/anbox session-manager ExecStart=@SNAP_MOUNT_DIR@/anbox session-manager
Restart=always
StartLimitIntervalSec=3
StartLimitBurst=1
[Install] [Install]
WantedBy=default.target WantedBy=default.target

BIN
data/ui/loading-screen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,3 +1,4 @@
etc/X11/Xsession.d/68anbox etc/X11/Xsession.d/68anbox
usr/share/upstart/sessions/anbox.conf usr/share/upstart/sessions/anbox.conf
usr/lib/systemd/user/anbox.service usr/lib/systemd/user/anbox.service
usr/lib/systemd/user/default.target.wants/anbox.service

7
debian/changelog vendored
View file

@ -1,3 +1,10 @@
anbox (6) artful; urgency=medium
* Add anbox-common package which ships any additional files needed for
anbox but can't be installed with a snap as of today.
-- Simon Fels <morphis@gravedo.de> Sat, 29 Apr 2017 12:06:56 +0200
anbox (5) zesty; urgency=medium anbox (5) zesty; urgency=medium
* Rework packaging to also ship things we installed through the snap * Rework packaging to also ship things we installed through the snap

2
debian/control vendored
View file

@ -10,7 +10,7 @@ Vcs-Git: https://github.com/anbox/anbox.git
Package: anbox-common Package: anbox-common
Architecture: all Architecture: all
Depends: ${misc:Depends} Depends: ${misc:Depends}, dbus-user-session
Description: Common files necessary for Anbox Description: Common files necessary for Anbox
. .
This package contains necessary things which can't be shipped This package contains necessary things which can't be shipped

3
debian/rules vendored
View file

@ -28,8 +28,9 @@ override_dh_install:
install -d $(CURDIR)/debian/tmp/etc/modules-load.d install -d $(CURDIR)/debian/tmp/etc/modules-load.d
install -m 0644 kernel/anbox.conf $(CURDIR)/debian/tmp/etc/modules-load.d install -m 0644 kernel/anbox.conf $(CURDIR)/debian/tmp/etc/modules-load.d
install -d $(CURDIR)/debian/tmp/usr/lib/systemd/user/ install -d $(CURDIR)/debian/tmp/usr/lib/systemd/user/default.target.wants
install -m 0644 data/anbox.service $(CURDIR)/debian/tmp/usr/lib/systemd/user/ install -m 0644 data/anbox.service $(CURDIR)/debian/tmp/usr/lib/systemd/user/
ln -sf /usr/lib/systemd/user/anbox.service $(CURDIR)/debian/tmp/usr/lib/systemd/user/default.target.wants/anbox.service
install -d $(CURDIR)/debian/tmp/usr/share/upstart/sessions/ install -d $(CURDIR)/debian/tmp/usr/share/upstart/sessions/
install -m 0644 data/anbox.conf $(CURDIR)/debian/tmp/usr/share/upstart/sessions/ install -m 0644 data/anbox.conf $(CURDIR)/debian/tmp/usr/share/upstart/sessions/

View file

@ -33,8 +33,15 @@ This will take quite some time depending on the speed of your internet connectio
## Build Android ## Build Android
When all sources are successfully downloaded you can start building Android When all sources are successfully downloaded you can start building Android itself.
itself. Initialize the build by
Firstly initialize the environment with the ```envsetup.sh``` script.
```
$ . build/envsetup.sh
```
Then initialize the build using ```lunch```.
``` ```
$ lunch anbox_desktop_x86_64-userdebug $ lunch anbox_desktop_x86_64-userdebug
@ -43,7 +50,7 @@ $ lunch anbox_desktop_x86_64-userdebug
The complete list of supported build targets: The complete list of supported build targets:
* anbox_desktop_x86_64-userdebug * anbox_desktop_x86_64-userdebug
* anbox_desktop_armv7a_arm-userdebug * anbox_desktop_armv7a_neon-userdebug
* anbox_desktop_arm64-userdebug * anbox_desktop_arm64-userdebug
Now build everything with Now build everything with

View file

@ -20,5 +20,5 @@ if ("${cmake_build_type_lower}" STREQUAL "trace")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}")
endif() endif()
add_library(GLESv1_dec ${SOURCES} ${GENERATED_SOURCES}) add_library(GLESv1_dec STATIC ${SOURCES} ${GENERATED_SOURCES})
target_link_libraries(GLESv1_dec OpenglCodecCommon) target_link_libraries(GLESv1_dec OpenglCodecCommon)

View file

@ -20,5 +20,5 @@ if ("${cmake_build_type_lower}" STREQUAL "trace")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}")
endif() endif()
add_library(GLESv2_dec ${SOURCES} ${GENERATED_SOURCES}) add_library(GLESv2_dec STATIC ${SOURCES} ${GENERATED_SOURCES})
target_link_libraries(GLESv2_dec OpenglCodecCommon) target_link_libraries(GLESv2_dec OpenglCodecCommon)

View file

@ -12,6 +12,6 @@ set(SOURCES
objectNameManager.cpp objectNameManager.cpp
FramebufferData.cpp) FramebufferData.cpp)
add_library(GLcommon ${SOURCES}) add_library(GLcommon STATIC ${SOURCES})
target_link_libraries(GLcommon target_link_libraries(GLcommon
emugl_common) emugl_common)

View file

@ -3,7 +3,7 @@ set(SOURCES
GLESv2Dispatch.cpp GLESv2Dispatch.cpp
GLESv1Dispatch.cpp) GLESv1Dispatch.cpp)
add_library(OpenGLESDispatch ${SOURCES} ${GENERATED_SOURCES}) add_library(OpenGLESDispatch STATIC ${SOURCES} ${GENERATED_SOURCES})
target_link_libraries(OpenGLESDispatch target_link_libraries(OpenGLESDispatch
emugl_common emugl_common
GLESv2_dec GLESv2_dec

View file

@ -16,5 +16,5 @@ if ("${cmake_build_type_lower}" STREQUAL "trace")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPENGL_DEBUG}")
endif() endif()
add_library(renderControl_dec ${GENERATED_SOURCES}) add_library(renderControl_dec STATIC ${GENERATED_SOURCES})
target_link_libraries(renderControl_dec OpenglCodecCommon) target_link_libraries(renderControl_dec OpenglCodecCommon)

View file

@ -12,4 +12,4 @@ set(SOURCES
Makefile Makefile
ProtocolUtils.h) ProtocolUtils.h)
add_library(OpenglCodecCommon ${SOURCES}) add_library(OpenglCodecCommon STATIC ${SOURCES})

View file

@ -28,6 +28,6 @@ set(COMMON_SOURCES
thread_unittest.cpp thread_unittest.cpp
unique_integer_map.h) unique_integer_map.h)
add_library(emugl_common ${COMMON_SOURCES}) add_library(emugl_common STATIC ${COMMON_SOURCES})
target_link_libraries(emugl_common target_link_libraries(emugl_common
dl pthread) dl pthread)

View file

@ -114,6 +114,12 @@ public:
*/ */
wait::Result wait_for(const wait::Flags& flags); wait::Result wait_for(const wait::Flags& flags);
/**
* @brief Mark the child process to not to be killed when the ChildProcess
* instance goes away.
*/
void dont_kill_on_cleanup();
#ifndef ANDROID #ifndef ANDROID
/** /**
* @brief Access this process's stderr. * @brief Access this process's stderr.

View file

@ -15,6 +15,8 @@
# Authored by: Thomas Voss <thomas.voss@canonical.com> # Authored by: Thomas Voss <thomas.voss@canonical.com>
add_library( add_library(
process-cpp process-cpp
STATIC
core/posix/backtrace.h core/posix/backtrace.h
core/posix/backtrace.cpp core/posix/backtrace.cpp

View file

@ -303,7 +303,7 @@ struct ChildProcess::Private
~Private() ~Private()
{ {
// Check if we are in the original parent process. // Check if we are in the original parent process.
if (original_parent_pid == getpid()) if (original_parent_pid == getpid() && !dont_kill_on_cleanup)
{ {
// If so, check if we are considering a valid pid here. // If so, check if we are considering a valid pid here.
// If so, we kill the original child. // If so, we kill the original child.
@ -333,6 +333,8 @@ struct ChildProcess::Private
// is called from the child process. // is called from the child process.
pid_t original_parent_pid; pid_t original_parent_pid;
pid_t original_child_pid; pid_t original_child_pid;
bool dont_kill_on_cleanup = false;
}; };
ChildProcess ChildProcess::invalid() ChildProcess ChildProcess::invalid()
@ -395,6 +397,11 @@ wait::Result ChildProcess::wait_for(const wait::Flags& flags)
return result; return result;
} }
void ChildProcess::dont_kill_on_cleanup()
{
d->dont_kill_on_cleanup = true;
}
#ifndef ANDROID #ifndef ANDROID
std::istream& ChildProcess::cerr() std::istream& ChildProcess::cerr()
{ {

View file

@ -11,7 +11,7 @@ include_directories(
${Boost_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
) )
add_library(xdg xdg.cpp) add_library(xdg STATIC xdg.cpp)
set_property(TARGET xdg PROPERTY CXX_STANDARD 11) set_property(TARGET xdg PROPERTY CXX_STANDARD 11)
target_link_libraries(xdg ${Boost_LIBRARIES}) target_link_libraries(xdg ${Boost_LIBRARIES})

View file

@ -57,7 +57,6 @@ constexpr const char* xdg_data_dirs{"XDG_DATA_DIRS"};
constexpr const char* xdg_config_home{"XDG_CONFIG_HOME"}; constexpr const char* xdg_config_home{"XDG_CONFIG_HOME"};
constexpr const char* xdg_config_dirs{"XDG_CONFIG_DIRS"}; constexpr const char* xdg_config_dirs{"XDG_CONFIG_DIRS"};
constexpr const char* xdg_cache_home{"XDG_CACHE_HOME"}; constexpr const char* xdg_cache_home{"XDG_CACHE_HOME"};
constexpr const char* xdg_runtime_dir{"XDG_RUNTIME_DIR"};
} }
namespace impl namespace impl

View file

@ -1,7 +1,7 @@
PACKAGE_NAME="anbox-ashmem" PACKAGE_NAME="anbox-ashmem"
PACKAGE_VERSION="1" PACKAGE_VERSION="1"
CLEAN="make clean" CLEAN="make clean"
MAKE[0]="make all KVERSION=$kernelver" MAKE[0]="make all KERNEL_SRC=/lib/modules/$kernelver/build"
BUILT_MODULE_NAME[0]="ashmem_linux" BUILT_MODULE_NAME[0]="ashmem_linux"
DEST_MODULE_LOCATION[0]="/updates" DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes" AUTOINSTALL="yes"

View file

@ -1,7 +1,7 @@
PACKAGE_NAME="anbox-binder" PACKAGE_NAME="anbox-binder"
PACKAGE_VERSION="1" PACKAGE_VERSION="1"
CLEAN="make clean" CLEAN="make clean"
MAKE[0]="make all KVERSION=$kernelver" MAKE[0]="make all KERNEL_SRC=/lib/modules/$kernelver/build"
BUILT_MODULE_NAME[0]="binder_linux" BUILT_MODULE_NAME[0]="binder_linux"
DEST_MODULE_LOCATION[0]="/updates" DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes" AUTOINSTALL="yes"

View file

@ -0,0 +1,185 @@
From 8f8ac2552c4a411cf1b8c6328409f861248e8d0d Mon Sep 17 00:00:00 2001
From: Oren Laadan <orenl@cellrox.com>
Date: Sun, 22 Dec 2013 10:07:39 +0000
Subject: [PATCH 1/2] ipc namespace: a generic per-ipc pointer and peripc_ops
Add a void * pointer to struct ipc_namespace. The access rules are:
1. (un)register ops with (un)register_peripc_operations()
2. call ipc_assign_generic() to put private data on the ipc_namespace
3. call ipc_access_generic() to access the private data
4. do not change the pointer during the lifetime of ipc_namespace
Modeled after generic net-ns pointers (commit dec827d), but simplified
to accommodate a single user for now (reduce code churn):
5. only one caller can register at a time
6. caller must register at boot time (not to be used by modules)
Signed-off-by: Oren Laadan <orenl@cellrox.com>
Signed-off-by: Amir Goldstein <cardoe@cardoe.com>
---
include/linux/ipc_namespace.h | 29 +++++++++++++++++++++
ipc/namespace.c | 9 +++++++
ipc/util.c | 60 +++++++++++++++++++++++++++++++++++++++++++
ipc/util.h | 3 +++
4 files changed, 101 insertions(+)
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index d6ad91f..535061a 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -70,8 +70,37 @@ struct ipc_namespace {
struct user_namespace *user_ns;
unsigned int proc_inum;
+
+ /* allow others to piggyback on ipc_namesspaces */
+ void *gen; /* for others' private stuff */
};
+/*
+ * To access to the per-ipc generic data:
+ * 1. (un)register ops with (un)register_peripc_operations()
+ * 2. call ipc_assign_generic() to put private data on the ipc_namespace
+ * 3. call ipc_access_generic() to access the private data
+ * 4. do not change the pointer during the lifetime of ipc_namespace
+ *
+ * Modeled after generic net-ns pointers (commit dec827d), simplified for
+ * a single user case for now:
+ * 5. only one caller can register at a time
+ * 6. caller must register at boot time (not to be used by modules)
+ */
+struct peripc_operations {
+ int (*init)(struct ipc_namespace *);
+ void (*exit)(struct ipc_namespace *);
+};
+
+static inline void ipc_assign_generic(struct ipc_namespace *ns, void *data)
+{ ns->gen = data; }
+
+static inline void *ipc_access_generic(struct ipc_namespace *ns)
+{ return ns->gen; }
+
+extern int register_peripc_ops(struct peripc_operations *ops);
+extern void unregister_peripc_ops(struct peripc_operations *ops);
+
extern struct ipc_namespace init_ipc_ns;
extern atomic_t nr_ipc_ns;
diff --git a/ipc/namespace.c b/ipc/namespace.c
index aba9a58..575aeae 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -33,9 +33,17 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
}
atomic_set(&ns->count, 1);
+
+ err = init_peripc_ns(ns);
+ if (err) {
+ kfree(ns);
+ return ERR_PTR(err);
+ }
+
err = mq_init_ns(ns);
if (err) {
proc_free_inum(ns->proc_inum);
+ exit_peripc_ns(ns);
kfree(ns);
return ERR_PTR(err);
}
@@ -111,6 +119,7 @@ static void free_ipc_ns(struct ipc_namespace *ns)
sem_exit_ns(ns);
msg_exit_ns(ns);
shm_exit_ns(ns);
+ exit_peripc_ns(ns);
atomic_dec(&nr_ipc_ns);
/*
diff --git a/ipc/util.c b/ipc/util.c
index 7353425..533f8f9 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -71,6 +71,66 @@ struct ipc_proc_iface {
int (*show)(struct seq_file *, void *);
};
+/* allow others to piggyback on ipc_namespace */
+static DEFINE_MUTEX(peripc_mutex);
+static struct peripc_operations *peripc_ops;
+
+/*
+ * peripc_operations is a simplified pernet_operations:
+ * - allow only one entity to register
+ * - allow to register only at boot time (no modules)
+ * (these assumptions make the code much simpler)
+ */
+
+static int init_peripc_count;
+
+/* caller hold peripc_mutex */
+int init_peripc_ns(struct ipc_namespace *ns)
+{
+ int ret = 0;
+
+ if (peripc_ops && peripc_ops->init)
+ ret = peripc_ops->init(ns);
+ if (ret == 0)
+ init_peripc_count++;
+ return ret;
+}
+
+/* caller hold peripc_mutex */
+void exit_peripc_ns(struct ipc_namespace *ns)
+{
+ if (peripc_ops && peripc_ops->exit)
+ peripc_ops->exit(ns);
+ init_peripc_count--;
+}
+
+int register_peripc_ops(struct peripc_operations *ops)
+{
+ int ret = -EBUSY;
+
+ mutex_lock(&peripc_mutex);
+ /* must be first register, and only init ipc_namespace exists */
+ if (peripc_ops == NULL && init_peripc_count == 0) {
+ peripc_ops = ops;
+ ret = init_peripc_ns(&init_ipc_ns);
+ if (ret < 0)
+ peripc_ops = NULL;
+ }
+ mutex_unlock(&peripc_mutex);
+ return ret;
+}
+
+void unregister_peripc_ops(struct peripc_operations *ops)
+{
+ mutex_lock(&peripc_mutex);
+ /* sanity: be same as registered, and no other ipc ns (beyond init) */
+ BUG_ON(peripc_ops != ops);
+ BUG_ON(init_peripc_count != 1);
+ if (ops->exit)
+ exit_peripc_ns(&init_ipc_ns);
+ peripc_ops = NULL;
+ mutex_unlock(&peripc_mutex);
+}
static void ipc_memory_notifier(struct work_struct *work)
{
ipcns_notify(IPCNS_MEMCHANGED);
diff --git a/ipc/util.h b/ipc/util.h
index 59d78aa..daee0be 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -47,6 +47,9 @@ static inline void msg_exit_ns(struct ipc_namespace *ns) { }
static inline void shm_exit_ns(struct ipc_namespace *ns) { }
#endif
+int init_peripc_ns(struct ipc_namespace *ns);
+void exit_peripc_ns(struct ipc_namespace *ns);
+
struct ipc_rcu {
struct rcu_head rcu;
atomic_t refcount;
--
2.7.4

View file

@ -0,0 +1,428 @@
From fcd9d70190dd7e6536878a6379122f06e3b90919 Mon Sep 17 00:00:00 2001
From: Oren Laadan <orenl@cellrox.com>
Date: Sun, 22 Dec 2013 10:07:40 +0000
Subject: [PATCH 2/2] binder: implement namepsace support for Android binder
driver
Add namespaces support for the Android binder driver.
As binder is an IPC mechanism, tie its namespace to IPC_NS.
In binder, the first process to call BINDER_SET_CONTEXT_MGR ioctl
becomes the manager with context 0, and thereafter IPC is realized
through binder handles obtained from this manager.
For namespaces, associate a separate binder state with each namespace
so each namespace has its own context manager. Binder users within a
namespace interact only with the context manager there. This suffices
because binder does not allow IPC not via the context manager.
Currently, statistics remain global, except for the list of processes
that hold an open binder device (reported per namespace).
Signed-off-by: Oren Laadan <orenl@cellrox.com>
Acked-by: Amir Goldstein <cardoe@cardoe.com>
---
drivers/android/Kconfig | 1 +
drivers/android/binder.c | 172 ++++++++++++++++++++++++++++++++++++++---------
2 files changed, 143 insertions(+), 30 deletions(-)
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig
index bdfc6c6..739063d 100644
--- a/drivers/android/Kconfig
+++ b/drivers/android/Kconfig
@@ -10,6 +10,7 @@ if ANDROID
config ANDROID_BINDER_IPC
bool "Android Binder IPC Driver"
depends on MMU
+ select SYSVIPC
default n
---help---
Binder is used in Android for both communication between processes,
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index fee479d..2a63e9b 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -37,6 +37,7 @@
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/ipc_namespace.h>
#include <linux/pid_namespace.h>
#include <linux/security.h>
@@ -47,19 +48,98 @@
#include <uapi/linux/android/binder.h>
#include "binder_trace.h"
+/*
+ * Using a private context manager for each binder namespace is sufficient
+ * to isolate between namespaces, because in binder all IPC must be realized
+ * via hanldes obtained from the context manager.
+ *
+ * TODO: currently, most debugfs data is not tracked per binder namespaces.
+ * Except for "procs" which are properly virtualized, everything else is
+ * global, including stats, logs, and dead nodes.
+ */
+struct binder_namespace {
+ struct kref kref;
+
+ struct binder_node *context_mgr_node;
+ kuid_t context_mgr_uid;
+ int last_id;
+
+ struct hlist_head procs;
+};
+
+static struct binder_namespace *create_binder_ns(void)
+{
+ struct binder_namespace *binder_ns;
+
+ binder_ns = kzalloc(sizeof(struct binder_namespace), GFP_KERNEL);
+ if (binder_ns) {
+ kref_init(&binder_ns->kref);
+ binder_ns->context_mgr_uid = INVALID_UID;
+ INIT_HLIST_HEAD(&binder_ns->procs);
+ }
+ return binder_ns;
+}
+
+static void free_binder_ns(struct kref *kref)
+{
+ kfree(container_of(kref, struct binder_namespace, kref));
+}
+
+static void get_binder_ns(struct binder_namespace *binder_ns)
+{
+ kref_get(&binder_ns->kref);
+}
+
+static void put_binder_ns(struct binder_namespace *binder_ns)
+{
+ kref_put(&binder_ns->kref, free_binder_ns);
+}
+
+/*
+ * Binder is an IPC mechanism, so tie its namespace to IPC_NS
+ * using the generic data pointer and per-ipc operations.
+ */
+static struct binder_namespace *current_binder_ns(void)
+{
+ return ipc_access_generic(current->nsproxy->ipc_ns);
+}
+
+int binder_init_ns(struct ipc_namespace *ipcns)
+{
+ struct binder_namespace *binder_ns;
+ int ret = -ENOMEM;
+
+ binder_ns = create_binder_ns();
+ if (binder_ns) {
+ ipc_assign_generic(ipcns, binder_ns);
+ ret = 0;
+ }
+ return ret;
+}
+
+void binder_exit_ns(struct ipc_namespace *ipcns)
+{
+ struct binder_namespace *binder_ns;
+
+ binder_ns = ipc_access_generic(ipcns);
+ if (binder_ns)
+ put_binder_ns(binder_ns);
+}
+
+struct peripc_operations binder_peripc_ops = {
+ .init = binder_init_ns,
+ .exit = binder_exit_ns,
+};
+
static DEFINE_RT_MUTEX(binder_main_lock);
static DEFINE_MUTEX(binder_deferred_lock);
static DEFINE_MUTEX(binder_mmap_lock);
-static HLIST_HEAD(binder_procs);
static HLIST_HEAD(binder_deferred_list);
static HLIST_HEAD(binder_dead_nodes);
static struct dentry *binder_debugfs_dir_entry_root;
static struct dentry *binder_debugfs_dir_entry_proc;
-static struct binder_node *binder_context_mgr_node;
-static kuid_t binder_context_mgr_uid = INVALID_UID;
-static int binder_last_id;
static struct workqueue_struct *binder_deferred_workqueue;
#define BINDER_DEBUG_ENTRY(name) \
@@ -327,6 +407,8 @@ struct binder_proc {
int ready_threads;
long default_priority;
struct dentry *debugfs_entry;
+
+ struct binder_namespace *binder_ns;
};
enum {
@@ -910,7 +992,7 @@ static struct binder_node *binder_new_node(struct binder_proc *proc,
binder_stats_created(BINDER_STAT_NODE);
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
- node->debug_id = ++binder_last_id;
+ node->debug_id = ++proc->binder_ns->last_id;
node->proc = proc;
node->ptr = ptr;
node->cookie = cookie;
@@ -931,7 +1013,7 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal,
if (internal) {
if (target_list == NULL &&
node->internal_strong_refs == 0 &&
- !(node == binder_context_mgr_node &&
+ !(node == node->proc->binder_ns->context_mgr_node &&
node->has_strong_ref)) {
pr_err("invalid inc strong node for %d\n",
node->debug_id);
@@ -1045,13 +1127,13 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
if (new_ref == NULL)
return NULL;
binder_stats_created(BINDER_STAT_REF);
- new_ref->debug_id = ++binder_last_id;
+ new_ref->debug_id = ++proc->binder_ns->last_id;
new_ref->proc = proc;
new_ref->node = node;
rb_link_node(&new_ref->rb_node_node, parent, p);
rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
- new_ref->desc = (node == binder_context_mgr_node) ? 0 : 1;
+ new_ref->desc = (node == proc->binder_ns->context_mgr_node) ? 0 : 1;
for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
ref = rb_entry(n, struct binder_ref, rb_node_desc);
if (ref->desc > new_ref->desc)
@@ -1391,7 +1473,7 @@ static void binder_transaction(struct binder_proc *proc,
}
target_node = ref->node;
} else {
- target_node = binder_context_mgr_node;
+ target_node = proc->binder_ns->context_mgr_node;
if (target_node == NULL) {
return_error = BR_DEAD_REPLY;
goto err_no_context_mgr_node;
@@ -1452,7 +1534,7 @@ static void binder_transaction(struct binder_proc *proc,
}
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
- t->debug_id = ++binder_last_id;
+ t->debug_id = ++proc->binder_ns->last_id;
e->debug_id = t->debug_id;
if (reply)
@@ -1787,10 +1869,10 @@ static int binder_thread_write(struct binder_proc *proc,
if (get_user(target, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
- if (target == 0 && binder_context_mgr_node &&
+ if (target == 0 && proc->binder_ns->context_mgr_node &&
(cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
ref = binder_get_ref_for_node(proc,
- binder_context_mgr_node);
+ proc->binder_ns->context_mgr_node);
if (ref->desc != target) {
binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n",
proc->pid, thread->pid,
@@ -2696,9 +2778,10 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
+ struct binder_namespace *binder_ns = proc->binder_ns;
kuid_t curr_euid = current_euid();
- if (binder_context_mgr_node != NULL) {
+ if (binder_ns->context_mgr_node != NULL) {
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
goto out;
@@ -2706,27 +2789,27 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
ret = security_binder_set_context_mgr(proc->tsk);
if (ret < 0)
goto out;
- if (uid_valid(binder_context_mgr_uid)) {
- if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
+ if (uid_valid(binder_ns->context_mgr_uid)) {
+ if (!uid_eq(binder_ns->context_mgr_uid, curr_euid)) {
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
from_kuid(&init_user_ns, curr_euid),
from_kuid(&init_user_ns,
- binder_context_mgr_uid));
+ binder_ns->context_mgr_uid));
ret = -EPERM;
goto out;
}
} else {
- binder_context_mgr_uid = curr_euid;
+ binder_ns->context_mgr_uid = curr_euid;
}
- binder_context_mgr_node = binder_new_node(proc, 0, 0);
- if (binder_context_mgr_node == NULL) {
+ binder_ns->context_mgr_node = binder_new_node(proc, 0, 0);
+ if (binder_ns->context_mgr_node == NULL) {
ret = -ENOMEM;
goto out;
}
- binder_context_mgr_node->local_weak_refs++;
- binder_context_mgr_node->local_strong_refs++;
- binder_context_mgr_node->has_strong_ref = 1;
- binder_context_mgr_node->has_weak_ref = 1;
+ binder_ns->context_mgr_node->local_weak_refs++;
+ binder_ns->context_mgr_node->local_strong_refs++;
+ binder_ns->context_mgr_node->has_strong_ref = 1;
+ binder_ns->context_mgr_node->has_weak_ref = 1;
out:
return ret;
}
@@ -2947,10 +3030,15 @@ err_bad_arg:
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
+ struct binder_namespace *binder_ns;
binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
current->group_leader->pid, current->pid);
+ binder_ns = current_binder_ns();
+ if (binder_ns == NULL)
+ return -ENOMEM;
+
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
@@ -2960,10 +3048,13 @@ static int binder_open(struct inode *nodp, struct file *filp)
init_waitqueue_head(&proc->wait);
proc->default_priority = task_nice(current);
+ proc->binder_ns = binder_ns;
+ get_binder_ns(binder_ns);
+
binder_lock(__func__);
binder_stats_created(BINDER_STAT_PROC);
- hlist_add_head(&proc->proc_node, &binder_procs);
+ hlist_add_head(&proc->proc_node, &binder_ns->procs);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;
@@ -3067,6 +3158,7 @@ static int binder_node_release(struct binder_node *node, int refs)
static void binder_deferred_release(struct binder_proc *proc)
{
+ struct binder_namespace *binder_ns = proc->binder_ns;
struct binder_transaction *t;
struct rb_node *n;
int threads, nodes, incoming_refs, outgoing_refs, buffers,
@@ -3077,11 +3169,12 @@ static void binder_deferred_release(struct binder_proc *proc)
hlist_del(&proc->proc_node);
- if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) {
+ if (binder_ns->context_mgr_node &&
+ binder_ns->context_mgr_node->proc == proc) {
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"%s: %d context_mgr_node gone\n",
__func__, proc->pid);
- binder_context_mgr_node = NULL;
+ binder_ns->context_mgr_node = NULL;
}
threads = 0;
@@ -3160,6 +3253,7 @@ static void binder_deferred_release(struct binder_proc *proc)
vfree(proc->buffer);
}
+ put_binder_ns(proc->binder_ns);
put_task_struct(proc->tsk);
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
@@ -3540,10 +3634,14 @@ static void print_binder_proc_stats(struct seq_file *m,
static int binder_state_show(struct seq_file *m, void *unused)
{
+ struct binder_namespace *binder_ns = current_binder_ns();
struct binder_proc *proc;
struct binder_node *node;
int do_lock = !binder_debug_no_lock;
+ if (binder_ns == NULL)
+ return 0;
+
if (do_lock)
binder_lock(__func__);
@@ -3554,7 +3652,7 @@ static int binder_state_show(struct seq_file *m, void *unused)
hlist_for_each_entry(node, &binder_dead_nodes, dead_node)
print_binder_node(m, node);
- hlist_for_each_entry(proc, &binder_procs, proc_node)
+ hlist_for_each_entry(proc, &binder_ns->procs, proc_node)
print_binder_proc(m, proc, 1);
if (do_lock)
binder_unlock(__func__);
@@ -3563,9 +3661,13 @@ static int binder_state_show(struct seq_file *m, void *unused)
static int binder_stats_show(struct seq_file *m, void *unused)
{
+ struct binder_namespace *binder_ns = current_binder_ns();
struct binder_proc *proc;
int do_lock = !binder_debug_no_lock;
+ if (binder_ns == NULL)
+ return 0;
+
if (do_lock)
binder_lock(__func__);
@@ -3573,7 +3675,7 @@ static int binder_stats_show(struct seq_file *m, void *unused)
print_binder_stats(m, "", &binder_stats);
- hlist_for_each_entry(proc, &binder_procs, proc_node)
+ hlist_for_each_entry(proc, &binder_ns->procs, proc_node)
print_binder_proc_stats(m, proc);
if (do_lock)
binder_unlock(__func__);
@@ -3582,14 +3684,18 @@ static int binder_stats_show(struct seq_file *m, void *unused)
static int binder_transactions_show(struct seq_file *m, void *unused)
{
+ struct binder_namespace *binder_ns = current_binder_ns();
struct binder_proc *proc;
int do_lock = !binder_debug_no_lock;
+ if (binder_ns == NULL)
+ return 0;
+
if (do_lock)
binder_lock(__func__);
seq_puts(m, "binder transactions:\n");
- hlist_for_each_entry(proc, &binder_procs, proc_node)
+ hlist_for_each_entry(proc, &binder_ns->procs, proc_node)
print_binder_proc(m, proc, 0);
if (do_lock)
binder_unlock(__func__);
@@ -3661,9 +3767,15 @@ static int __init binder_init(void)
{
int ret;
+ ret = register_peripc_ops(&binder_peripc_ops);
+ if (ret < 0)
+ return ret;
+
binder_deferred_workqueue = create_singlethread_workqueue("binder");
- if (!binder_deferred_workqueue)
+ if (!binder_deferred_workqueue) {
+ unregister_peripc_ops(&binder_peripc_ops);
return -ENOMEM;
+ }
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root)
--
2.7.4

View file

@ -14,34 +14,21 @@
# limitations under the License. # limitations under the License.
# Taken from https://github.com/lxc/lxd-pkg-ubuntu/blob/dpm-xenial/lxd-bridge/lxd-bridge # Taken from https://github.com/lxc/lxd-pkg-ubuntu/blob/dpm-xenial/lxd-bridge/lxd-bridge
# but modified for the use within anbox.
varrun="/run/anbox" varrun="/run/anbox"
varlib="/var/lib/anbox"
BRIDGE="anboxbr0" BRIDGE="anbox0"
# IPv4 # IPv4
IPV4_ADDR="10.0.6.1" IPV4_ADDR="192.168.250.1"
IPV4_NETMASK="255.255.255.0" IPV4_NETMASK="255.255.255.0"
IPV4_NETWORK="10.0.6.1/24" IPV4_NETWORK="192.168.250.1/24"
IPV4_DHCP_RANGE="10.0.6.2,10.0.6.254"
IPV4_DHCP_MAX="252"
IPV4_NAT="true" IPV4_NAT="true"
# IPv6
IPV6_ADDR="fd9d:e4dc:4e00:9e98::1"
IPV6_MASK="64"
IPV6_NETWORK="fd9d:e4dc:4e00:9e98::1/64"
IPV6_NAT="true"
IPV6_PROXY="false"
use_iptables_lock="-w" use_iptables_lock="-w"
iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock="" iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
HAS_IPV6=false
[ -e "/proc/sys/net/ipv6/conf/default/disable_ipv6" ] && \
[ "$(cat /proc/sys/net/ipv6/conf/default/disable_ipv6)" = "0" ] && HAS_IPV6=true
_netmask2cidr () { _netmask2cidr () {
# Assumes there's no "255." after a non-255 byte in the mask # Assumes there's no "255." after a non-255 byte in the mask
local x=${1##*255.} local x=${1##*255.}
@ -88,11 +75,6 @@ start() {
# set up the anbox network # set up the anbox network
[ ! -d "/sys/class/net/${BRIDGE}" ] && ip link add dev "${BRIDGE}" type bridge [ ! -d "/sys/class/net/${BRIDGE}" ] && ip link add dev "${BRIDGE}" type bridge
if [ "${HAS_IPV6}" = "true" ]; then
echo 0 > "/proc/sys/net/ipv6/conf/${BRIDGE}/autoconf" || true
echo 0 > "/proc/sys/net/ipv6/conf/${BRIDGE}/accept_dad" || true
fi
# if we are run from systemd on a system with selinux enabled, # if we are run from systemd on a system with selinux enabled,
# the mkdir will create /run/anbox as init_var_run_t which dnsmasq # the mkdir will create /run/anbox as init_var_run_t which dnsmasq
# can't write its pid into, so we restorecon it (to var_run_t) # can't write its pid into, so we restorecon it (to var_run_t)
@ -103,13 +85,6 @@ start() {
fi fi
fi fi
if [ ! -d "${varlib}" ]; then
mkdir -p "${varlib}"
if which restorecon >/dev/null 2>&1; then
restorecon "${varlib}"
fi
fi
ifup "${BRIDGE}" "${IPV4_ADDR}" "${IPV4_NETMASK}" ifup "${BRIDGE}" "${IPV4_ADDR}" "${IPV4_NETMASK}"
IPV4_ARG="" IPV4_ARG=""
@ -118,25 +93,6 @@ start() {
if [ "${IPV4_NAT}" = "true" ]; then if [ "${IPV4_NAT}" = "true" ]; then
iptables "${use_iptables_lock}" -t nat -A POSTROUTING -s "${IPV4_NETWORK}" ! -d "${IPV4_NETWORK}" -j MASQUERADE -m comment --comment "managed by anbox-bridge" iptables "${use_iptables_lock}" -t nat -A POSTROUTING -s "${IPV4_NETWORK}" ! -d "${IPV4_NETWORK}" -j MASQUERADE -m comment --comment "managed by anbox-bridge"
fi fi
IPV4_ARG="--listen-address ${IPV4_ADDR} --dhcp-range ${IPV4_DHCP_RANGE} --dhcp-lease-max=${IPV4_DHCP_MAX}"
fi
IPV6_ARG=""
if [ "${HAS_IPV6}" = "true" ] && [ -n "${IPV6_ADDR}" ] && [ -n "${IPV6_MASK}" ] && [ -n "${IPV6_NETWORK}" ]; then
# IPv6 sysctls don't respect the "all" path...
for interface in /proc/sys/net/ipv6/conf/*; do
echo 2 > "${interface}/accept_ra"
done
for interface in /proc/sys/net/ipv6/conf/*; do
echo 1 > "${interface}/forwarding"
done
ip -6 addr add dev "${BRIDGE}" "${IPV6_ADDR}/${IPV6_MASK}"
if [ "${IPV6_NAT}" = "true" ]; then
ip6tables "${use_iptables_lock}" -t nat -A POSTROUTING -s "${IPV6_NETWORK}" ! -d "${IPV6_NETWORK}" -j MASQUERADE -m comment --comment "managed by anbox-bridge"
fi
IPV6_ARG="--dhcp-range=${IPV6_ADDR},ra-stateless,ra-names --listen-address ${IPV6_ADDR}"
fi fi
iptables "${use_iptables_lock}" -I INPUT -i "${BRIDGE}" -p udp --dport 67 -j ACCEPT -m comment --comment "managed by anbox-bridge" iptables "${use_iptables_lock}" -I INPUT -i "${BRIDGE}" -p udp --dport 67 -j ACCEPT -m comment --comment "managed by anbox-bridge"
@ -147,35 +103,6 @@ start() {
iptables "${use_iptables_lock}" -I FORWARD -o "${BRIDGE}" -j ACCEPT -m comment --comment "managed by anbox-bridge" iptables "${use_iptables_lock}" -I FORWARD -o "${BRIDGE}" -j ACCEPT -m comment --comment "managed by anbox-bridge"
iptables "${use_iptables_lock}" -t mangle -A POSTROUTING -o "${BRIDGE}" -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill -m comment --comment "managed by anbox-bridge" iptables "${use_iptables_lock}" -t mangle -A POSTROUTING -o "${BRIDGE}" -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill -m comment --comment "managed by anbox-bridge"
DOMAIN_ARG=""
if [ -n "${DOMAIN}" ]; then
DOMAIN_ARG="-s ${DOMAIN} -S /${DOMAIN}/"
fi
CONFILE_ARG=""
if [ -n "${CONFILE}" ]; then
CONFILE_ARG="--conf-file=${CONFILE}"
fi
# https://lists.linuxcontainers.org/pipermail/lxc-devel/2014-October/010561.html
for DNSMASQ_USER in anbox dnsmasq nobody
do
if getent passwd "${DNSMASQ_USER}" >/dev/null; then
break
fi
done
if [ -n "${IPV4_ADDR}" ] || [ -n "${IPV6_ADDR}" ]; then
# shellcheck disable=SC2086
dnsmasq ${CONFILE_ARG} ${DOMAIN_ARG} -u "${DNSMASQ_USER}" --strict-order --bind-interfaces --pid-file="${varrun}/dnsmasq.pid" --dhcp-no-override --except-interface=lo --interface="${BRIDGE}" --dhcp-leasefile="${varlib}/dnsmasq.${BRIDGE}.leases" --dhcp-authoritative ${IPV4_ARG} ${IPV6_ARG} || cleanup
fi
if [ "${HAS_IPV6}" = "true" ] && [ "${IPV6_PROXY}" = "true" ]; then
PATH="${PATH}:$(dirname "${0}")" anbox-bridge-proxy --addr="[fe80::1%${BRIDGE}]:13128" &
PID=$!
echo "${PID}" > "${varrun}/proxy.pid"
fi
touch "${varrun}/network_up" touch "${varrun}/network_up"
FAILED=0 FAILED=0
} }
@ -197,20 +124,6 @@ stop() {
iptables ${use_iptables_lock} -t nat -D POSTROUTING -s ${IPV4_NETWORK} ! -d ${IPV4_NETWORK} -j MASQUERADE -m comment --comment "managed by anbox-bridge" iptables ${use_iptables_lock} -t nat -D POSTROUTING -s ${IPV4_NETWORK} ! -d ${IPV4_NETWORK} -j MASQUERADE -m comment --comment "managed by anbox-bridge"
fi fi
if [ "${HAS_IPV6}" = "true" ] && [ -n "${IPV6_NETWORK}" ] && [ "${IPV6_NAT}" = "true" ]; then
ip6tables ${use_iptables_lock} -t nat -D POSTROUTING -s ${IPV6_NETWORK} ! -d ${IPV6_NETWORK} -j MASQUERADE -m comment --comment "managed by anbox-bridge"
fi
if [ -e "${varrun}/dnsmasq.pid" ]; then
pid=$(cat "${varrun}/dnsmasq.pid" 2>/dev/null) && kill -9 "${pid}"
rm -f "${varrun}/dnsmasq.pid"
fi
if [ -e "${varrun}/proxy.pid" ]; then
pid=$(cat "${varrun}/proxy.pid" 2>/dev/null) && kill -9 "${pid}"
rm -f "${varrun}/proxy.pid"
fi
# if ${BRIDGE} has attached interfaces, don't destroy the bridge # if ${BRIDGE} has attached interfaces, don't destroy the bridge
ls /sys/class/net/${BRIDGE}/brif/* > /dev/null 2>&1 || ip link delete "${BRIDGE}" ls /sys/class/net/${BRIDGE}/brif/* > /dev/null 2>&1 || ip link delete "${BRIDGE}"
fi fi

View file

@ -32,6 +32,7 @@ apt-get install -qq -y \
libproperties-cpp-dev \ libproperties-cpp-dev \
libprotobuf-dev \ libprotobuf-dev \
libsdl2-dev \ libsdl2-dev \
libsdl2-image-dev \
lxc-dev \ lxc-dev \
pkg-config \ pkg-config \
protobuf-compiler protobuf-compiler
@ -40,14 +41,26 @@ apt-get clean
cd /anbox cd /anbox
# In cases where anbox comes directly from a checked out Android cleanup() {
# build environment we miss some symlinks which are present on # In cases where anbox comes directly from a checked out Android
# the host and don't have a valid git repository in that case. # build environment we miss some symlinks which are present on
git clean -fdx . || true # the host and don't have a valid git repository in that case.
git reset --hard || true if [ -d .git ] ; then
git clean -fdx .
git reset --hard
fi
}
cleanup
mkdir build || rm -rf build/* mkdir build || rm -rf build/*
cd build cd build
cmake .. cmake ..
make -j10 make -j10
make test make test
cleanup
apt-get install -y build-essential curl devscripts gdebi-core dkms dh-systemd
apt-get install -y $(gdebi --quiet --apt-line ./debian/control)
debuild -us -uc

View file

@ -37,7 +37,8 @@ start() {
exec $AA_EXEC $SNAP/bin/anbox-wrapper.sh container-manager \ exec $AA_EXEC $SNAP/bin/anbox-wrapper.sh container-manager \
--data-path=$DATA_PATH \ --data-path=$DATA_PATH \
--android-image=$ANDROID_IMG --android-image=$ANDROID_IMG \
--daemon
} }
stop() { stop() {

View file

@ -29,6 +29,12 @@ export LIBGL_DRIVERS_PATH=$SNAP/usr/lib/$ARCH/dri
# ensure the snappy gl libs win # ensure the snappy gl libs win
export LD_LIBRARY_PATH="$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH" export LD_LIBRARY_PATH="$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH"
# Workaround in snapd for proprietary nVidia drivers mounts the drivers in
# /var/lib/snapd/lib/gl that needs to be in LD_LIBRARY_PATH
# Without that OpenGL using apps do not work with the nVidia drivers.
# Ref.: https://bugs.launchpad.net/snappy/+bug/1588192
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/var/lib/snapd/lib/gl
# We set XDG_DATA_HOME to SNAP_USER_COMMON here as this will be the location we will # We set XDG_DATA_HOME to SNAP_USER_COMMON here as this will be the location we will
# create all our application launchers in. The system application launcher will # create all our application launchers in. The system application launcher will
# be configured by our installer to look into this directory for available # be configured by our installer to look into this directory for available

View file

@ -1,5 +1,11 @@
name: anbox name: anbox
version: 1-dev version: 3
version-script: |
if [ "$SNAPCRAFT_GRADE" = "stable" ]; then
echo $SNAPCRAFT_PROJECT_VERSION
else
echo $SNAPCRAFT_PROJECT_VERSION-$(git rev-parse --short HEAD)
fi
summary: Android in a Box summary: Android in a Box
description: | description: |
Runtime for Android applications which runs a full Android system Runtime for Android applications which runs a full Android system
@ -84,6 +90,7 @@ parts:
# FIXME: Anbox currently has some paths with hard coded prefixes. Once # FIXME: Anbox currently has some paths with hard coded prefixes. Once
# that is fixed we can avoid using a prefix here. # that is fixed we can avoid using a prefix here.
- -DCMAKE_INSTALL_PREFIX:PATH=/usr - -DCMAKE_INSTALL_PREFIX:PATH=/usr
- -DANBOX_VERSION=$SNAPCRAFT_PROJECT_VERSION
build-packages: build-packages:
- build-essential - build-essential
- cmake - cmake
@ -111,6 +118,7 @@ parts:
- libprotobuf-dev - libprotobuf-dev
- libproperties-cpp-dev - libproperties-cpp-dev
- libsdl2-dev - libsdl2-dev
- libsdl2-image-dev
- pkg-config - pkg-config
- protobuf-compiler - protobuf-compiler
stage-packages: stage-packages:
@ -123,4 +131,5 @@ parts:
make test make test
prime: prime:
- usr/bin/anbox - usr/bin/anbox
- usr/share/anbox
- usr/lib/*-linux-*/ - usr/lib/*-linux-*/

View file

@ -7,6 +7,8 @@ include_directories(
${DBUS_CPP_INCLUDE_DIRS} ${DBUS_CPP_INCLUDE_DIRS}
${DBUS_INCLUDE_DIRS} ${DBUS_INCLUDE_DIRS}
${SDL2_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}
${SDL2_IMAGE_INCLUDE_DIRS}
${PROPERTIES_CPP_INCLUDE_DIRS}
${LXC_INCLUDE_DIRS} ${LXC_INCLUDE_DIRS}
${MIRCLIENT_INCLUDE_DIRS} ${MIRCLIENT_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
@ -41,6 +43,7 @@ protobuf_generate_cpp(
add_library(anbox-protobuf add_library(anbox-protobuf
STATIC
${GENERATED_PROTOBUF_BRIDGE_SRCS} ${GENERATED_PROTOBUF_BRIDGE_SRCS}
${GENERATED_PROTOBUF_BRIDGE_HDRS} ${GENERATED_PROTOBUF_BRIDGE_HDRS}
${GENERATED_PROTOBUF_RPC_SRCS} ${GENERATED_PROTOBUF_RPC_SRCS}
@ -56,12 +59,15 @@ set(SOURCES
anbox/utils.cpp anbox/utils.cpp
anbox/cli.cpp anbox/cli.cpp
anbox/runtime.cpp anbox/runtime.cpp
anbox/version.cpp
anbox/daemon.cpp anbox/daemon.cpp
anbox/config.cpp anbox/config.cpp
anbox/not_reachable.cpp anbox/not_reachable.cpp
anbox/build/version.cpp
anbox/build/version.h.in
anbox/android/intent.cpp anbox/android/intent.cpp
anbox/android/ip_config_builder.cpp
anbox/common/fd.cpp anbox/common/fd.cpp
anbox/common/fd_sets.h anbox/common/fd_sets.h
@ -75,6 +81,7 @@ set(SOURCES
anbox/common/loop_device.cpp anbox/common/loop_device.cpp
anbox/common/loop_device_allocator.cpp anbox/common/loop_device_allocator.cpp
anbox/common/mount_entry.cpp anbox/common/mount_entry.cpp
anbox/common/binary_writer.cpp
anbox/testing/gtest_utils.h anbox/testing/gtest_utils.h
@ -203,11 +210,13 @@ set(SOURCES
anbox/utils/environment_file.cpp anbox/utils/environment_file.cpp
anbox/ui/splash_screen.cpp
anbox/do_not_copy_or_move.h anbox/do_not_copy_or_move.h
anbox/optional.h anbox/optional.h
anbox/defer_action.h) anbox/defer_action.h)
add_library(anbox-core ${SOURCES}) add_library(anbox-core STATIC ${SOURCES})
target_link_libraries(anbox-core target_link_libraries(anbox-core
${Boost_LDFLAGS} ${Boost_LDFLAGS}
${Boost_LIBRARIES} ${Boost_LIBRARIES}
@ -215,6 +224,8 @@ target_link_libraries(anbox-core
${DBUS_CPP_LIBRARIES} ${DBUS_CPP_LIBRARIES}
${SDL2_LDFLAGS} ${SDL2_LDFLAGS}
${SDL2_LIBRARIES} ${SDL2_LIBRARIES}
${SDL2_IMAGE_LDFLAGS}
${SDL2_IMAGE_LIBRARIES}
${LXC_LDFLAGS} ${LXC_LDFLAGS}
${LXC_LIBRARIES} ${LXC_LIBRARIES}
${MIRCLIENT_LDFLAGS} ${MIRCLIENT_LDFLAGS}

View file

@ -21,17 +21,32 @@
namespace anbox { namespace anbox {
namespace android { namespace android {
bool Intent::valid() const {
// At the moment we only support component+package for intents
// (see android/service/android_api_skeleton.cpp for more details)
return !(component.empty() && package.empty());
}
std::ostream &operator<<(std::ostream &out, const Intent &intent) { std::ostream &operator<<(std::ostream &out, const Intent &intent) {
out << "[" out << "[";
<< "action=" << intent.action << " " if (!intent.action.empty())
<< "uri=" << intent.uri << " " out << " " << "action=" << intent.action << " ";
<< "type=" << intent.type << " " if (!intent.uri.empty())
<< "flags=" << intent.flags << " " out << " " << "uri=" << intent.uri << " ";
<< "package=" << intent.package << " " if (!intent.type.empty())
<< "component=" << intent.component << " " out << " " << "type=" << intent.type << " ";
<< "categories=[ "; if (intent.flags > 0)
for (const auto &category : intent.categories) out << category << " "; out << " " << "flags=" << intent.flags << " ";
out << "]]"; if (!intent.package.empty())
out << " " << "package=" << intent.package << " ";
if (!intent.component.empty())
out << "component=" << intent.component << " ";
if (intent.categories.size() > 0) {
out << "categories=[ ";
for (const auto &category : intent.categories) out << category << " ";
out << "] ";
}
out << "]";
return out; return out;
} }
} // namespace android } // namespace android

View file

@ -31,6 +31,8 @@ struct Intent {
std::string package; std::string package;
std::string component; std::string component;
std::vector<std::string> categories; std::vector<std::string> categories;
bool valid() const;
}; };
std::ostream &operator<<(std::ostream &out, const Intent &intent); std::ostream &operator<<(std::ostream &out, const Intent &intent);

View file

@ -0,0 +1,114 @@
/*
* Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/android/ip_config_builder.h"
#include <boost/endian/buffers.hpp>
#include <ostream>
#include <sstream>
namespace {
constexpr const char *assignment_key{"ipAssignment"};
constexpr const char *link_address_key{"linkAddress"};
constexpr const char *gateway_key{"gateway"};
constexpr const char *dns_key{"dns"};
constexpr const char *id_key{"id"};
constexpr const char *eos_key{"eos"};
constexpr const char *assignment_static{"STATIC"};
constexpr const char *assignment_dhcp{"DHCP"};
constexpr const char *assignment_unknown{"UNKNOWN"};
constexpr const std::uint32_t is_default_gateway{0};
constexpr const std::uint32_t gateway_is_present{1};
namespace aa = anbox::android;
std::string assignment_to_string(const aa::IpConfigBuilder::Assignment &value) {
switch (value) {
case anbox::android::IpConfigBuilder::Assignment::Static:
return assignment_static;
break;
case anbox::android::IpConfigBuilder::Assignment::DHCP:
return assignment_dhcp;
break;
default:
break;
}
return assignment_unknown;
}
}
namespace anbox {
namespace android {
std::size_t IpConfigBuilder::write(common::BinaryWriter &writer) {
writer.set_byte_order(common::BinaryWriter::Order::Big);
// See http://androidxref.com/7.1.1_r6/xref/frameworks/base/services/core/java/com/android/server/net/IpConfigStore.java
// for more details on the binary file format used here.
writer.write_uint32(static_cast<std::uint32_t>(version_));
writer.write_string_with_size(assignment_key);
writer.write_string_with_size(assignment_to_string(assignment_));
writer.write_string_with_size(link_address_key);
writer.write_string_with_size(link_.address);
writer.write_uint32(link_.prefix_length);
writer.write_string_with_size(gateway_key);
writer.write_uint32(is_default_gateway);
writer.write_uint32(gateway_is_present);
writer.write_string_with_size(gateway_);
writer.write_string_with_size(dns_key);
for (const auto &server : dns_servers_)
writer.write_string_with_size(server);
writer.write_string_with_size(id_key);
writer.write_uint32(id_);
writer.write_string_with_size(eos_key);
return writer.bytes_written();
}
void IpConfigBuilder::set_version(const Version &version) {
version_ = version;
}
void IpConfigBuilder::set_assignment(const Assignment &assignment) {
assignment_ = assignment;
}
void IpConfigBuilder::set_link_address(const std::string &address, uint32_t prefix_length) {
link_.address = address;
link_.prefix_length = prefix_length;
}
void IpConfigBuilder::set_gateway(const std::string &gateway) {
gateway_ = gateway;
}
void IpConfigBuilder::set_dns_servers(const std::vector<std::string> &dns_servers) {
dns_servers_ = dns_servers;
}
void IpConfigBuilder::set_id(uint32_t id) {
id_ = id;
}
} // namespace android
} // namespace anbox

View file

@ -0,0 +1,66 @@
/*
* Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_ANDROID_IPCONFIGBUILDER_H_
#define ANBOX_ANDROID_IPCONFIGBUILDER_H_
#include "anbox/common/binary_writer.h"
#include <string>
#include <vector>
#include <cstdint>
namespace anbox {
namespace android {
class IpConfigBuilder {
public:
enum class Version : std::uint32_t {
Version1 = 1,
Version2 = 2,
};
enum class Assignment {
Static,
DHCP,
};
IpConfigBuilder() = default;
std::size_t write(common::BinaryWriter &writer);
void set_version(const Version &version);
void set_assignment(const Assignment &assignment);
void set_link_address(const std::string &address, std::uint32_t prefix_length);
void set_gateway(const std::string &gateway);
void set_dns_servers(const std::vector<std::string> &dns_servers);
void set_id(std::uint32_t id);
private:
Version version_;
Assignment assignment_;
struct {
std::string address;
std::uint32_t prefix_length;
} link_;
std::string gateway_;
std::vector<std::string> dns_servers_;
std::uint32_t id_;
};
} // namespace android
} // namespace anbox
#endif

View file

@ -18,6 +18,7 @@
#ifndef ANBOX_BRIDGE_PLATFORM_SERVER_H_ #ifndef ANBOX_BRIDGE_PLATFORM_SERVER_H_
#define ANBOX_BRIDGE_PLATFORM_SERVER_H_ #define ANBOX_BRIDGE_PLATFORM_SERVER_H_
#include <functional>
#include <memory> #include <memory>
namespace google { namespace google {

View file

@ -0,0 +1,39 @@
/*
* Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/build/version.h"
#include "anbox/utils.h"
#include <cstring>
namespace anbox {
namespace build {
static std::string init_version_string() {
std::string v;
if (!version_suffix || std::strlen(version_suffix) == 0)
v = utils::string_format("%s", version);
else
v = utils::string_format("%s-%s", version, version_suffix);
return v;
}
std::string print_version() {
static const std::string v{init_version_string()};
return v;
}
} // namespace build
} // namespace anbox

View file

@ -17,11 +17,22 @@
* *
*/ */
#include "anbox/version.h" #ifndef ANBOX_VERSION_H_
#define ANBOX_VERSION_H_
void anbox::version(std::uint32_t& major, std::uint32_t& minor, #include <cstdint>
std::uint32_t& patch) { #include <string>
major = anbox::build::version_major;
minor = anbox::build::version_minor; namespace anbox {
patch = anbox::build::version_patch; namespace build {
} /// @brief version marks the version
static constexpr const char *version{"@ANBOX_VERSION@"};
/// @brief version_suffix is an additional suffix which can be amended to
/// the major version number to indicate a dev build for example.
static constexpr const char *version_suffix{"@ANBOX_VERSION_SUFFIX@"};
/// @brief version queries the version of Anbox
std::string print_version();
} // namespace build
} // namespace anbox
#endif // ANBOX_VERSION_H_

View file

@ -48,11 +48,22 @@ anbox::cmds::ContainerManager::ContainerManager()
flag(cli::make_flag(cli::Name{"privileged"}, flag(cli::make_flag(cli::Name{"privileged"},
cli::Description{"Run Android container in privileged mode"}, cli::Description{"Run Android container in privileged mode"},
privileged_)); privileged_));
flag(cli::make_flag(cli::Name{"daemon"},
cli::Description{"Mark service as being started as systemd daemon"},
daemon_));
action([&](const cli::Command::Context&) { action([&](const cli::Command::Context&) {
try { try {
if (getuid() != 0) { if (!daemon_) {
ERROR("You're not running the container-manager as root. Generally you don't"); WARNING("You are running the container manager manually which is most likely not");
WARNING("what you want. The container manager is normally started by systemd or");
WARNING("another init system. If you still want to run the container-manager");
WARNING("you can get rid of this warning by starting with the --daemon option.");
WARNING("");
}
if (geteuid() != 0) {
ERROR("You are not running the container-manager as root. Generally you don't");
ERROR("want to run the container-manager manually unless you're a developer"); ERROR("want to run the container-manager manually unless you're a developer");
ERROR("as it is started by the init system of your operating system."); ERROR("as it is started by the init system of your operating system.");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -68,6 +79,9 @@ anbox::cmds::ContainerManager::ContainerManager()
if (!data_path_.empty()) if (!data_path_.empty())
SystemConfiguration::instance().set_data_path(data_path_); SystemConfiguration::instance().set_data_path(data_path_);
if (!fs::exists(data_path_))
fs::create_directories(data_path_);
if (!setup_mounts()) if (!setup_mounts())
return EXIT_FAILURE; return EXIT_FAILURE;

View file

@ -42,6 +42,7 @@ class ContainerManager : public cli::CommandWithFlagsAndAction {
std::shared_ptr<common::LoopDevice> android_img_loop_dev_; std::shared_ptr<common::LoopDevice> android_img_loop_dev_;
std::vector<std::shared_ptr<common::MountEntry>> mounts_; std::vector<std::shared_ptr<common::MountEntry>> mounts_;
bool privileged_ = false; bool privileged_ = false;
bool daemon_ = false;
}; };
} // namespace cmds } // namespace cmds
} // namespace anbox } // namespace anbox

View file

@ -19,6 +19,8 @@
#include "anbox/common/wait_handle.h" #include "anbox/common/wait_handle.h"
#include "anbox/dbus/stub/application_manager.h" #include "anbox/dbus/stub/application_manager.h"
#include "anbox/common/dispatcher.h" #include "anbox/common/dispatcher.h"
#include "anbox/ui/splash_screen.h"
#include "anbox/config.h"
#include "anbox/runtime.h" #include "anbox/runtime.h"
#include "anbox/logger.h" #include "anbox/logger.h"
@ -26,12 +28,31 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "core/posix/exec.h"
#include "core/posix/fork.h"
#include "core/posix/signal.h" #include "core/posix/signal.h"
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
namespace { namespace {
const boost::posix_time::seconds max_wait_timeout{30}; const boost::posix_time::seconds max_wait_timeout{240};
const int max_restart_attempts{3};
const std::chrono::seconds restart_interval{5};
}
bool anbox::cmds::Launch::try_launch_activity(const std::shared_ptr<dbus::stub::ApplicationManager> &stub) {
try {
DEBUG("Sending launch intent %s to Android ..", intent_);
stub->launch(intent_, graphics::Rect::Invalid, stack_);
} catch (const std::exception &err) {
ERROR("Failed to launch activity: %s", err.what());
return false;
} catch (...) {
ERROR("Failed to launch activity");
return false;
}
return true;
} }
anbox::cmds::Launch::Launch() anbox::cmds::Launch::Launch()
@ -58,6 +79,11 @@ anbox::cmds::Launch::Launch()
stack_)); stack_));
action([this](const cli::Command::Context&) { action([this](const cli::Command::Context&) {
if (!intent_.valid()) {
ERROR("The intent you provided is invalid. Please provide a correct launch intent.");
return EXIT_FAILURE;
}
auto trap = core::posix::trap_signals_for_process({core::posix::Signal::sig_term, core::posix::Signal::sig_int}); auto trap = core::posix::trap_signals_for_process({core::posix::Signal::sig_term, core::posix::Signal::sig_int});
trap->signal_raised().connect([trap](const core::posix::Signal& signal) { trap->signal_raised().connect([trap](const core::posix::Signal& signal) {
INFO("Signal %i received. Good night.", static_cast<int>(signal)); INFO("Signal %i received. Good night.", static_cast<int>(signal));
@ -69,42 +95,95 @@ anbox::cmds::Launch::Launch()
auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session); auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service())); bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
const auto snap_path = utils::get_env_value("SNAP");
if (!snap_path.empty()) {
const auto resource_path = fs::path(snap_path) / "usr" / "share" / "anbox";
SystemConfiguration::instance().set_resource_path(resource_path);
}
std::shared_ptr<ui::SplashScreen> ss;
// Instead of relying on the user session init system to start our
// session manager process we also attempt to start it on our own
// if not already running. This will help to mitigate problems with
// a crashing or a not yet started session manager instance.
std::shared_ptr<dbus::stub::ApplicationManager> stub; std::shared_ptr<dbus::stub::ApplicationManager> stub;
try { for (auto n = 0; n < max_restart_attempts; n++) {
stub = dbus::stub::ApplicationManager::create_for_bus(bus); try {
} catch (...) { stub = dbus::stub::ApplicationManager::create_for_bus(bus);
ERROR("Anbox session manager service isn't running!"); break;
} catch (std::exception &err) {
WARNING("Anbox session manager service isn't running, trying to start it.");
// Give us a splash screen as long as we're trying to connect
// with the session manager so the user knows something is
// happening after he started Anbox.
if (!ss)
ss = std::make_shared<ui::SplashScreen>();
std::vector<std::string> args = {"session-manager"};
std::map<std::string,std::string> env;
core::posix::this_process::env::for_each([&](const std::string &name, const std::string &value) {
env.insert({name, value});
});
const auto exe_path = utils::process_get_exe_path(::getpid());
if (!fs::exists(exe_path)) {
ERROR("Can't find correct anbox executable to run. Found %s but does not exist", exe_path);
return EXIT_FAILURE;
}
try {
auto flags = core::posix::StandardStream::stdout | core::posix::StandardStream::stderr;
// If we have logging enable in debug mode then we allow the child process
// to print to stdout/stderr too.
if (Log().GetSeverity() == Logger::Severity::kDebug)
flags = core::posix::StandardStream::empty;
auto child = core::posix::fork([&]() {
auto grandchild = core::posix::exec(exe_path, args, env, flags);
grandchild.dont_kill_on_cleanup();
return core::posix::exit::Status::success;
}, flags);
// We don't wait for the grandchild but the child as we use double forking
// here to break through the process hierarchy and make the grandchild a
// direct child of the init process so it keeps running on its own and
// indepent of our short living process here.
child.wait_for(core::posix::wait::Flags::untraced);
DEBUG("Started session manager, will now try to connect ..");
}
catch (...) {
ERROR("Failed to start session manager instance");
}
std::this_thread::sleep_for(restart_interval);
}
}
if (!stub) {
ERROR("Couldn't get a connection with the session manager");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
bool success = false; bool success = false;
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
dispatcher->dispatch([&]() { dispatcher->dispatch([&]() {
if (stub->ready()) { if (stub->ready()) {
try { ss.reset();
stub->launch(intent_, graphics::Rect::Invalid, stack_); success = try_launch_activity(stub);
success = true;
} catch (std::exception &err) {
ERROR("err %s", err.what());
}
trap->stop(); trap->stop();
return; return;
} }
DEBUG("Android hasn't fully booted yet. Waiting a bit.."); DEBUG("Android hasn't fully booted yet. Waiting a bit ..");
stub->ready().changed().connect([&](bool ready) { stub->ready().changed().connect([&](bool ready) {
if (!ready) if (!ready)
return; return;
try { ss.reset();
stub->launch(intent_, graphics::Rect::Invalid, stack_); success = try_launch_activity(stub);
success = true;
} catch (std::exception &err) {
ERROR("Failed to launch activity: %s", err.what());
success = false;
}
trap->stop(); trap->stop();
}); });
}); });
@ -112,8 +191,10 @@ anbox::cmds::Launch::Launch()
boost::asio::deadline_timer timer(rt->service()); boost::asio::deadline_timer timer(rt->service());
timer.expires_from_now(max_wait_timeout); timer.expires_from_now(max_wait_timeout);
timer.async_wait([&](const boost::system::error_code&) { timer.async_wait([&](const boost::system::error_code&) {
WARNING("Stop waiting as we're already waiting for too long. Something is wrong"); WARNING("Stopped waiting as we've already waited for too long. Something");
WARNING("with your setup and the container may have failed to boot."); WARNING("is wrong with your setup or the container has failed to boot.");
WARNING("If you think you found a bug please don't hesitate to file on");
WARNING("at https://github.com/anbox/anbox/issues/new");
trap->stop(); trap->stop();
}); });

View file

@ -23,6 +23,7 @@
#include <memory> #include <memory>
#include "anbox/android/intent.h" #include "anbox/android/intent.h"
#include "anbox/dbus/stub/application_manager.h"
#include "anbox/wm/stack.h" #include "anbox/wm/stack.h"
#include "anbox/cli.h" #include "anbox/cli.h"
@ -33,6 +34,8 @@ class Launch : public cli::CommandWithFlagsAndAction {
Launch(); Launch();
private: private:
bool try_launch_activity(const std::shared_ptr<dbus::stub::ApplicationManager> &stub);
android::Intent intent_; android::Intent intent_;
wm::Stack::Id stack_; wm::Stack::Id stack_;
}; };

View file

@ -27,12 +27,17 @@
#include "anbox/bridge/android_api_stub.h" #include "anbox/bridge/android_api_stub.h"
#include "anbox/bridge/platform_api_skeleton.h" #include "anbox/bridge/platform_api_skeleton.h"
#include "anbox/bridge/platform_message_processor.h" #include "anbox/bridge/platform_message_processor.h"
#include "anbox/graphics/gl_renderer_server.h"
namespace {
std::istream& operator>>(std::istream& in, anbox::graphics::GLRendererServer::Config::Driver& driver);
}
#include "anbox/cmds/session_manager.h" #include "anbox/cmds/session_manager.h"
#include "anbox/common/dispatcher.h" #include "anbox/common/dispatcher.h"
#include "anbox/config.h" #include "anbox/config.h"
#include "anbox/container/client.h" #include "anbox/container/client.h"
#include "anbox/dbus/skeleton/service.h" #include "anbox/dbus/skeleton/service.h"
#include "anbox/graphics/gl_renderer_server.h"
#include "anbox/input/manager.h" #include "anbox/input/manager.h"
#include "anbox/logger.h" #include "anbox/logger.h"
#include "anbox/network/published_socket_connector.h" #include "anbox/network/published_socket_connector.h"
@ -106,6 +111,12 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
flag(cli::make_flag(cli::Name{"window-size"}, flag(cli::make_flag(cli::Name{"window-size"},
cli::Description{"Size of the window in single window mode, e.g. --window-size=1024,768"}, cli::Description{"Size of the window in single window mode, e.g. --window-size=1024,768"},
window_size_)); window_size_));
flag(cli::make_flag(cli::Name{"standalone"},
cli::Description{"Prevents the Container Manager from starting the default container (Experimental)"},
standalone_));
flag(cli::make_flag(cli::Name{"experimental"},
cli::Description{"Allows users to use experimental features"},
experimental_));
action([this](const cli::Command::Context &) { action([this](const cli::Command::Context &) {
auto trap = core::posix::trap_signals_for_process( auto trap = core::posix::trap_signals_for_process(
@ -115,6 +126,11 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
trap->stop(); trap->stop();
}); });
if (standalone_ && !experimental_) {
ERROR("Experimental features selected, but --experimental flag not set");
return EXIT_FAILURE;
}
if (!fs::exists("/dev/binder") || !fs::exists("/dev/ashmem")) { if (!fs::exists("/dev/binder") || !fs::exists("/dev/ashmem")) {
ERROR("Failed to start as either binder or ashmem kernel drivers are not loaded"); ERROR("Failed to start as either binder or ashmem kernel drivers are not loaded");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -135,11 +151,13 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
auto rt = Runtime::create(); auto rt = Runtime::create();
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt); auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
container::Client container(rt); if (!standalone_) {
container.register_terminate_handler([&]() { container_ = std::make_shared<container::Client>(rt);
WARNING("Lost connection to container manager, terminating."); container_->register_terminate_handler([&]() {
trap->stop(); WARNING("Lost connection to container manager, terminating.");
}); trap->stop();
});
}
auto input_manager = std::make_shared<input::Manager>(rt); auto input_manager = std::make_shared<input::Manager>(rt);
@ -159,8 +177,6 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
display_frame = window_size_; display_frame = window_size_;
auto policy = std::make_shared<ubuntu::PlatformPolicy>(input_manager, display_frame, single_window_); auto policy = std::make_shared<ubuntu::PlatformPolicy>(input_manager, display_frame, single_window_);
// FIXME this needs to be removed and solved differently behind the scenes
registerDisplayManager(policy);
auto app_db = std::make_shared<application::Database>(); auto app_db = std::make_shared<application::Database>();
@ -213,7 +229,8 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
})); }));
container::Configuration container_configuration; container::Configuration container_configuration;
container_configuration.bind_mounts = { if (!standalone_) {
container_configuration.bind_mounts = {
{qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"}, {qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"},
{bridge_connector->socket_file(), "/dev/anbox_bridge"}, {bridge_connector->socket_file(), "/dev/anbox_bridge"},
{audio_server->socket_file(), "/dev/anbox_audio"}, {audio_server->socket_file(), "/dev/anbox_audio"},
@ -221,9 +238,10 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
{"/dev/binder", "/dev/binder"}, {"/dev/binder", "/dev/binder"},
{"/dev/ashmem", "/dev/ashmem"}, {"/dev/ashmem", "/dev/ashmem"},
{"/dev/fuse", "/dev/fuse"}, {"/dev/fuse", "/dev/fuse"},
}; };
dispatcher->dispatch([&]() { container.start(container_configuration); }); dispatcher->dispatch([&]() { container_->start(container_configuration); });
}
auto bus = bus_factory_(); auto bus = bus_factory_();
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service())); bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
@ -233,9 +251,11 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
rt->start(); rt->start();
trap->run(); trap->run();
// Stop the container which should close all open connections we have on if (!standalone_) {
// our side and should terminate all services. // Stop the container which should close all open connections we have on
container.stop(); // our side and should terminate all services.
container_->stop();
}
rt->stop(); rt->stop();

View file

@ -30,6 +30,9 @@
#include "anbox/graphics/rect.h" #include "anbox/graphics/rect.h"
namespace anbox { namespace anbox {
namespace container {
class Client;
} // namespace container
namespace cmds { namespace cmds {
class SessionManager : public cli::CommandWithFlagsAndAction { class SessionManager : public cli::CommandWithFlagsAndAction {
public: public:
@ -40,11 +43,14 @@ class SessionManager : public cli::CommandWithFlagsAndAction {
SessionManager(const BusFactory& bus_factory = session_bus_factory()); SessionManager(const BusFactory& bus_factory = session_bus_factory());
private: private:
std::shared_ptr<container::Client> container_;
BusFactory bus_factory_; BusFactory bus_factory_;
std::string desktop_file_hint_; std::string desktop_file_hint_;
graphics::GLRendererServer::Config::Driver gles_driver_; graphics::GLRendererServer::Config::Driver gles_driver_;
bool single_window_ = false; bool single_window_ = false;
graphics::Rect window_size_; graphics::Rect window_size_;
bool standalone_ = false;
bool experimental_ = false;
}; };
} // namespace cmds } // namespace cmds
} // namespace anbox } // namespace anbox

View file

@ -19,9 +19,9 @@
#include "anbox/graphics/emugl/RenderApi.h" #include "anbox/graphics/emugl/RenderApi.h"
#include "anbox/graphics/emugl/DispatchTables.h" #include "anbox/graphics/emugl/DispatchTables.h"
#include "anbox/utils/environment_file.h" #include "anbox/utils/environment_file.h"
#include "anbox/version.h"
#include "anbox/logger.h" #include "anbox/logger.h"
#include "anbox/version.h"
#include "anbox/build/version.h"
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
@ -34,9 +34,12 @@ namespace fs = boost::filesystem;
namespace { namespace {
constexpr const char *os_release_path{"/etc/os-release"}; constexpr const char *os_release_path{"/etc/os-release"};
constexpr const char *host_os_release_path{"/var/lib/snapd/hostfs/etc/os-release"};
constexpr const char *proc_version_path{"/proc/version"}; constexpr const char *proc_version_path{"/proc/version"};
constexpr const char *binder_path{"/dev/binder"}; constexpr const char *binder_path{"/dev/binder"};
constexpr const char *ashmem_path{"/dev/ashmem"}; constexpr const char *ashmem_path{"/dev/ashmem"};
constexpr const char *os_release_name{"NAME"};
constexpr const char *os_release_version{"VERSION"};
class SystemInformation { class SystemInformation {
public: public:
@ -50,12 +53,15 @@ class SystemInformation {
std::stringstream s; std::stringstream s;
s << "version: " s << "version: "
<< anbox::utils::string_format("%d.%d.%d", << anbox::build::print_version()
anbox::build::version_major,
anbox::build::version_minor,
anbox::build::version_patch)
<< std::endl; << std::endl;
if (anbox::utils::is_env_set("SNAP_REVISION")) {
s << "snap-revision: "
<< anbox::utils::get_env_value("SNAP_REVISION")
<< std::endl;
}
s << "os:" << std::endl s << "os:" << std::endl
<< " name: " << os_info_.name << std::endl << " name: " << os_info_.name << std::endl
<< " version: " << os_info_.version << std::endl << " version: " << os_info_.version << std::endl
@ -96,15 +102,19 @@ class SystemInformation {
private: private:
void collect_os_info() { void collect_os_info() {
os_info_.snap_based = (getenv("SNAP") != nullptr); os_info_.snap_based = !anbox::utils::get_env_value("SNAP").empty();
if (fs::exists(os_release_path)) { fs::path path = os_release_path;
anbox::utils::EnvironmentFile os_release(os_release_path); // If we're running from within a snap the best we can do is to
os_info_.name = os_release.value("NAME"); // access the hostfs and read the os-release file from there.
os_info_.version = os_release.value("VERSION"); if (os_info_.snap_based && fs::exists(host_os_release_path))
} else if (os_info_.snap_based) { path = host_os_release_path;
// As we can't read /etc/os-release and we're snap-based this is the best we can guess
os_info_.name = "Ubuntu"; // Double check that there aren't any permission errors when trying
os_info_.version = "16"; // to access the file (e.g. because of snap confinement)
if (fs::exists(path)) {
anbox::utils::EnvironmentFile os_release(path);
os_info_.name = os_release.value(os_release_name);
os_info_.version = os_release.value(os_release_version);
} }
} }

View file

@ -18,16 +18,15 @@
*/ */
#include "anbox/cmds/version.h" #include "anbox/cmds/version.h"
#include "anbox/version.h" #include "anbox/build/version.h"
#include "anbox/utils.h"
anbox::cmds::Version::Version() anbox::cmds::Version::Version()
: CommandWithFlagsAndAction{ : CommandWithFlagsAndAction{
cli::Name{"version"}, cli::Usage{"version"}, cli::Name{"version"}, cli::Usage{"version"},
cli::Description{"print the version of the daemon"}} { cli::Description{"print the version of the daemon"}} {
action([](const cli::Command::Context& ctxt) { action([](const cli::Command::Context& ctxt) {
std::uint32_t major, minor, patch; ctxt.cout << "anbox " << build::print_version() << std::endl;
anbox::version(major, minor, patch);
ctxt.cout << "anbox " << major << "." << minor << "." << patch << std::endl;
return 0; return 0;
}); });
} }

View file

@ -0,0 +1,106 @@
/*
* Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
* 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/common/binary_writer.h"
#include <cstring>
#include <stdexcept>
#include <boost/endian/buffers.hpp>
namespace {
bool is_little_endian() {
static const std::uint32_t v = 1;
return (*reinterpret_cast<const std::uint8_t*>(&v) == 1);
}
}
namespace anbox {
namespace common {
BinaryWriter::BinaryWriter(std::vector<std::uint8_t>::iterator begin,
std::vector<std::uint8_t>::iterator end) :
begin_{begin}, current_{begin}, end_{end},
byte_order_{is_little_endian() ? Order::Little : Order::Big} {}
void BinaryWriter::set_byte_order(Order order) {
byte_order_ = order;
}
void BinaryWriter::write_uint16(std::uint16_t value) {
if (current_ + sizeof(value) > end_)
throw std::out_of_range{"Write buffer exhausted"};
std::uint16_t v = value;
switch (byte_order_) {
case Order::Big:
v = boost::endian::native_to_big(value);
break;
case Order::Little:
v = boost::endian::native_to_little(value);
break;
default:
break;
}
*reinterpret_cast<std::uint16_t*>(&(*current_)) = v;
current_ += sizeof(v);
}
void BinaryWriter::write_uint32(std::uint32_t value) {
if (current_ + sizeof(value) > end_)
throw std::out_of_range{"Write buffer exhausted"};
std::uint32_t v = value;
switch (byte_order_) {
case Order::Big:
v = boost::endian::native_to_big(value);
break;
case Order::Little:
v = boost::endian::native_to_little(value);
break;
default:
break;
}
*reinterpret_cast<std::uint32_t*>(&(*current_)) = v;
current_ += sizeof(v);
}
void BinaryWriter::write_string(const char *s, std::size_t size) {
if (current_ + size > end_)
throw std::out_of_range{"Write buffer exhausted"};
memcpy(&(*current_), s, size);
current_ += size;
}
void BinaryWriter::write_string_with_size(const std::string &str) {
write_string_with_size(str.c_str(), str.length());
}
void BinaryWriter::write_string_with_size(const char *s, std::size_t size) {
write_uint16(size);
write_string(s, size);
}
std::size_t BinaryWriter::bytes_written() const {
return current_ - begin_;
}
} // namespace common
} // namespace anbox

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2016 Thomas Voss <thomas.voss.bochum@gmail.com>
* 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_COMMON_BINARY_WRITER_H_
#define ANBOX_COMMON_BINARY_WRITER_H_
#include <cstdint>
#include <vector>
#include <string>
namespace anbox {
namespace common {
class BinaryWriter {
public:
enum class Order {
Big,
Little,
};
explicit BinaryWriter(std::vector<std::uint8_t>::iterator begin_,
std::vector<std::uint8_t>::iterator end_);
void set_byte_order(Order order);
void write_uint16(std::uint16_t value);
void write_uint32(std::uint32_t value);
void write_string(const char *s, std::size_t size);
void write_string_with_size(const std::string &str);
void write_string_with_size(const char *s, std::size_t size);
std::size_t bytes_written() const;
private:
std::vector<std::uint8_t>::iterator begin_;
std::vector<std::uint8_t>::iterator current_;
std::vector<std::uint8_t>::iterator end_;
Order byte_order_;
};
} // namespace common
} // namespace anbox
#endif

View file

@ -41,6 +41,10 @@ void anbox::SystemConfiguration::set_data_path(const std::string &path) {
data_path = path; data_path = path;
} }
void anbox::SystemConfiguration::set_resource_path(const fs::path &path) {
resource_path = path;
}
fs::path anbox::SystemConfiguration::data_dir() const { fs::path anbox::SystemConfiguration::data_dir() const {
return data_path; return data_path;
} }
@ -76,6 +80,10 @@ std::string anbox::SystemConfiguration::application_item_dir() const {
return dir.string(); return dir.string();
} }
std::string anbox::SystemConfiguration::resource_dir() const {
return resource_path.string();
}
anbox::SystemConfiguration& anbox::SystemConfiguration::instance() { anbox::SystemConfiguration& anbox::SystemConfiguration::instance() {
static SystemConfiguration config; static SystemConfiguration config;
return config; return config;

View file

@ -31,6 +31,7 @@ class SystemConfiguration {
virtual ~SystemConfiguration() = default; virtual ~SystemConfiguration() = default;
void set_data_path(const std::string &path); void set_data_path(const std::string &path);
void set_resource_path(const boost::filesystem::path &path);
boost::filesystem::path data_dir() const; boost::filesystem::path data_dir() const;
std::string rootfs_dir() const; std::string rootfs_dir() const;
@ -40,11 +41,13 @@ class SystemConfiguration {
std::string container_socket_path() const; std::string container_socket_path() const;
std::string input_device_dir() const; std::string input_device_dir() const;
std::string application_item_dir() const; std::string application_item_dir() const;
std::string resource_dir() const;
protected: protected:
SystemConfiguration() = default; SystemConfiguration() = default;
boost::filesystem::path data_path = "/var/lib/anbox"; boost::filesystem::path data_path = "/var/lib/anbox";
boost::filesystem::path resource_path = "/usr/share/anbox";
}; };
} // namespace anbox } // namespace anbox

View file

@ -15,6 +15,7 @@
* *
*/ */
#include "anbox/android/ip_config_builder.h"
#include "anbox/container/lxc_container.h" #include "anbox/container/lxc_container.h"
#include "anbox/config.h" #include "anbox/config.h"
#include "anbox/logger.h" #include "anbox/logger.h"
@ -22,6 +23,7 @@
#include <map> #include <map>
#include <stdexcept> #include <stdexcept>
#include <fstream>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
@ -30,9 +32,20 @@
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
namespace {
constexpr unsigned int unprivileged_user_id{100000};
constexpr const char *default_container_ip_address{"192.168.250.2"};
constexpr const std::uint32_t default_container_ip_prefix_length{24};
constexpr const char *default_host_ip_address{"192.168.250.1"};
constexpr const char *default_dns_server{"8.8.8.8"};
}
namespace anbox { namespace anbox {
namespace container { namespace container {
LxcContainer::LxcContainer(bool privileged, const network::Credentials &creds) LxcContainer::LxcContainer(bool privileged, const network::Credentials &creds)
@ -49,8 +62,7 @@ LxcContainer::~LxcContainer() {
} }
void LxcContainer::setup_id_maps() { void LxcContainer::setup_id_maps() {
// FIXME make these id sets configurable const auto base_id = unprivileged_user_id;
const auto base_id = 100000;
const auto max_id = 65536; const auto max_id = 65536;
set_config_item("lxc.id_map", set_config_item("lxc.id_map",
@ -76,6 +88,75 @@ void LxcContainer::setup_id_maps() {
max_id - creds_.gid() - 1)); max_id - creds_.gid() - 1));
} }
void LxcContainer::setup_network() {
if (!fs::exists("/sys/class/net/anbox0")) {
WARNING("Anbox bridge interface 'anbox0' doesn't exist. Network functionality will not be available");
return;
}
set_config_item("lxc.network.type", "veth");
set_config_item("lxc.network.flags", "up");
set_config_item("lxc.network.link", "anbox0");
// Instead of relying on DHCP we will give Android a static IP configuration
// for the virtual ethernet interface LXC creates for us. This will be bridged
// to the host and will allows us to have reliable network connectivity and
// not depend on any other system service.
android::IpConfigBuilder ip_conf;
ip_conf.set_version(android::IpConfigBuilder::Version::Version2);
ip_conf.set_assignment(android::IpConfigBuilder::Assignment::Static);
ip_conf.set_link_address(default_container_ip_address, default_container_ip_prefix_length);
ip_conf.set_gateway(default_host_ip_address);
ip_conf.set_dns_servers({default_dns_server});
ip_conf.set_id(0);
std::vector<std::uint8_t> buffer(512);
common::BinaryWriter writer(buffer.begin(), buffer.end());
const auto size = ip_conf.write(writer);
const auto data_ethernet_path = fs::path("data") / "misc" / "ethernet";
const auto ip_conf_dir = SystemConfiguration::instance().data_dir() / data_ethernet_path;
if (!fs::exists(ip_conf_dir))
fs::create_directories(ip_conf_dir);
// We have to walk through the created directory hierachy now and
// ensure the permissions are set correctly. Otherwise the Android
// system will fail to boot as it isn't allowed to write anything
// into these directories. As previous versions of Anbox which were
// published to our users did this incorrectly we need to check on
// every startup if those directories are still owned by root and
// if they are we move them over to the unprivileged user.
auto path = SystemConfiguration::instance().data_dir();
for (auto iter = data_ethernet_path.begin(); iter != data_ethernet_path.end(); iter++) {
path /= *iter;
struct stat st;
if (stat(path.c_str(), &st) < 0) {
WARNING("Cannot retrieve permissions of path %s", path);
continue;
}
if (st.st_uid != 0 && st.st_gid != 0)
continue;
if (::chown(path.c_str(), unprivileged_user_id, unprivileged_user_id) < 0)
WARNING("Failed to set owner for path '%s'", path);
}
const auto ip_conf_path = ip_conf_dir / "ipconfig.txt";
if (fs::exists(ip_conf_path))
fs::remove(ip_conf_path);
std::ofstream f(ip_conf_path.string(), std::ofstream::binary);
if (f.is_open()) {
f.write(reinterpret_cast<const char*>(buffer.data()), size);
f.close();
} else {
ERROR("Failed to write IP configuration. Network functionality will not be available.");
}
}
void LxcContainer::start(const Configuration &configuration) { void LxcContainer::start(const Configuration &configuration) {
if (getuid() != 0) if (getuid() != 0)
BOOST_THROW_EXCEPTION(std::runtime_error("You have to start the container as root")); BOOST_THROW_EXCEPTION(std::runtime_error("You have to start the container as root"));
@ -131,11 +212,7 @@ void LxcContainer::start(const Configuration &configuration) {
const auto log_path = SystemConfiguration::instance().log_dir(); const auto log_path = SystemConfiguration::instance().log_dir();
set_config_item("lxc.logfile", utils::string_format("%s/container.log", log_path).c_str()); set_config_item("lxc.logfile", utils::string_format("%s/container.log", log_path).c_str());
if (fs::exists("/sys/class/net/anboxbr0")) { setup_network();
set_config_item("lxc.network.type", "veth");
set_config_item("lxc.network.flags", "up");
set_config_item("lxc.network.link", "anboxbr0");
}
#if 0 #if 0
// Android uses namespaces as well so we have to allow nested namespaces for LXC // Android uses namespaces as well so we have to allow nested namespaces for LXC

View file

@ -39,6 +39,7 @@ class LxcContainer : public Container {
private: private:
void set_config_item(const std::string &key, const std::string &value); void set_config_item(const std::string &key, const std::string &value);
void setup_id_maps(); void setup_id_maps();
void setup_network();
State state_; State state_;
lxc_container *container_; lxc_container *container_;

View file

@ -25,10 +25,8 @@ namespace skeleton {
std::shared_ptr<Service> Service::create_for_bus( std::shared_ptr<Service> Service::create_for_bus(
const core::dbus::Bus::Ptr &bus, const core::dbus::Bus::Ptr &bus,
const std::shared_ptr<anbox::application::Manager> &application_manager) { const std::shared_ptr<anbox::application::Manager> &application_manager) {
auto service = core::dbus::Service::add_service( auto service = core::dbus::Service::add_service(bus, anbox::dbus::interface::Service::name());
bus, anbox::dbus::interface::Service::name()); auto object = service->add_object_for_path(anbox::dbus::interface::Service::path());
auto object =
service->add_object_for_path(anbox::dbus::interface::Service::path());
return std::make_shared<Service>(bus, service, object, application_manager); return std::make_shared<Service>(bus, service, object, application_manager);
} }

View file

@ -25,7 +25,7 @@ namespace dbus {
namespace stub { namespace stub {
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const core::dbus::Bus::Ptr &bus) { std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const core::dbus::Bus::Ptr &bus) {
auto service = core::dbus::Service::use_service_or_throw_if_not_available(bus, anbox::dbus::interface::Service::name()); auto service = core::dbus::Service::use_service_or_throw_if_not_available(bus, anbox::dbus::interface::Service::name());
auto object = service->add_object_for_path(anbox::dbus::interface::Service::path()); auto object = service->object_for_path(anbox::dbus::interface::Service::path());
return std::make_shared<ApplicationManager>(bus, service, object); return std::make_shared<ApplicationManager>(bus, service, object);
} }

View file

@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "ColorBuffer.h"
#include "DispatchTables.h"
#include "RenderThreadInfo.h"
#include "TextureDraw.h"
#include "TextureResize.h"
#include "OpenGLESDispatch/EGLDispatch.h"
#include "anbox/graphics/emugl/ColorBuffer.h"
#include "anbox/graphics/emugl/DispatchTables.h"
#include "anbox/graphics/emugl/RenderThreadInfo.h"
#include "anbox/graphics/emugl/TextureDraw.h"
#include "anbox/graphics/emugl/TextureResize.h"
#include "anbox/logger.h" #include "anbox/logger.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
#include <stdio.h> #include <stdio.h>
namespace { namespace {
@ -35,22 +34,6 @@ inline void* SafePointerFromUInt(unsigned int handle) {
return reinterpret_cast<void*>(static_cast<uintptr_t>(handle)); return reinterpret_cast<void*>(static_cast<uintptr_t>(handle));
} }
inline unsigned int SafeUIntFromPointer(const void* ptr) {
#if 1
// Ignore the assert below to avoid crashing when running older
// system images, which might have buggy encoder libraries. Print
// an error message though.
if (reinterpret_cast<uintptr_t>(ptr) != static_cast<unsigned int>(reinterpret_cast<uintptr_t>(ptr))) {
WARNING("Bad generic pointer %p", ptr);
}
#else
// Assertion error if the pointer contains a value that does not fit
// in an unsigned integer!
assert((uintptr_t)(ptr) == (unsigned int)(uintptr_t)(ptr));
#endif
return static_cast<unsigned int>(reinterpret_cast<uintptr_t>(ptr));
}
// Lazily create and bind a framebuffer object to the current host context. // Lazily create and bind a framebuffer object to the current host context.
// |fbo| is the address of the framebuffer object name. // |fbo| is the address of the framebuffer object name.
// |tex| is the name of a texture that is attached to the framebuffer object // |tex| is the name of a texture that is attached to the framebuffer object
@ -251,7 +234,7 @@ void ColorBuffer::subUpdate(int x, int y, int width, int height,
bool ColorBuffer::blitFromCurrentReadBuffer() { bool ColorBuffer::blitFromCurrentReadBuffer() {
RenderThreadInfo* tInfo = RenderThreadInfo::get(); RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) { if (!tInfo->currContext) {
// no Current context // no Current context
return false; return false;
} }
@ -312,7 +295,7 @@ bool ColorBuffer::bindToTexture() {
return false; return false;
} }
RenderThreadInfo* tInfo = RenderThreadInfo::get(); RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) { if (!tInfo->currContext) {
return false; return false;
} }
if (tInfo->currContext->isGL2()) { if (tInfo->currContext->isGL2()) {
@ -328,7 +311,7 @@ bool ColorBuffer::bindToRenderbuffer() {
return false; return false;
} }
RenderThreadInfo* tInfo = RenderThreadInfo::get(); RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) { if (!tInfo->currContext) {
return false; return false;
} }
if (tInfo->currContext->isGL2()) { if (tInfo->currContext->isGL2()) {

View file

@ -19,7 +19,6 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include <GLES/gl.h> #include <GLES/gl.h>
#include "emugl/common/smart_ptr.h"
#include <memory> #include <memory>
@ -135,6 +134,6 @@ class ColorBuffer {
TextureResize* m_resizer; TextureResize* m_resizer;
}; };
typedef emugl::SmartPtr<ColorBuffer> ColorBufferPtr; typedef std::shared_ptr<ColorBuffer> ColorBufferPtr;
#endif #endif

View file

@ -17,22 +17,22 @@
#include "DisplayManager.h" #include "DisplayManager.h"
namespace { namespace anbox {
std::shared_ptr<DisplayManager> display_mgr; namespace graphics {
namespace emugl {
class NullDisplayManager : public DisplayManager { std::shared_ptr<DisplayInfo> DisplayInfo::get() {
public: static auto info = std::make_shared<DisplayInfo>();
DisplayInfo display_info() const override { return {1280, 720}; } return info;
};
} }
DisplayManager::~DisplayManager() {} void DisplayInfo::set_resolution(const std::uint32_t &vertical, const std::uint32_t horizontal) {
vertical_resolution_ = vertical;
std::shared_ptr<DisplayManager> DisplayManager::get() { horizontal_resolution_ = horizontal;
if (!display_mgr) display_mgr = std::make_shared<NullDisplayManager>();
return display_mgr;
} }
void registerDisplayManager(const std::shared_ptr<DisplayManager> &mgr) { std::uint32_t DisplayInfo::vertical_resolution() const { return vertical_resolution_; }
display_mgr = mgr;
} std::uint32_t DisplayInfo::horizontal_resolution() const { return horizontal_resolution_; }
} // namespace emugl
} // namespace graphics
} // namespace anbox

View file

@ -15,25 +15,32 @@
* *
*/ */
#ifndef DISPLAY_MANAGER_H_ #ifndef ANBOX_GRAPHICS_EMUGL_DISPLAY_INFO_H_
#define DISPLAY_MANAGER_H_ #define ANBOX_GRAPHICS_EMUGL_DISPLAY_INFO_H_
#include <cstdint>
#include <memory> #include <memory>
class DisplayManager { namespace anbox {
namespace graphics {
namespace emugl {
class DisplayInfo {
public: public:
virtual ~DisplayManager(); DisplayInfo() = default;
struct DisplayInfo { static std::shared_ptr<DisplayInfo> get();
int horizontal_resolution;
int vertical_resolution;
};
virtual DisplayInfo display_info() const = 0; void set_resolution(const std::uint32_t &vertical, const std::uint32_t horizontal);
static std::shared_ptr<DisplayManager> get(); std::uint32_t vertical_resolution() const;
std::uint32_t horizontal_resolution() const;
private:
std::uint32_t vertical_resolution_ = 1280;
std::uint32_t horizontal_resolution_ = 720;
}; };
} // namespace emugl
void registerDisplayManager(const std::shared_ptr<DisplayManager> &mgr); } // namespace graphics
} // namespace anbox
#endif #endif

View file

@ -13,13 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "ReadBuffer.h"
#include "anbox/graphics/emugl/ReadBuffer.h"
#include "anbox/logger.h"
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>
#include "anbox/logger.h"
ReadBuffer::ReadBuffer(size_t bufsize) { ReadBuffer::ReadBuffer(size_t bufsize) {
m_size = bufsize; m_size = bufsize;
m_buf = static_cast<unsigned char*>(malloc(m_size * sizeof(unsigned char))); m_buf = static_cast<unsigned char*>(malloc(m_size * sizeof(unsigned char)));

View file

@ -16,7 +16,7 @@
#ifndef _READ_BUFFER_H #ifndef _READ_BUFFER_H
#define _READ_BUFFER_H #define _READ_BUFFER_H
#include "IOStream.h" #include "external/android-emugl/host/include/libOpenglRender/IOStream.h"
class ReadBuffer { class ReadBuffer {
public: public:
@ -34,4 +34,5 @@ class ReadBuffer {
size_t m_size; size_t m_size;
size_t m_validData; size_t m_validData;
}; };
#endif #endif

View file

@ -14,15 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
#include "RenderApi.h" #include "anbox/graphics/emugl/RenderApi.h"
#include "anbox/graphics/emugl/DispatchTables.h"
#include "DispatchTables.h" #include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/GLESv1Dispatch.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/GLESv2Dispatch.h"
#include "OpenGLESDispatch/EGLDispatch.h" #include "external/android-emugl/shared/emugl/common/crash_reporter.h"
#include "OpenGLESDispatch/GLESv1Dispatch.h"
#include "OpenGLESDispatch/GLESv2Dispatch.h"
#include "emugl/common/crash_reporter.h"
#include <string.h> #include <string.h>

View file

@ -21,7 +21,7 @@
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include "emugl/common/logging.h" #include "external/android-emugl/shared/emugl/common/logging.h"
typedef struct { typedef struct {
logger_t coarse; logger_t coarse;

View file

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "RenderContext.h"
#include "anbox/graphics/emugl/RenderContext.h"
#include "OpenGLESDispatch/EGLDispatch.h" #include "OpenGLESDispatch/EGLDispatch.h"

View file

@ -13,14 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef _LIBRENDER_RENDER_CONTEXT_H #ifndef _LIBRENDER_RENDER_CONTEXT_H
#define _LIBRENDER_RENDER_CONTEXT_H #define _LIBRENDER_RENDER_CONTEXT_H
#include "GLDecoderContextData.h" #include "external/android-emugl/shared/OpenglCodecCommon/GLDecoderContextData.h"
#include "emugl/common/smart_ptr.h"
#include <EGL/egl.h> #include <EGL/egl.h>
#include <memory>
// A class used to model a guest EGLContext. This simply wraps a host // A class used to model a guest EGLContext. This simply wraps a host
// EGLContext, associated with an GLDecoderContextData instance that is // EGLContext, associated with an GLDecoderContextData instance that is
// used to store copies of guest-side arrays. // used to store copies of guest-side arrays.
@ -60,6 +62,6 @@ class RenderContext {
GLDecoderContextData mContextData; GLDecoderContextData mContextData;
}; };
typedef emugl::SmartPtr<RenderContext> RenderContextPtr; typedef std::shared_ptr<RenderContext> RenderContextPtr;
#endif // _LIBRENDER_RENDER_CONTEXT_H #endif // _LIBRENDER_RENDER_CONTEXT_H

View file

@ -13,20 +13,20 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "RenderControl.h"
#include "ChecksumCalculatorThreadInfo.h"
#include "DispatchTables.h"
#include "DisplayManager.h"
#include "RenderThreadInfo.h"
#include "Renderer.h"
#include "RendererConfig.h"
#include "OpenGLESDispatch/EGLDispatch.h"
#include "anbox/graphics/emugl/RenderControl.h"
#include "anbox/graphics/emugl/DispatchTables.h"
#include "anbox/graphics/emugl/DisplayManager.h"
#include "anbox/graphics/emugl/RenderThreadInfo.h"
#include "anbox/graphics/emugl/Renderer.h"
#include "anbox/graphics/emugl/RendererConfig.h"
#include "anbox/graphics/layer_composer.h" #include "anbox/graphics/layer_composer.h"
#include "anbox/logger.h" #include "anbox/logger.h"
#include "external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
#include <map> #include <map>
#include <string> #include <string>
@ -169,10 +169,10 @@ static EGLint rcGetFBParam(EGLint param) {
switch (param) { switch (param) {
case FB_WIDTH: case FB_WIDTH:
ret = DisplayManager::get()->display_info().horizontal_resolution; ret = static_cast<EGLint>(anbox::graphics::emugl::DisplayInfo::get()->vertical_resolution());
break; break;
case FB_HEIGHT: case FB_HEIGHT:
ret = DisplayManager::get()->display_info().vertical_resolution; ret = static_cast<EGLint>(anbox::graphics::emugl::DisplayInfo::get()->horizontal_resolution());
break; break;
case FB_XDPI: case FB_XDPI:
ret = 72; // XXX: should be implemented ret = 72; // XXX: should be implemented
@ -360,12 +360,12 @@ int rcGetNumDisplays() {
int rcGetDisplayWidth(uint32_t display_id) { int rcGetDisplayWidth(uint32_t display_id) {
(void)display_id; (void)display_id;
return DisplayManager::get()->display_info().horizontal_resolution; return static_cast<int>(anbox::graphics::emugl::DisplayInfo::get()->vertical_resolution());
} }
int rcGetDisplayHeight(uint32_t display_id) { int rcGetDisplayHeight(uint32_t display_id) {
(void)display_id; (void)display_id;
return DisplayManager::get()->display_info().vertical_resolution; return static_cast<int>(anbox::graphics::emugl::DisplayInfo::get()->horizontal_resolution());
} }
int rcGetDisplayDpiX(uint32_t display_id) { int rcGetDisplayDpiX(uint32_t display_id) {

View file

@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef _RENDER_CONTROL_H #ifndef _RENDER_CONTROL_H
#define _RENDER_CONTROL_H #define _RENDER_CONTROL_H
// Generated with emugl at build time
#include "renderControl_dec.h" #include "renderControl_dec.h"
#include <memory> #include <memory>

View file

@ -13,32 +13,31 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "RenderThread.h"
#include "ReadBuffer.h"
#include "RenderControl.h"
#include "RenderThreadInfo.h"
#include "Renderer.h"
#include "TimeUtils.h"
#include "../../../shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h"
#include "OpenGLESDispatch/EGLDispatch.h"
#include "OpenGLESDispatch/GLESv1Dispatch.h"
#include "OpenGLESDispatch/GLESv2Dispatch.h"
#include "anbox/graphics/emugl/RenderThread.h"
#include "anbox/graphics/emugl/ReadBuffer.h"
#include "anbox/graphics/emugl/RenderControl.h"
#include "anbox/graphics/emugl/RenderThreadInfo.h"
#include "anbox/graphics/emugl/Renderer.h"
#include "anbox/graphics/emugl/TimeUtils.h"
#include "anbox/logger.h" #include "anbox/logger.h"
#include "external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/GLESv1Dispatch.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/GLESv2Dispatch.h"
#define STREAM_BUFFER_SIZE 4 * 1024 * 1024 #define STREAM_BUFFER_SIZE 4 * 1024 * 1024
RenderThread::RenderThread(const std::shared_ptr<Renderer> &renderer, IOStream *stream, emugl::Mutex *lock) RenderThread::RenderThread(const std::shared_ptr<Renderer> &renderer, IOStream *stream, std::mutex &m)
: emugl::Thread(), renderer_(renderer), m_lock(lock), m_stream(stream) {} : emugl::Thread(), renderer_(renderer), m_lock(m), m_stream(stream) {}
RenderThread::~RenderThread() { RenderThread::~RenderThread() {
forceStop(); forceStop();
} }
RenderThread *RenderThread::create(const std::shared_ptr<Renderer> &renderer, IOStream *stream, emugl::Mutex *lock) { RenderThread *RenderThread::create(const std::shared_ptr<Renderer> &renderer, IOStream *stream, std::mutex &m) {
return new RenderThread(renderer, stream, lock); return new RenderThread(renderer, stream, m);
} }
void RenderThread::forceStop() { m_stream->forceStop(); } void RenderThread::forceStop() { m_stream->forceStop(); }
@ -62,7 +61,8 @@ intptr_t RenderThread::main() {
do { do {
progress = false; progress = false;
m_lock->lock(); std::unique_lock<std::mutex> l(m_lock);
size_t last = size_t last =
threadInfo.m_glDec.decode(readBuf.buf(), readBuf.validData(), m_stream); threadInfo.m_glDec.decode(readBuf.buf(), readBuf.validData(), m_stream);
if (last > 0) { if (last > 0) {
@ -83,8 +83,6 @@ intptr_t RenderThread::main() {
progress = true; progress = true;
} }
m_lock->unlock();
} while (progress); } while (progress);
} }

View file

@ -13,15 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef _LIB_OPENGL_RENDER_RENDER_THREAD_H #ifndef _LIB_OPENGL_RENDER_RENDER_THREAD_H
#define _LIB_OPENGL_RENDER_RENDER_THREAD_H #define _LIB_OPENGL_RENDER_RENDER_THREAD_H
#include "IOStream.h" #include "external/android-emugl/host/include/libOpenglRender/IOStream.h"
#include "emugl/common/mutex.h"
#include "emugl/common/thread.h" #include "emugl/common/thread.h"
#include <memory> #include <memory>
#include <mutex>
class Renderer; class Renderer;
@ -36,7 +37,7 @@ class RenderThread : public emugl::Thread {
// decoding operations between all threads. // decoding operations between all threads.
// TODO(digit): Why is this needed here? Shouldn't this be handled // TODO(digit): Why is this needed here? Shouldn't this be handled
// by the decoders themselves or at a lower-level? // by the decoders themselves or at a lower-level?
static RenderThread* create(const std::shared_ptr<Renderer>& renderer, IOStream* stream, emugl::Mutex* mutex); static RenderThread* create(const std::shared_ptr<Renderer>& renderer, IOStream* stream, std::mutex &m);
// Destructor. // Destructor.
virtual ~RenderThread(); virtual ~RenderThread();
@ -51,12 +52,12 @@ class RenderThread : public emugl::Thread {
private: private:
RenderThread(); // No default constructor RenderThread(); // No default constructor
RenderThread(const std::shared_ptr<Renderer>& renderer, IOStream* stream, emugl::Mutex* mutex); RenderThread(const std::shared_ptr<Renderer>& renderer, IOStream* stream, std::mutex &m);
virtual intptr_t main(); virtual intptr_t main();
std::shared_ptr<Renderer> renderer_; std::shared_ptr<Renderer> renderer_;
emugl::Mutex* m_lock; std::mutex &m_lock;
IOStream* m_stream; IOStream* m_stream;
}; };

View file

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
#include "RenderThreadInfo.h" #include "anbox/graphics/emugl/RenderThreadInfo.h"
#include "emugl/common/lazy_instance.h" #include "external/android-emugl/shared/emugl/common/lazy_instance.h"
#include "emugl/common/thread_store.h" #include "external/android-emugl/shared/emugl/common/thread_store.h"
namespace { namespace {
class ThreadInfoStore : public ::emugl::ThreadStore { class ThreadInfoStore : public ::emugl::ThreadStore {

View file

@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef _LIB_OPENGL_RENDER_THREAD_INFO_H #ifndef _LIB_OPENGL_RENDER_THREAD_INFO_H
#define _LIB_OPENGL_RENDER_THREAD_INFO_H #define _LIB_OPENGL_RENDER_THREAD_INFO_H
#include "GLESv1Decoder.h" #include "anbox/graphics/emugl/RenderContext.h"
#include "GLESv2Decoder.h" #include "anbox/graphics/emugl/WindowSurface.h"
#include "RenderContext.h"
#include "WindowSurface.h" #include "external/android-emugl/host/libs/GLESv1_dec/GLESv1Decoder.h"
#include "external/android-emugl/host/libs/GLESv2_dec/GLESv2Decoder.h"
// Generated with emugl at build time
#include "renderControl_dec.h" #include "renderControl_dec.h"
#include <set> #include <set>

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include "Renderable.h" #include "anbox/graphics/emugl/Renderable.h"
Renderable::Renderable(const std::string &name, const std::uint32_t &buffer, Renderable::Renderable(const std::string &name, const std::uint32_t &buffer,
const anbox::graphics::Rect &screen_position, const anbox::graphics::Rect &screen_position,

View file

@ -14,19 +14,18 @@
* limitations under the License. * limitations under the License.
*/ */
#include "Renderer.h" #include "anbox/graphics/emugl/Renderer.h"
#include "anbox/graphics/emugl/DispatchTables.h"
#include "DispatchTables.h" #include "anbox/graphics/emugl/RenderThreadInfo.h"
#include "RenderThreadInfo.h" #include "anbox/graphics/emugl/TimeUtils.h"
#include "TimeUtils.h"
#include "gles2_dec.h"
#include "OpenGLESDispatch/EGLDispatch.h"
#include "anbox/graphics/gl_extensions.h" #include "anbox/graphics/gl_extensions.h"
#include "anbox/logger.h" #include "anbox/logger.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
// Generated with emugl at build time
#include "gles2_dec.h"
#include <stdio.h> #include <stdio.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@ -361,13 +360,14 @@ HandleType Renderer::genHandle() {
HandleType Renderer::createColorBuffer(int p_width, int p_height, HandleType Renderer::createColorBuffer(int p_width, int p_height,
GLenum p_internalFormat) { GLenum p_internalFormat) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
HandleType ret = 0; HandleType ret = 0;
ColorBufferPtr cb(ColorBuffer::create( ColorBufferPtr cb(ColorBuffer::create(
getDisplay(), p_width, p_height, p_internalFormat, getDisplay(), p_width, p_height, p_internalFormat,
getCaps().has_eglimage_texture_2d, m_colorBufferHelper)); getCaps().has_eglimage_texture_2d, m_colorBufferHelper));
if (cb.Ptr() != NULL) { if (cb) {
ret = genHandle(); ret = genHandle();
m_colorbuffers[ret].cb = cb; m_colorbuffers[ret].cb = cb;
m_colorbuffers[ret].refcount = 1; m_colorbuffers[ret].refcount = 1;
@ -377,7 +377,8 @@ HandleType Renderer::createColorBuffer(int p_width, int p_height,
HandleType Renderer::createRenderContext(int p_config, HandleType p_share, HandleType Renderer::createRenderContext(int p_config, HandleType p_share,
bool p_isGL2) { bool p_isGL2) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
HandleType ret = 0; HandleType ret = 0;
const RendererConfig *config = getConfigs()->get(p_config); const RendererConfig *config = getConfigs()->get(p_config);
@ -394,11 +395,11 @@ HandleType Renderer::createRenderContext(int p_config, HandleType p_share,
share = (*s).second; share = (*s).second;
} }
EGLContext sharedContext = EGLContext sharedContext =
share.Ptr() ? share->getEGLContext() : EGL_NO_CONTEXT; share ? share->getEGLContext() : EGL_NO_CONTEXT;
RenderContextPtr rctx(RenderContext::create( RenderContextPtr rctx(RenderContext::create(
m_eglDisplay, config->getEglConfig(), sharedContext, p_isGL2)); m_eglDisplay, config->getEglConfig(), sharedContext, p_isGL2));
if (rctx.Ptr() != NULL) { if (rctx) {
ret = genHandle(); ret = genHandle();
m_contexts[ret] = rctx; m_contexts[ret] = rctx;
RenderThreadInfo *tinfo = RenderThreadInfo::get(); RenderThreadInfo *tinfo = RenderThreadInfo::get();
@ -409,7 +410,7 @@ HandleType Renderer::createRenderContext(int p_config, HandleType p_share,
HandleType Renderer::createWindowSurface(int p_config, int p_width, HandleType Renderer::createWindowSurface(int p_config, int p_width,
int p_height) { int p_height) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
HandleType ret = 0; HandleType ret = 0;
@ -420,7 +421,7 @@ HandleType Renderer::createWindowSurface(int p_config, int p_width,
WindowSurfacePtr win(WindowSurface::create( WindowSurfacePtr win(WindowSurface::create(
getDisplay(), config->getEglConfig(), p_width, p_height)); getDisplay(), config->getEglConfig(), p_width, p_height));
if (win.Ptr() != NULL) { if (win) {
ret = genHandle(); ret = genHandle();
m_windows[ret] = std::pair<WindowSurfacePtr, HandleType>(win, 0); m_windows[ret] = std::pair<WindowSurfacePtr, HandleType>(win, 0);
RenderThreadInfo *tinfo = RenderThreadInfo::get(); RenderThreadInfo *tinfo = RenderThreadInfo::get();
@ -431,7 +432,8 @@ HandleType Renderer::createWindowSurface(int p_config, int p_width,
} }
void Renderer::drainRenderContext() { void Renderer::drainRenderContext() {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
RenderThreadInfo *tinfo = RenderThreadInfo::get(); RenderThreadInfo *tinfo = RenderThreadInfo::get();
if (tinfo->m_contextSet.empty()) return; if (tinfo->m_contextSet.empty()) return;
for (std::set<HandleType>::iterator it = tinfo->m_contextSet.begin(); for (std::set<HandleType>::iterator it = tinfo->m_contextSet.begin();
@ -443,7 +445,8 @@ void Renderer::drainRenderContext() {
} }
void Renderer::drainWindowSurface() { void Renderer::drainWindowSurface() {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
RenderThreadInfo *tinfo = RenderThreadInfo::get(); RenderThreadInfo *tinfo = RenderThreadInfo::get();
if (tinfo->m_windowSet.empty()) return; if (tinfo->m_windowSet.empty()) return;
for (std::set<HandleType>::iterator it = tinfo->m_windowSet.begin(); for (std::set<HandleType>::iterator it = tinfo->m_windowSet.begin();
@ -466,7 +469,8 @@ void Renderer::drainWindowSurface() {
} }
void Renderer::DestroyRenderContext(HandleType p_context) { void Renderer::DestroyRenderContext(HandleType p_context) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
m_contexts.erase(p_context); m_contexts.erase(p_context);
RenderThreadInfo *tinfo = RenderThreadInfo::get(); RenderThreadInfo *tinfo = RenderThreadInfo::get();
if (tinfo->m_contextSet.empty()) return; if (tinfo->m_contextSet.empty()) return;
@ -474,7 +478,8 @@ void Renderer::DestroyRenderContext(HandleType p_context) {
} }
void Renderer::DestroyWindowSurface(HandleType p_surface) { void Renderer::DestroyWindowSurface(HandleType p_surface) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
if (m_windows.find(p_surface) != m_windows.end()) { if (m_windows.find(p_surface) != m_windows.end()) {
m_windows.erase(p_surface); m_windows.erase(p_surface);
RenderThreadInfo *tinfo = RenderThreadInfo::get(); RenderThreadInfo *tinfo = RenderThreadInfo::get();
@ -484,7 +489,8 @@ void Renderer::DestroyWindowSurface(HandleType p_surface) {
} }
int Renderer::openColorBuffer(HandleType p_colorbuffer) { int Renderer::openColorBuffer(HandleType p_colorbuffer) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
if (c == m_colorbuffers.end()) { if (c == m_colorbuffers.end()) {
// bad colorbuffer handle // bad colorbuffer handle
@ -496,7 +502,8 @@ int Renderer::openColorBuffer(HandleType p_colorbuffer) {
} }
void Renderer::closeColorBuffer(HandleType p_colorbuffer) { void Renderer::closeColorBuffer(HandleType p_colorbuffer) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
if (c == m_colorbuffers.end()) { if (c == m_colorbuffers.end()) {
// This is harmless: it is normal for guest system to issue // This is harmless: it is normal for guest system to issue
@ -511,7 +518,7 @@ void Renderer::closeColorBuffer(HandleType p_colorbuffer) {
} }
bool Renderer::flushWindowSurfaceColorBuffer(HandleType p_surface) { bool Renderer::flushWindowSurfaceColorBuffer(HandleType p_surface) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
WindowSurfaceMap::iterator w(m_windows.find(p_surface)); WindowSurfaceMap::iterator w(m_windows.find(p_surface));
if (w == m_windows.end()) { if (w == m_windows.end()) {
@ -521,7 +528,10 @@ bool Renderer::flushWindowSurfaceColorBuffer(HandleType p_surface) {
return false; return false;
} }
WindowSurface *surface = (*w).second.first.Ptr(); auto surface = (*w).second.first;
if (!surface)
return false;
surface->flushColorBuffer(); surface->flushColorBuffer();
return true; return true;
@ -529,7 +539,7 @@ bool Renderer::flushWindowSurfaceColorBuffer(HandleType p_surface) {
bool Renderer::setWindowSurfaceColorBuffer(HandleType p_surface, bool Renderer::setWindowSurfaceColorBuffer(HandleType p_surface,
HandleType p_colorbuffer) { HandleType p_colorbuffer) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
WindowSurfaceMap::iterator w(m_windows.find(p_surface)); WindowSurfaceMap::iterator w(m_windows.find(p_surface));
if (w == m_windows.end()) { if (w == m_windows.end()) {
@ -553,7 +563,7 @@ bool Renderer::setWindowSurfaceColorBuffer(HandleType p_surface,
void Renderer::readColorBuffer(HandleType p_colorbuffer, int x, int y, void Renderer::readColorBuffer(HandleType p_colorbuffer, int x, int y,
int width, int height, GLenum format, int width, int height, GLenum format,
GLenum type, void *pixels) { GLenum type, void *pixels) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
if (c == m_colorbuffers.end()) { if (c == m_colorbuffers.end()) {
@ -567,7 +577,7 @@ void Renderer::readColorBuffer(HandleType p_colorbuffer, int x, int y,
bool Renderer::updateColorBuffer(HandleType p_colorbuffer, int x, int y, bool Renderer::updateColorBuffer(HandleType p_colorbuffer, int x, int y,
int width, int height, GLenum format, int width, int height, GLenum format,
GLenum type, void *pixels) { GLenum type, void *pixels) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
if (c == m_colorbuffers.end()) { if (c == m_colorbuffers.end()) {
@ -581,7 +591,7 @@ bool Renderer::updateColorBuffer(HandleType p_colorbuffer, int x, int y,
} }
bool Renderer::bindColorBufferToTexture(HandleType p_colorbuffer) { bool Renderer::bindColorBufferToTexture(HandleType p_colorbuffer) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
if (c == m_colorbuffers.end()) { if (c == m_colorbuffers.end()) {
@ -593,7 +603,7 @@ bool Renderer::bindColorBufferToTexture(HandleType p_colorbuffer) {
} }
bool Renderer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) { bool Renderer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer));
if (c == m_colorbuffers.end()) { if (c == m_colorbuffers.end()) {
@ -606,7 +616,7 @@ bool Renderer::bindColorBufferToRenderbuffer(HandleType p_colorbuffer) {
bool Renderer::bindContext(HandleType p_context, HandleType p_drawSurface, bool Renderer::bindContext(HandleType p_context, HandleType p_drawSurface,
HandleType p_readSurface) { HandleType p_readSurface) {
emugl::Mutex::AutoLock mutex(m_lock); std::unique_lock<std::mutex> l(m_lock);
WindowSurfacePtr draw(NULL), read(NULL); WindowSurfacePtr draw(NULL), read(NULL);
RenderContextPtr ctx(NULL); RenderContextPtr ctx(NULL);
@ -654,7 +664,7 @@ bool Renderer::bindContext(HandleType p_context, HandleType p_drawSurface,
// //
RenderThreadInfo *tinfo = RenderThreadInfo::get(); RenderThreadInfo *tinfo = RenderThreadInfo::get();
WindowSurfacePtr bindDraw, bindRead; WindowSurfacePtr bindDraw, bindRead;
if (draw.Ptr() == NULL && read.Ptr() == NULL) { if (!draw && !read) {
// Unbind the current read and draw surfaces from the context // Unbind the current read and draw surfaces from the context
bindDraw = tinfo->currDrawSurf; bindDraw = tinfo->currDrawSurf;
bindRead = tinfo->currReadSurf; bindRead = tinfo->currReadSurf;
@ -663,8 +673,8 @@ bool Renderer::bindContext(HandleType p_context, HandleType p_drawSurface,
bindRead = read; bindRead = read;
} }
if (bindDraw.Ptr() != NULL && bindRead.Ptr() != NULL) { if (bindDraw && bindRead) {
if (bindDraw.Ptr() != bindRead.Ptr()) { if (bindDraw != bindRead) {
bindDraw->bind(ctx, WindowSurface::BIND_DRAW); bindDraw->bind(ctx, WindowSurface::BIND_DRAW);
bindRead->bind(ctx, WindowSurface::BIND_READ); bindRead->bind(ctx, WindowSurface::BIND_READ);
} else { } else {

View file

@ -16,14 +16,12 @@
#ifndef _LIBRENDER_FRAMEBUFFER_H #ifndef _LIBRENDER_FRAMEBUFFER_H
#define _LIBRENDER_FRAMEBUFFER_H #define _LIBRENDER_FRAMEBUFFER_H
#include "ColorBuffer.h" #include "anbox/graphics/emugl/ColorBuffer.h"
#include "RenderContext.h" #include "anbox/graphics/emugl/RenderContext.h"
#include "RendererConfig.h" #include "anbox/graphics/emugl/RendererConfig.h"
#include "TextureDraw.h" #include "anbox/graphics/emugl/TextureDraw.h"
#include "WindowSurface.h" #include "anbox/graphics/emugl/WindowSurface.h"
#include "emugl/common/mutex.h" #include "anbox/graphics/emugl/Renderable.h"
#include "Renderable.h"
#include "anbox/graphics/primitives.h" #include "anbox/graphics/primitives.h"
#include "anbox/graphics/program_family.h" #include "anbox/graphics/program_family.h"
@ -32,6 +30,7 @@
#include <EGL/egl.h> #include <EGL/egl.h>
#include <map> #include <map>
#include <mutex>
#include <stdint.h> #include <stdint.h>
@ -257,7 +256,7 @@ class Renderer : public anbox::graphics::Renderer {
private: private:
static Renderer* s_renderer; static Renderer* s_renderer;
static HandleType s_nextHandle; static HandleType s_nextHandle;
emugl::Mutex m_lock; std::mutex m_lock;
RendererConfigList* m_configs; RendererConfigList* m_configs;
RendererCaps m_caps; RendererCaps m_caps;
EGLDisplay m_eglDisplay; EGLDisplay m_eglDisplay;

View file

@ -12,15 +12,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "RendererConfig.h" #include "anbox/graphics/emugl/RendererConfig.h"
#include "anbox/logger.h"
#include "OpenGLESDispatch/EGLDispatch.h" #include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "anbox/logger.h"
namespace { namespace {
const GLuint kConfigAttributes[] = { const GLuint kConfigAttributes[] = {
EGL_DEPTH_SIZE, // must be first - see getDepthSize() EGL_DEPTH_SIZE, // must be first - see getDepthSize()

View file

@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "TextureDraw.h" #include "anbox/graphics/emugl/TextureDraw.h"
#include "anbox/graphics/emugl/DispatchTables.h"
#include "DispatchTables.h" #include "anbox/logger.h"
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
@ -22,8 +22,6 @@
#include <stdio.h> #include <stdio.h>
#include "anbox/logger.h"
// M_PI isn't defined in C++ (when strict ISO compliance is enabled) // M_PI isn't defined in C++ (when strict ISO compliance is enabled)
#ifndef M_PI #ifndef M_PI
#define M_PI 3.14159265358979323846264338327 #define M_PI 3.14159265358979323846264338327
@ -97,16 +95,13 @@ const GLint kIndicesLen = sizeof(kIndices) / sizeof(kIndices[0]);
} // namespace } // namespace
TextureDraw::TextureDraw(EGLDisplay display) TextureDraw::TextureDraw(EGLDisplay)
: mDisplay(display), : mVertexShader(0),
mVertexShader(0),
mFragmentShader(0), mFragmentShader(0),
mProgram(0), mProgram(0),
mPositionSlot(-1), mPositionSlot(-1),
mInCoordSlot(-1), mInCoordSlot(-1),
mTextureSlot(-1), mTextureSlot(-1) {
mRotationSlot(-1),
mTranslationSlot(-1) {
// Create shaders and program. // Create shaders and program.
mVertexShader = createShader(GL_VERTEX_SHADER, kVertexShaderSource); mVertexShader = createShader(GL_VERTEX_SHADER, kVertexShaderSource);
mFragmentShader = createShader(GL_FRAGMENT_SHADER, kFragmentShaderSource); mFragmentShader = createShader(GL_FRAGMENT_SHADER, kFragmentShaderSource);

View file

@ -42,15 +42,12 @@ class TextureDraw {
bool draw(GLuint texture); bool draw(GLuint texture);
private: private:
EGLDisplay mDisplay;
GLuint mVertexShader; GLuint mVertexShader;
GLuint mFragmentShader; GLuint mFragmentShader;
GLuint mProgram; GLuint mProgram;
GLint mPositionSlot; GLint mPositionSlot;
GLint mInCoordSlot; GLint mInCoordSlot;
GLint mTextureSlot; GLint mTextureSlot;
GLint mRotationSlot;
GLint mTranslationSlot;
GLuint mVertexBuffer; GLuint mVertexBuffer;
GLuint mIndexBuffer; GLuint mIndexBuffer;
}; };

View file

@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "TextureResize.h"
#include "DispatchTables.h" #include "anbox/graphics/emugl/TextureResize.h"
#include "anbox/graphics/emugl/DispatchTables.h"
#include "anbox/logger.h"
#include <stdio.h> #include <stdio.h>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility> #include <utility>
#include "anbox/logger.h"
#define MAX_FACTOR_POWER 4 #define MAX_FACTOR_POWER 4
static const char kCommonShaderSource[] = static const char kCommonShaderSource[] =

View file

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef _LIBRENDER_TEXTURERESIZE_H #ifndef _LIBRENDER_TEXTURERESIZE_H
#define _LIBRENDER_TEXTURERESIZE_H #define _LIBRENDER_TEXTURERESIZE_H

View file

@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "TimeUtils.h"
#include "anbox/graphics/emugl/TimeUtils.h"
#include <stdlib.h> #include <stdlib.h>
#include <sys/time.h> #include <sys/time.h>

View file

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef _TIME_UTILS_H #ifndef _TIME_UTILS_H
#define _TIME_UTILS_H #define _TIME_UTILS_H

View file

@ -13,17 +13,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include "WindowSurface.h"
#include "RendererConfig.h"
#include "OpenGLESDispatch/EGLDispatch.h" #include "anbox/graphics/emugl/WindowSurface.h"
#include "anbox/graphics/emugl/RendererConfig.h"
#include "anbox/logger.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
#include <GLES/glext.h> #include <GLES/glext.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "anbox/logger.h"
WindowSurface::WindowSurface(EGLDisplay display, EGLConfig config) WindowSurface::WindowSurface(EGLDisplay display, EGLConfig config)
: mSurface(NULL), : mSurface(NULL),
@ -84,7 +85,7 @@ void WindowSurface::bind(RenderContextPtr p_ctx, BindType p_bindType) {
} }
bool WindowSurface::flushColorBuffer() { bool WindowSurface::flushColorBuffer() {
if (!mAttachedColorBuffer.Ptr()) { if (!mAttachedColorBuffer) {
return true; return true;
} }
if (!mWidth || !mHeight) { if (!mWidth || !mHeight) {
@ -98,7 +99,7 @@ bool WindowSurface::flushColorBuffer() {
return false; return false;
} }
if (!mDrawContext.Ptr()) { if (!mDrawContext) {
ERROR("Draw context is NULL"); ERROR("Draw context is NULL");
return false; return false;
} }

View file

@ -16,10 +16,8 @@
#ifndef _LIBRENDER_WINDOW_SURFACE_H #ifndef _LIBRENDER_WINDOW_SURFACE_H
#define _LIBRENDER_WINDOW_SURFACE_H #define _LIBRENDER_WINDOW_SURFACE_H
#include "ColorBuffer.h" #include "anbox/graphics/emugl/ColorBuffer.h"
#include "RenderContext.h" #include "anbox/graphics/emugl/RenderContext.h"
#include "emugl/common/smart_ptr.h"
#include <EGL/egl.h> #include <EGL/egl.h>
#include <GLES/gl.h> #include <GLES/gl.h>
@ -94,6 +92,6 @@ class WindowSurface {
EGLDisplay mDisplay; EGLDisplay mDisplay;
}; };
typedef emugl::SmartPtr<WindowSurface> WindowSurfacePtr; typedef std::shared_ptr<WindowSurface> WindowSurfacePtr;
#endif // _LIBRENDER_WINDOW_SURFACE_H #endif // _LIBRENDER_WINDOW_SURFACE_H

View file

@ -29,7 +29,7 @@
namespace anbox { namespace anbox {
namespace graphics { namespace graphics {
emugl::Mutex OpenGlesMessageProcessor::global_lock{}; std::mutex OpenGlesMessageProcessor::global_lock{};
OpenGlesMessageProcessor::OpenGlesMessageProcessor( OpenGlesMessageProcessor::OpenGlesMessageProcessor(
const std::shared_ptr<Renderer> &renderer, const std::shared_ptr<Renderer> &renderer,
@ -43,7 +43,7 @@ OpenGlesMessageProcessor::OpenGlesMessageProcessor(
boost::asio::buffer(&client_flags, sizeof(unsigned int))); boost::asio::buffer(&client_flags, sizeof(unsigned int)));
if (err) ERROR("%s", err.message()); if (err) ERROR("%s", err.message());
render_thread_.reset(RenderThread::create(renderer, stream_.get(), &global_lock)); render_thread_.reset(RenderThread::create(renderer, stream_.get(), std::ref(global_lock)));
if (!render_thread_->start()) if (!render_thread_->start())
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
std::runtime_error("Failed to start renderer thread")); std::runtime_error("Failed to start renderer thread"));

View file

@ -18,16 +18,15 @@
#ifndef ANBOX_GRAPHICS_OPENGLES_MESSAGE_PROCESSOR_H_ #ifndef ANBOX_GRAPHICS_OPENGLES_MESSAGE_PROCESSOR_H_
#define ANBOX_GRAPHICS_OPENGLES_MESSAGE_PROCESSOR_H_ #define ANBOX_GRAPHICS_OPENGLES_MESSAGE_PROCESSOR_H_
#include <memory>
#include <boost/asio.hpp>
#include "anbox/network/message_processor.h" #include "anbox/network/message_processor.h"
#include "anbox/network/socket_connection.h" #include "anbox/network/socket_connection.h"
#include "anbox/network/socket_messenger.h" #include "anbox/network/socket_messenger.h"
#include "anbox/runtime.h" #include "anbox/runtime.h"
#include "external/android-emugl/shared/emugl/common/mutex.h" #include <boost/asio.hpp>
#include <memory>
#include <mutex>
class IOStream; class IOStream;
class RenderThread; class RenderThread;
@ -45,7 +44,7 @@ class OpenGlesMessageProcessor : public network::MessageProcessor {
bool process_data(const std::vector<std::uint8_t> &data) override; bool process_data(const std::vector<std::uint8_t> &data) override;
private: private:
static emugl::Mutex global_lock; static std::mutex global_lock;
std::shared_ptr<network::SocketMessenger> messenger_; std::shared_ptr<network::SocketMessenger> messenger_;
std::shared_ptr<IOStream> stream_; std::shared_ptr<IOStream> stream_;

View file

@ -64,6 +64,10 @@ struct BoostLogLogger : public anbox::Logger {
severity_ = severity; severity_ = severity;
} }
Severity GetSeverity() override {
return severity_;
}
void Log(Severity severity, const std::string& message, const boost::optional<Location>& loc) override { void Log(Severity severity, const std::string& message, const boost::optional<Location>& loc) override {
if (!initialized_) Init(); if (!initialized_) Init();

View file

@ -51,6 +51,7 @@ class Logger : public DoNotCopyOrMove {
bool SetSeverityFromString(const std::string &severity); bool SetSeverityFromString(const std::string &severity);
virtual void SetSeverity(const Severity& severity) = 0; virtual void SetSeverity(const Severity& severity) = 0;
virtual Severity GetSeverity() = 0;
virtual void Log(Severity severity, const std::string& message, virtual void Log(Severity severity, const std::string& message,
const boost::optional<Location>& location) = 0; const boost::optional<Location>& location) = 0;

View file

@ -33,7 +33,7 @@ PublishedSocketConnector::PublishedSocketConnector(
start_accept(); start_accept();
} }
PublishedSocketConnector::~PublishedSocketConnector() {} PublishedSocketConnector::~PublishedSocketConnector() noexcept {}
void PublishedSocketConnector::start_accept() { void PublishedSocketConnector::start_accept() {
auto socket = std::make_shared<boost::asio::local::stream_protocol::socket>(runtime_->service()); auto socket = std::make_shared<boost::asio::local::stream_protocol::socket>(runtime_->service());

View file

@ -34,7 +34,7 @@ TcpSocketConnector::TcpSocketConnector(
start_accept(); start_accept();
} }
TcpSocketConnector::~TcpSocketConnector() { acceptor_.cancel(); } TcpSocketConnector::~TcpSocketConnector() noexcept { acceptor_.cancel(); }
void TcpSocketConnector::start_accept() { void TcpSocketConnector::start_accept() {
auto socket = auto socket =

View file

@ -16,10 +16,10 @@
*/ */
#include "anbox/qemu/adb_message_processor.h" #include "anbox/qemu/adb_message_processor.h"
#include "anbox/logger.h"
#include "anbox/network/delegate_connection_creator.h" #include "anbox/network/delegate_connection_creator.h"
#include "anbox/network/delegate_message_processor.h" #include "anbox/network/delegate_message_processor.h"
#include "anbox/network/tcp_socket_messenger.h" #include "anbox/network/tcp_socket_messenger.h"
#include "anbox/utils.h"
#include <fstream> #include <fstream>
#include <functional> #include <functional>
@ -27,18 +27,23 @@
namespace { namespace {
const unsigned short default_adb_client_port{5037}; const unsigned short default_adb_client_port{5037};
const unsigned short default_host_listen_port{6664}; const unsigned short default_host_listen_port{6664};
constexpr const char *loopback_address{"127.0.0.1"};
const std::string accept_command{"accept"}; const std::string accept_command{"accept"};
const std::string ok_command{"ok"}; const std::string ok_command{"ok"};
const std::string ko_command{"ko"}; const std::string ko_command{"ko"};
const std::string start_command{"start"}; const std::string start_command{"start"};
// This timeount should be too high to not cause a too long wait time for the
// user until we connect to the adb host instance after it appeared and not
// too short to not put unnecessary burden on the CPU.
const boost::posix_time::seconds default_adb_wait_time{1}; const boost::posix_time::seconds default_adb_wait_time{1};
static std::mutex active_instance;
} }
using namespace std::placeholders; using namespace std::placeholders;
namespace anbox { namespace anbox {
namespace qemu { namespace qemu {
std::mutex AdbMessageProcessor::active_instance_{};
AdbMessageProcessor::AdbMessageProcessor( AdbMessageProcessor::AdbMessageProcessor(
const std::shared_ptr<Runtime> &rt, const std::shared_ptr<Runtime> &rt,
const std::shared_ptr<network::SocketMessenger> &messenger) const std::shared_ptr<network::SocketMessenger> &messenger)
@ -46,12 +51,14 @@ AdbMessageProcessor::AdbMessageProcessor(
state_(waiting_for_guest_accept_command), state_(waiting_for_guest_accept_command),
expected_command_(accept_command), expected_command_(accept_command),
messenger_(messenger), messenger_(messenger),
host_notify_timer_(rt->service()) {} host_notify_timer_(rt->service()),
lock_(active_instance_, std::defer_lock) {}
AdbMessageProcessor::~AdbMessageProcessor() { AdbMessageProcessor::~AdbMessageProcessor() {
state_ = closed_by_host; state_ = closed_by_host;
host_notify_timer_.cancel();
host_connector_.reset(); host_connector_.reset();
active_instance.unlock();
} }
void AdbMessageProcessor::advance_state() { void AdbMessageProcessor::advance_state() {
@ -61,9 +68,10 @@ void AdbMessageProcessor::advance_state() {
// running we don't have to do anything here until that one is done. // running we don't have to do anything here until that one is done.
// The container directly starts a second connection once the first // The container directly starts a second connection once the first
// one is established but will not use it until the active one is closed. // one is established but will not use it until the active one is closed.
active_instance.lock(); lock_.lock();
if (state_ == closed_by_host) { if (state_ == closed_by_host) {
host_notify_timer_.cancel();
host_connector_.reset(); host_connector_.reset();
return; return;
} }
@ -100,9 +108,12 @@ void AdbMessageProcessor::advance_state() {
} }
void AdbMessageProcessor::wait_for_host_connection() { void AdbMessageProcessor::wait_for_host_connection() {
if (state_ == closed_by_host || state_ == closed_by_container)
return;
if (!host_connector_) { if (!host_connector_) {
host_connector_ = std::make_shared<network::TcpSocketConnector>( host_connector_ = std::make_shared<network::TcpSocketConnector>(
boost::asio::ip::address_v4::from_string("127.0.0.1"), boost::asio::ip::address_v4::from_string(loopback_address),
default_host_listen_port, runtime_, default_host_listen_port, runtime_,
std::make_shared< std::make_shared<
network::DelegateConnectionCreator<boost::asio::ip::tcp>>( network::DelegateConnectionCreator<boost::asio::ip::tcp>>(
@ -113,18 +124,19 @@ void AdbMessageProcessor::wait_for_host_connection() {
// Notify the adb host instance so that it knows on which port our // Notify the adb host instance so that it knows on which port our
// proxy is waiting for incoming connections. // proxy is waiting for incoming connections.
auto messenger = std::make_shared<network::TcpSocketMessenger>( auto messenger = std::make_shared<network::TcpSocketMessenger>(
boost::asio::ip::address_v4::from_string("127.0.0.1"), boost::asio::ip::address_v4::from_string(loopback_address), default_adb_client_port, runtime_);
default_adb_client_port, runtime_); auto message = utils::string_format("host:emulator:%d", default_host_listen_port);
auto message = auto handshake = utils::string_format("%04x%s", message.size(), message.c_str());
utils::string_format("host:emulator:%d", default_host_listen_port);
auto handshake =
utils::string_format("%04x%s", message.size(), message.c_str());
messenger->send(handshake.data(), handshake.size()); messenger->send(handshake.data(), handshake.size());
} catch (std::exception &) { } catch (...) {
// Try again later when the host adb service is maybe available // Try again later when the host adb service is maybe available
host_notify_timer_.cancel();
host_notify_timer_.expires_from_now(default_adb_wait_time); host_notify_timer_.expires_from_now(default_adb_wait_time);
host_notify_timer_.async_wait( host_notify_timer_.async_wait([this](const boost::system::error_code &err) {
[&](const boost::system::error_code &) { wait_for_host_connection(); }); if (err)
return;
wait_for_host_connection();
});
} }
} }
@ -148,15 +160,13 @@ void AdbMessageProcessor::on_host_connection(std::shared_ptr<boost::asio::basic_
void AdbMessageProcessor::read_next_host_message() { void AdbMessageProcessor::read_next_host_message() {
auto callback = std::bind(&AdbMessageProcessor::on_host_read_size, this, _1, _2); auto callback = std::bind(&AdbMessageProcessor::on_host_read_size, this, _1, _2);
host_messenger_->async_receive_msg(callback, host_messenger_->async_receive_msg(callback, boost::asio::buffer(host_buffer_));
boost::asio::buffer(host_buffer_));
} }
void AdbMessageProcessor::on_host_read_size( void AdbMessageProcessor::on_host_read_size(const boost::system::error_code &error, std::size_t bytes_read) {
const boost::system::error_code &error, std::size_t bytes_read) {
if (error) { if (error) {
state_ = closed_by_host; state_ = closed_by_host;
BOOST_THROW_EXCEPTION(std::runtime_error(error.message())); return;
} }
messenger_->send(reinterpret_cast<const char *>(host_buffer_.data()), bytes_read); messenger_->send(reinterpret_cast<const char *>(host_buffer_.data()), bytes_read);

View file

@ -27,6 +27,8 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <mutex>
namespace anbox { namespace anbox {
namespace qemu { namespace qemu {
class AdbMessageProcessor : public network::MessageProcessor { class AdbMessageProcessor : public network::MessageProcessor {
@ -66,6 +68,9 @@ class AdbMessageProcessor : public network::MessageProcessor {
std::shared_ptr<network::TcpSocketMessenger> host_messenger_; std::shared_ptr<network::TcpSocketMessenger> host_messenger_;
std::array<std::uint8_t, 8192> host_buffer_; std::array<std::uint8_t, 8192> host_buffer_;
boost::asio::deadline_timer host_notify_timer_; boost::asio::deadline_timer host_notify_timer_;
std::unique_lock<std::mutex> lock_;
static std::mutex active_instance_;
}; };
} // namespace graphics } // namespace graphics
} // namespace anbox } // namespace anbox

View file

@ -18,6 +18,7 @@
#ifndef ANBOX_QEMU_AT_PARSER_H_ #ifndef ANBOX_QEMU_AT_PARSER_H_
#define ANBOX_QEMU_AT_PARSER_H_ #define ANBOX_QEMU_AT_PARSER_H_
#include <functional>
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>

View file

@ -73,7 +73,7 @@ PipeConnectionCreator::PipeConnectionCreator(const std::shared_ptr<Renderer> &re
std::make_shared<network::Connections<network::SocketConnection>>()) { std::make_shared<network::Connections<network::SocketConnection>>()) {
} }
PipeConnectionCreator::~PipeConnectionCreator() { PipeConnectionCreator::~PipeConnectionCreator() noexcept {
connections_->clear(); connections_->clear();
} }

View file

@ -34,7 +34,7 @@ ConnectionCreator::ConnectionCreator(const std::shared_ptr<Runtime>& rt,
std::make_shared<network::Connections<network::SocketConnection>>()), std::make_shared<network::Connections<network::SocketConnection>>()),
message_processor_factory_(factory) {} message_processor_factory_(factory) {}
ConnectionCreator::~ConnectionCreator() {} ConnectionCreator::~ConnectionCreator() noexcept {}
void ConnectionCreator::create_connection_for( void ConnectionCreator::create_connection_for(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& std::shared_ptr<boost::asio::local::stream_protocol::socket> const&
@ -43,8 +43,7 @@ void ConnectionCreator::create_connection_for(
socket->close(); socket->close();
WARNING( WARNING(
"A second client tried to connect. Denied request as we already have " "A second client tried to connect. Denied request as we already have "
"one" "one and only allow a single client");
"and only allow a single client");
return; return;
} }

View file

@ -57,7 +57,7 @@ Runtime::Runtime(std::uint32_t pool_size)
strand_{service_}, strand_{service_},
keep_alive_{service_} {} keep_alive_{service_} {}
Runtime::~Runtime() { Runtime::~Runtime() noexcept(true) {
try { try {
stop(); stop();
} catch (...) { } catch (...) {

View file

@ -68,8 +68,7 @@ PlatformPolicy::PlatformPolicy(
window_size_immutable_ = true; window_size_immutable_ = true;
} }
display_info_.horizontal_resolution = display_frame.width(); graphics::emugl::DisplayInfo::get()->set_resolution(display_frame.width(), display_frame.height());
display_info_.vertical_resolution = display_frame.height();
pointer_ = input_manager->create_device(); pointer_ = input_manager->create_device();
pointer_->set_name("anbox-pointer"); pointer_->set_name("anbox-pointer");
@ -285,10 +284,6 @@ void PlatformPolicy::window_resized(const Window::Id &id,
} }
} }
DisplayManager::DisplayInfo PlatformPolicy::display_info() const {
return display_info_;
}
void PlatformPolicy::set_clipboard_data(const ClipboardData &data) { void PlatformPolicy::set_clipboard_data(const ClipboardData &data) {
if (data.text.empty()) if (data.text.empty())
return; return;

View file

@ -41,8 +41,7 @@ class Manager;
namespace ubuntu { namespace ubuntu {
class PlatformPolicy : public std::enable_shared_from_this<PlatformPolicy>, class PlatformPolicy : public std::enable_shared_from_this<PlatformPolicy>,
public platform::Policy, public platform::Policy,
public Window::Observer, public Window::Observer {
public DisplayManager {
public: public:
PlatformPolicy(const std::shared_ptr<input::Manager> &input_manager, PlatformPolicy(const std::shared_ptr<input::Manager> &input_manager,
const graphics::Rect &static_display_frame = graphics::Rect::Invalid, const graphics::Rect &static_display_frame = graphics::Rect::Invalid,
@ -61,8 +60,6 @@ class PlatformPolicy : public std::enable_shared_from_this<PlatformPolicy>,
void window_resized(const Window::Id &id, const std::int32_t &width, void window_resized(const Window::Id &id, const std::int32_t &width,
const std::int32_t &height) override; const std::int32_t &height) override;
DisplayInfo display_info() const override;
void set_renderer(const std::shared_ptr<Renderer> &renderer); void set_renderer(const std::shared_ptr<Renderer> &renderer);
void set_window_manager(const std::shared_ptr<wm::Manager> &window_manager); void set_window_manager(const std::shared_ptr<wm::Manager> &window_manager);
@ -89,7 +86,6 @@ class PlatformPolicy : public std::enable_shared_from_this<PlatformPolicy>,
bool event_thread_running_; bool event_thread_running_;
std::shared_ptr<input::Device> pointer_; std::shared_ptr<input::Device> pointer_;
std::shared_ptr<input::Device> keyboard_; std::shared_ptr<input::Device> keyboard_;
DisplayManager::DisplayInfo display_info_;
bool window_size_immutable_ = false; bool window_size_immutable_ = false;
bool single_window_ = false; bool single_window_ = false;
}; };

View file

@ -0,0 +1,90 @@
/*
* Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/ui/splash_screen.h"
#include "anbox/config.h"
#include "anbox/utils.h"
#include <SDL2/SDL_image.h>
namespace anbox {
namespace ui {
SplashScreen::SplashScreen() {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
const auto message = utils::string_format("Failed to initialize SDL: %s", SDL_GetError());
BOOST_THROW_EXCEPTION(std::runtime_error(message));
}
const auto width = 1024, height = 768;
window_ = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
if (!window_) {
const auto message = utils::string_format("Failed to create window: %s", SDL_GetError());
BOOST_THROW_EXCEPTION(std::runtime_error(message));
}
auto surface = SDL_GetWindowSurface(window_);
if (!surface)
BOOST_THROW_EXCEPTION(std::runtime_error("Could not retrieve surface for our window"));
SDL_FillRect(surface, nullptr, SDL_MapRGB(surface->format, 0xee, 0xee, 0xee));
SDL_UpdateWindowSurface(window_);
auto renderer = SDL_CreateRenderer(window_, -1, SDL_RENDERER_ACCELERATED);
if (!renderer)
BOOST_THROW_EXCEPTION(std::runtime_error("Could not create renderer"));
const auto icon_path = utils::string_format("%s/ui/loading-screen.png", SystemConfiguration::instance().resource_dir());
auto img = IMG_LoadTexture(renderer, icon_path.c_str());
if (!img) {
const auto msg = utils::string_format("Failed to create texture from %s", icon_path);
BOOST_THROW_EXCEPTION(std::runtime_error(msg));
}
SDL_RenderClear(renderer);
SDL_Rect r{0, 0, width, height};
SDL_RenderCopy(renderer, img, nullptr, &r);
SDL_RenderPresent(renderer);
SDL_ShowWindow(window_);
event_thread_ = std::thread(&SplashScreen::process_events, this);
}
SplashScreen::~SplashScreen() {
if (event_thread_running_) {
event_thread_running_ = false;
if (event_thread_.joinable())
event_thread_.join();
}
if (window_)
SDL_DestroyWindow(window_);
}
void SplashScreen::process_events() {
event_thread_running_ = true;
while (event_thread_running_) {
SDL_Event event;
while (SDL_WaitEventTimeout(&event, 100)) {
// Keep running until we're terminated
}
}
}
} // namespace ui
} // namespace anbox

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2017 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_UI_SPLASH_SCREEN_H_
#define ANBOX_UI_SPLASH_SCREEN_H_
#include <thread>
#include <SDL2/SDL.h>
namespace anbox {
namespace ui {
class SplashScreen {
public:
SplashScreen();
~SplashScreen();
private:
void process_events();
std::thread event_thread_;
bool event_thread_running_;
SDL_Window *window_;
};
} // namespace ui
} // namespace anbox
#endif

Some files were not shown because too many files have changed in this diff Show more