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.
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
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
**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:**
**Expected:**
**What were you expecting?:**
**Additional info:**

View file

@ -64,9 +64,11 @@ find_package(GLESv2 REQUIRED)
find_package(Protobuf 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 dbus-1 REQUIRED)
pkg_check_modules(LXC lxc REQUIRED)
pkg_check_modules(PROPERTIES_CPP properties-cpp REQUIRED)
pkg_check_modules(MIRCLIENT mirclient)
if (MIRCLIENT_FOUND)
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(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(src)
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_CXX_COMPILER}")
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 is container based approach to boot a full Android system on a
regular GNU Linux system like Ubuntu.
Anbox is a container-based approach to boot a full Android system on a
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
Anbox uses Linux namespaces (user, pid, uts, net, mount, ipc) to run a
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.
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
GL ES accelerated rendering. The Android system inside the container uses
reusing what Android implemented within the QEMU-based emulator for OpenGL
ES accelerated rendering. The Android system inside the container uses
different pipes to communicate with the host system and sends all hardware
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-thread-dev libcap-dev libdbus-1-dev libdbus-cpp-dev libegl1-mesa-dev \
libgles2-mesa-dev libglib2.0-dev libglm-dev libgtest-dev liblxc1 \
libproperties-cpp-dev libprotobuf-dev libsdl2-dev lxc-dev pkg-config \
protobuf-compiler
libproperties-cpp-dev libprotobuf-dev libsdl2-dev libsdl2-image-dev lxc-dev \
pkg-config protobuf-compiler
```
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)
documentation.
An alias will save typing later.
```
$ alias android='anbox launch --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity'
$ alias android >> ~/.bashrc
$ android
$ anbox launch --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity'
```
## documentation
## Documentation
You will find additional documentation for Anbox in the *docs* subdirectory
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
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
@ -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
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.

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
[Service]
Type=simple
ExecStart=@SNAP_MOUNT_DIR@/anbox session-manager
Restart=always
StartLimitIntervalSec=3
StartLimitBurst=1
[Install]
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
usr/share/upstart/sessions/anbox.conf
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
* 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
Architecture: all
Depends: ${misc:Depends}
Depends: ${misc:Depends}, dbus-user-session
Description: Common files necessary for Anbox
.
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 -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/
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 -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
When all sources are successfully downloaded you can start building Android
itself. Initialize the build by
When all sources are successfully downloaded you can start building Android itself.
Firstly initialize the environment with the ```envsetup.sh``` script.
```
$ . build/envsetup.sh
```
Then initialize the build using ```lunch```.
```
$ lunch anbox_desktop_x86_64-userdebug
@ -43,7 +50,7 @@ $ lunch anbox_desktop_x86_64-userdebug
The complete list of supported build targets:
* anbox_desktop_x86_64-userdebug
* anbox_desktop_armv7a_arm-userdebug
* anbox_desktop_armv7a_neon-userdebug
* anbox_desktop_arm64-userdebug
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}")
endif()
add_library(GLESv1_dec ${SOURCES} ${GENERATED_SOURCES})
add_library(GLESv1_dec STATIC ${SOURCES} ${GENERATED_SOURCES})
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}")
endif()
add_library(GLESv2_dec ${SOURCES} ${GENERATED_SOURCES})
add_library(GLESv2_dec STATIC ${SOURCES} ${GENERATED_SOURCES})
target_link_libraries(GLESv2_dec OpenglCodecCommon)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -114,6 +114,12 @@ public:
*/
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
/**
* @brief Access this process's stderr.

View file

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

View file

@ -303,7 +303,7 @@ struct ChildProcess::Private
~Private()
{
// 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, we kill the original child.
@ -333,6 +333,8 @@ struct ChildProcess::Private
// is called from the child process.
pid_t original_parent_pid;
pid_t original_child_pid;
bool dont_kill_on_cleanup = false;
};
ChildProcess ChildProcess::invalid()
@ -395,6 +397,11 @@ wait::Result ChildProcess::wait_for(const wait::Flags& flags)
return result;
}
void ChildProcess::dont_kill_on_cleanup()
{
d->dont_kill_on_cleanup = true;
}
#ifndef ANDROID
std::istream& ChildProcess::cerr()
{

View file

@ -11,7 +11,7 @@ include_directories(
${Boost_INCLUDE_DIRS}
)
add_library(xdg xdg.cpp)
add_library(xdg STATIC xdg.cpp)
set_property(TARGET xdg PROPERTY CXX_STANDARD 11)
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_dirs{"XDG_CONFIG_DIRS"};
constexpr const char* xdg_cache_home{"XDG_CACHE_HOME"};
constexpr const char* xdg_runtime_dir{"XDG_RUNTIME_DIR"};
}
namespace impl

View file

@ -1,7 +1,7 @@
PACKAGE_NAME="anbox-ashmem"
PACKAGE_VERSION="1"
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"
DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes"

View file

@ -1,7 +1,7 @@
PACKAGE_NAME="anbox-binder"
PACKAGE_VERSION="1"
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"
DEST_MODULE_LOCATION[0]="/updates"
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.
# 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"
varlib="/var/lib/anbox"
BRIDGE="anboxbr0"
BRIDGE="anbox0"
# IPv4
IPV4_ADDR="10.0.6.1"
IPV4_ADDR="192.168.250.1"
IPV4_NETMASK="255.255.255.0"
IPV4_NETWORK="10.0.6.1/24"
IPV4_DHCP_RANGE="10.0.6.2,10.0.6.254"
IPV4_DHCP_MAX="252"
IPV4_NETWORK="192.168.250.1/24"
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"
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 () {
# Assumes there's no "255." after a non-255 byte in the mask
local x=${1##*255.}
@ -88,11 +75,6 @@ start() {
# set up the anbox network
[ ! -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,
# 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)
@ -103,13 +85,6 @@ start() {
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}"
IPV4_ARG=""
@ -118,25 +93,6 @@ start() {
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"
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
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}" -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"
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"
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
ls /sys/class/net/${BRIDGE}/brif/* > /dev/null 2>&1 || ip link delete "${BRIDGE}"
fi

View file

@ -32,6 +32,7 @@ apt-get install -qq -y \
libproperties-cpp-dev \
libprotobuf-dev \
libsdl2-dev \
libsdl2-image-dev \
lxc-dev \
pkg-config \
protobuf-compiler
@ -40,14 +41,26 @@ apt-get clean
cd /anbox
# In cases where anbox comes directly from a checked out Android
# build environment we miss some symlinks which are present on
# the host and don't have a valid git repository in that case.
git clean -fdx . || true
git reset --hard || true
cleanup() {
# In cases where anbox comes directly from a checked out Android
# build environment we miss some symlinks which are present on
# the host and don't have a valid git repository in that case.
if [ -d .git ] ; then
git clean -fdx .
git reset --hard
fi
}
cleanup
mkdir build || rm -rf build/*
cd build
cmake ..
make -j10
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 \
--data-path=$DATA_PATH \
--android-image=$ANDROID_IMG
--android-image=$ANDROID_IMG \
--daemon
}
stop() {

View file

@ -29,6 +29,12 @@ export LIBGL_DRIVERS_PATH=$SNAP/usr/lib/$ARCH/dri
# ensure the snappy gl libs win
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
# create all our application launchers in. The system application launcher will
# be configured by our installer to look into this directory for available

View file

@ -1,5 +1,11 @@
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
description: |
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
# that is fixed we can avoid using a prefix here.
- -DCMAKE_INSTALL_PREFIX:PATH=/usr
- -DANBOX_VERSION=$SNAPCRAFT_PROJECT_VERSION
build-packages:
- build-essential
- cmake
@ -111,6 +118,7 @@ parts:
- libprotobuf-dev
- libproperties-cpp-dev
- libsdl2-dev
- libsdl2-image-dev
- pkg-config
- protobuf-compiler
stage-packages:
@ -123,4 +131,5 @@ parts:
make test
prime:
- usr/bin/anbox
- usr/share/anbox
- usr/lib/*-linux-*/

View file

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

View file

@ -21,17 +21,32 @@
namespace anbox {
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) {
out << "["
<< "action=" << intent.action << " "
<< "uri=" << intent.uri << " "
<< "type=" << intent.type << " "
<< "flags=" << intent.flags << " "
<< "package=" << intent.package << " "
<< "component=" << intent.component << " "
<< "categories=[ ";
for (const auto &category : intent.categories) out << category << " ";
out << "]]";
out << "[";
if (!intent.action.empty())
out << " " << "action=" << intent.action << " ";
if (!intent.uri.empty())
out << " " << "uri=" << intent.uri << " ";
if (!intent.type.empty())
out << " " << "type=" << intent.type << " ";
if (intent.flags > 0)
out << " " << "flags=" << intent.flags << " ";
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;
}
} // namespace android

View file

@ -31,6 +31,8 @@ struct Intent {
std::string package;
std::string component;
std::vector<std::string> categories;
bool valid() const;
};
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_
#define ANBOX_BRIDGE_PLATFORM_SERVER_H_
#include <functional>
#include <memory>
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,
std::uint32_t& patch) {
major = anbox::build::version_major;
minor = anbox::build::version_minor;
patch = anbox::build::version_patch;
}
#include <cstdint>
#include <string>
namespace anbox {
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"},
cli::Description{"Run Android container in privileged mode"},
privileged_));
flag(cli::make_flag(cli::Name{"daemon"},
cli::Description{"Mark service as being started as systemd daemon"},
daemon_));
action([&](const cli::Command::Context&) {
try {
if (getuid() != 0) {
ERROR("You're not running the container-manager as root. Generally you don't");
if (!daemon_) {
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("as it is started by the init system of your operating system.");
return EXIT_FAILURE;
@ -68,6 +79,9 @@ anbox::cmds::ContainerManager::ContainerManager()
if (!data_path_.empty())
SystemConfiguration::instance().set_data_path(data_path_);
if (!fs::exists(data_path_))
fs::create_directories(data_path_);
if (!setup_mounts())
return EXIT_FAILURE;

View file

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

View file

@ -19,6 +19,8 @@
#include "anbox/common/wait_handle.h"
#include "anbox/dbus/stub/application_manager.h"
#include "anbox/common/dispatcher.h"
#include "anbox/ui/splash_screen.h"
#include "anbox/config.h"
#include "anbox/runtime.h"
#include "anbox/logger.h"
@ -26,12 +28,31 @@
#include <boost/filesystem.hpp>
#include "core/posix/exec.h"
#include "core/posix/fork.h"
#include "core/posix/signal.h"
namespace fs = boost::filesystem;
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()
@ -58,6 +79,11 @@ anbox::cmds::Launch::Launch()
stack_));
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});
trap->signal_raised().connect([trap](const core::posix::Signal& 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);
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;
try {
stub = dbus::stub::ApplicationManager::create_for_bus(bus);
} catch (...) {
ERROR("Anbox session manager service isn't running!");
for (auto n = 0; n < max_restart_attempts; n++) {
try {
stub = dbus::stub::ApplicationManager::create_for_bus(bus);
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;
}
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
bool success = false;
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
dispatcher->dispatch([&]() {
if (stub->ready()) {
try {
stub->launch(intent_, graphics::Rect::Invalid, stack_);
success = true;
} catch (std::exception &err) {
ERROR("err %s", err.what());
}
ss.reset();
success = try_launch_activity(stub);
trap->stop();
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) {
if (!ready)
return;
try {
stub->launch(intent_, graphics::Rect::Invalid, stack_);
success = true;
} catch (std::exception &err) {
ERROR("Failed to launch activity: %s", err.what());
success = false;
}
ss.reset();
success = try_launch_activity(stub);
trap->stop();
});
});
@ -112,8 +191,10 @@ anbox::cmds::Launch::Launch()
boost::asio::deadline_timer timer(rt->service());
timer.expires_from_now(max_wait_timeout);
timer.async_wait([&](const boost::system::error_code&) {
WARNING("Stop waiting as we're already waiting for too long. Something is wrong");
WARNING("with your setup and the container may have failed to boot.");
WARNING("Stopped waiting as we've already waited for too long. Something");
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();
});

View file

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

View file

@ -27,12 +27,17 @@
#include "anbox/bridge/android_api_stub.h"
#include "anbox/bridge/platform_api_skeleton.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/common/dispatcher.h"
#include "anbox/config.h"
#include "anbox/container/client.h"
#include "anbox/dbus/skeleton/service.h"
#include "anbox/graphics/gl_renderer_server.h"
#include "anbox/input/manager.h"
#include "anbox/logger.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"},
cli::Description{"Size of the window in single window mode, e.g. --window-size=1024,768"},
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 &) {
auto trap = core::posix::trap_signals_for_process(
@ -115,6 +126,11 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
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")) {
ERROR("Failed to start as either binder or ashmem kernel drivers are not loaded");
return EXIT_FAILURE;
@ -135,11 +151,13 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
auto rt = Runtime::create();
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
container::Client container(rt);
container.register_terminate_handler([&]() {
WARNING("Lost connection to container manager, terminating.");
trap->stop();
});
if (!standalone_) {
container_ = std::make_shared<container::Client>(rt);
container_->register_terminate_handler([&]() {
WARNING("Lost connection to container manager, terminating.");
trap->stop();
});
}
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_;
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>();
@ -213,7 +229,8 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
}));
container::Configuration container_configuration;
container_configuration.bind_mounts = {
if (!standalone_) {
container_configuration.bind_mounts = {
{qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"},
{bridge_connector->socket_file(), "/dev/anbox_bridge"},
{audio_server->socket_file(), "/dev/anbox_audio"},
@ -221,9 +238,10 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
{"/dev/binder", "/dev/binder"},
{"/dev/ashmem", "/dev/ashmem"},
{"/dev/fuse", "/dev/fuse"},
};
};
dispatcher->dispatch([&]() { container.start(container_configuration); });
dispatcher->dispatch([&]() { container_->start(container_configuration); });
}
auto bus = bus_factory_();
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();
trap->run();
// Stop the container which should close all open connections we have on
// our side and should terminate all services.
container.stop();
if (!standalone_) {
// Stop the container which should close all open connections we have on
// our side and should terminate all services.
container_->stop();
}
rt->stop();

View file

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

View file

@ -19,9 +19,9 @@
#include "anbox/graphics/emugl/RenderApi.h"
#include "anbox/graphics/emugl/DispatchTables.h"
#include "anbox/utils/environment_file.h"
#include "anbox/version.h"
#include "anbox/logger.h"
#include "anbox/version.h"
#include "anbox/build/version.h"
#include <sstream>
#include <fstream>
@ -34,9 +34,12 @@ namespace fs = boost::filesystem;
namespace {
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 *binder_path{"/dev/binder"};
constexpr const char *ashmem_path{"/dev/ashmem"};
constexpr const char *os_release_name{"NAME"};
constexpr const char *os_release_version{"VERSION"};
class SystemInformation {
public:
@ -50,12 +53,15 @@ class SystemInformation {
std::stringstream s;
s << "version: "
<< anbox::utils::string_format("%d.%d.%d",
anbox::build::version_major,
anbox::build::version_minor,
anbox::build::version_patch)
<< anbox::build::print_version()
<< 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
<< " name: " << os_info_.name << std::endl
<< " version: " << os_info_.version << std::endl
@ -96,15 +102,19 @@ class SystemInformation {
private:
void collect_os_info() {
os_info_.snap_based = (getenv("SNAP") != nullptr);
if (fs::exists(os_release_path)) {
anbox::utils::EnvironmentFile os_release(os_release_path);
os_info_.name = os_release.value("NAME");
os_info_.version = os_release.value("VERSION");
} else if (os_info_.snap_based) {
// As we can't read /etc/os-release and we're snap-based this is the best we can guess
os_info_.name = "Ubuntu";
os_info_.version = "16";
os_info_.snap_based = !anbox::utils::get_env_value("SNAP").empty();
fs::path path = os_release_path;
// If we're running from within a snap the best we can do is to
// access the hostfs and read the os-release file from there.
if (os_info_.snap_based && fs::exists(host_os_release_path))
path = host_os_release_path;
// Double check that there aren't any permission errors when trying
// 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/version.h"
#include "anbox/build/version.h"
#include "anbox/utils.h"
anbox::cmds::Version::Version()
: CommandWithFlagsAndAction{
cli::Name{"version"}, cli::Usage{"version"},
cli::Description{"print the version of the daemon"}} {
action([](const cli::Command::Context& ctxt) {
std::uint32_t major, minor, patch;
anbox::version(major, minor, patch);
ctxt.cout << "anbox " << major << "." << minor << "." << patch << std::endl;
ctxt.cout << "anbox " << build::print_version() << std::endl;
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;
}
void anbox::SystemConfiguration::set_resource_path(const fs::path &path) {
resource_path = path;
}
fs::path anbox::SystemConfiguration::data_dir() const {
return data_path;
}
@ -76,6 +80,10 @@ std::string anbox::SystemConfiguration::application_item_dir() const {
return dir.string();
}
std::string anbox::SystemConfiguration::resource_dir() const {
return resource_path.string();
}
anbox::SystemConfiguration& anbox::SystemConfiguration::instance() {
static SystemConfiguration config;
return config;

View file

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

View file

@ -15,6 +15,7 @@
*
*/
#include "anbox/android/ip_config_builder.h"
#include "anbox/container/lxc_container.h"
#include "anbox/config.h"
#include "anbox/logger.h"
@ -22,6 +23,7 @@
#include <map>
#include <stdexcept>
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/throw_exception.hpp>
@ -30,9 +32,20 @@
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
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 container {
LxcContainer::LxcContainer(bool privileged, const network::Credentials &creds)
@ -49,8 +62,7 @@ LxcContainer::~LxcContainer() {
}
void LxcContainer::setup_id_maps() {
// FIXME make these id sets configurable
const auto base_id = 100000;
const auto base_id = unprivileged_user_id;
const auto max_id = 65536;
set_config_item("lxc.id_map",
@ -76,6 +88,75 @@ void LxcContainer::setup_id_maps() {
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) {
if (getuid() != 0)
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();
set_config_item("lxc.logfile", utils::string_format("%s/container.log", log_path).c_str());
if (fs::exists("/sys/class/net/anboxbr0")) {
set_config_item("lxc.network.type", "veth");
set_config_item("lxc.network.flags", "up");
set_config_item("lxc.network.link", "anboxbr0");
}
setup_network();
#if 0
// 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:
void set_config_item(const std::string &key, const std::string &value);
void setup_id_maps();
void setup_network();
State state_;
lxc_container *container_;

View file

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

View file

@ -25,7 +25,7 @@ namespace dbus {
namespace stub {
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 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);
}

View file

@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* 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 "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
#include <stdio.h>
namespace {
@ -35,22 +34,6 @@ inline void* SafePointerFromUInt(unsigned int 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.
// |fbo| is the address of the framebuffer object name.
// |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() {
RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
if (!tInfo->currContext) {
// no Current context
return false;
}
@ -312,7 +295,7 @@ bool ColorBuffer::bindToTexture() {
return false;
}
RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
if (!tInfo->currContext) {
return false;
}
if (tInfo->currContext->isGL2()) {
@ -328,7 +311,7 @@ bool ColorBuffer::bindToRenderbuffer() {
return false;
}
RenderThreadInfo* tInfo = RenderThreadInfo::get();
if (!tInfo->currContext.Ptr()) {
if (!tInfo->currContext) {
return false;
}
if (tInfo->currContext->isGL2()) {

View file

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

View file

@ -17,22 +17,22 @@
#include "DisplayManager.h"
namespace {
std::shared_ptr<DisplayManager> display_mgr;
class NullDisplayManager : public DisplayManager {
public:
DisplayInfo display_info() const override { return {1280, 720}; }
};
namespace anbox {
namespace graphics {
namespace emugl {
std::shared_ptr<DisplayInfo> DisplayInfo::get() {
static auto info = std::make_shared<DisplayInfo>();
return info;
}
DisplayManager::~DisplayManager() {}
std::shared_ptr<DisplayManager> DisplayManager::get() {
if (!display_mgr) display_mgr = std::make_shared<NullDisplayManager>();
return display_mgr;
void DisplayInfo::set_resolution(const std::uint32_t &vertical, const std::uint32_t horizontal) {
vertical_resolution_ = vertical;
horizontal_resolution_ = horizontal;
}
void registerDisplayManager(const std::shared_ptr<DisplayManager> &mgr) {
display_mgr = mgr;
}
std::uint32_t DisplayInfo::vertical_resolution() const { return vertical_resolution_; }
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_
#define DISPLAY_MANAGER_H_
#ifndef ANBOX_GRAPHICS_EMUGL_DISPLAY_INFO_H_
#define ANBOX_GRAPHICS_EMUGL_DISPLAY_INFO_H_
#include <cstdint>
#include <memory>
class DisplayManager {
namespace anbox {
namespace graphics {
namespace emugl {
class DisplayInfo {
public:
virtual ~DisplayManager();
DisplayInfo() = default;
struct DisplayInfo {
int horizontal_resolution;
int vertical_resolution;
};
static std::shared_ptr<DisplayInfo> get();
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;
};
void registerDisplayManager(const std::shared_ptr<DisplayManager> &mgr);
} // namespace emugl
} // namespace graphics
} // namespace anbox
#endif

View file

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

View file

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

View file

@ -14,15 +14,14 @@
* 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 "OpenGLESDispatch/GLESv1Dispatch.h"
#include "OpenGLESDispatch/GLESv2Dispatch.h"
#include "emugl/common/crash_reporter.h"
#include "external/android-emugl/shared/emugl/common/crash_reporter.h"
#include <string.h>

View file

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

View file

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

View file

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

View file

@ -13,20 +13,20 @@
* See the License for the specific language governing permissions and
* 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/logger.h"
#include "external/android-emugl/shared/OpenglCodecCommon/ChecksumCalculatorThreadInfo.h"
#include "external/android-emugl/host/include/OpenGLESDispatch/EGLDispatch.h"
#include <map>
#include <string>
@ -169,10 +169,10 @@ static EGLint rcGetFBParam(EGLint param) {
switch (param) {
case FB_WIDTH:
ret = DisplayManager::get()->display_info().horizontal_resolution;
ret = static_cast<EGLint>(anbox::graphics::emugl::DisplayInfo::get()->vertical_resolution());
break;
case FB_HEIGHT:
ret = DisplayManager::get()->display_info().vertical_resolution;
ret = static_cast<EGLint>(anbox::graphics::emugl::DisplayInfo::get()->horizontal_resolution());
break;
case FB_XDPI:
ret = 72; // XXX: should be implemented
@ -360,12 +360,12 @@ int rcGetNumDisplays() {
int rcGetDisplayWidth(uint32_t 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) {
(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) {

View file

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

View file

@ -13,32 +13,31 @@
* See the License for the specific language governing permissions and
* 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 "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
RenderThread::RenderThread(const std::shared_ptr<Renderer> &renderer, IOStream *stream, emugl::Mutex *lock)
: emugl::Thread(), renderer_(renderer), m_lock(lock), m_stream(stream) {}
RenderThread::RenderThread(const std::shared_ptr<Renderer> &renderer, IOStream *stream, std::mutex &m)
: emugl::Thread(), renderer_(renderer), m_lock(m), m_stream(stream) {}
RenderThread::~RenderThread() {
forceStop();
}
RenderThread *RenderThread::create(const std::shared_ptr<Renderer> &renderer, IOStream *stream, emugl::Mutex *lock) {
return new RenderThread(renderer, stream, lock);
RenderThread *RenderThread::create(const std::shared_ptr<Renderer> &renderer, IOStream *stream, std::mutex &m) {
return new RenderThread(renderer, stream, m);
}
void RenderThread::forceStop() { m_stream->forceStop(); }
@ -62,7 +61,8 @@ intptr_t RenderThread::main() {
do {
progress = false;
m_lock->lock();
std::unique_lock<std::mutex> l(m_lock);
size_t last =
threadInfo.m_glDec.decode(readBuf.buf(), readBuf.validData(), m_stream);
if (last > 0) {
@ -83,8 +83,6 @@ intptr_t RenderThread::main() {
progress = true;
}
m_lock->unlock();
} while (progress);
}

View file

@ -13,15 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _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 <memory>
#include <mutex>
class Renderer;
@ -36,7 +37,7 @@ class RenderThread : public emugl::Thread {
// decoding operations between all threads.
// TODO(digit): Why is this needed here? Shouldn't this be handled
// 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.
virtual ~RenderThread();
@ -51,12 +52,12 @@ class RenderThread : public emugl::Thread {
private:
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();
std::shared_ptr<Renderer> renderer_;
emugl::Mutex* m_lock;
std::mutex &m_lock;
IOStream* m_stream;
};

View file

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

View file

@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIB_OPENGL_RENDER_THREAD_INFO_H
#define _LIB_OPENGL_RENDER_THREAD_INFO_H
#include "GLESv1Decoder.h"
#include "GLESv2Decoder.h"
#include "RenderContext.h"
#include "WindowSurface.h"
#include "anbox/graphics/emugl/RenderContext.h"
#include "anbox/graphics/emugl/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 <set>

View file

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

View file

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

View file

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

View file

@ -12,15 +12,14 @@
// See the License for the specific language governing permissions and
// 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 <string.h>
#include "anbox/logger.h"
namespace {
const GLuint kConfigAttributes[] = {
EGL_DEPTH_SIZE, // must be first - see getDepthSize()

View file

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

View file

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

View file

@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* 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 <sstream>
#include <string>
#include <utility>
#include "anbox/logger.h"
#define MAX_FACTOR_POWER 4
static const char kCommonShaderSource[] =

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -29,7 +29,7 @@
namespace anbox {
namespace graphics {
emugl::Mutex OpenGlesMessageProcessor::global_lock{};
std::mutex OpenGlesMessageProcessor::global_lock{};
OpenGlesMessageProcessor::OpenGlesMessageProcessor(
const std::shared_ptr<Renderer> &renderer,
@ -43,7 +43,7 @@ OpenGlesMessageProcessor::OpenGlesMessageProcessor(
boost::asio::buffer(&client_flags, sizeof(unsigned int)));
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())
BOOST_THROW_EXCEPTION(
std::runtime_error("Failed to start renderer thread"));

View file

@ -18,16 +18,15 @@
#ifndef 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/socket_connection.h"
#include "anbox/network/socket_messenger.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 RenderThread;
@ -45,7 +44,7 @@ class OpenGlesMessageProcessor : public network::MessageProcessor {
bool process_data(const std::vector<std::uint8_t> &data) override;
private:
static emugl::Mutex global_lock;
static std::mutex global_lock;
std::shared_ptr<network::SocketMessenger> messenger_;
std::shared_ptr<IOStream> stream_;

View file

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

View file

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

View file

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

View file

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

View file

@ -16,10 +16,10 @@
*/
#include "anbox/qemu/adb_message_processor.h"
#include "anbox/logger.h"
#include "anbox/network/delegate_connection_creator.h"
#include "anbox/network/delegate_message_processor.h"
#include "anbox/network/tcp_socket_messenger.h"
#include "anbox/utils.h"
#include <fstream>
#include <functional>
@ -27,18 +27,23 @@
namespace {
const unsigned short default_adb_client_port{5037};
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 ok_command{"ok"};
const std::string ko_command{"ko"};
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};
static std::mutex active_instance;
}
using namespace std::placeholders;
namespace anbox {
namespace qemu {
std::mutex AdbMessageProcessor::active_instance_{};
AdbMessageProcessor::AdbMessageProcessor(
const std::shared_ptr<Runtime> &rt,
const std::shared_ptr<network::SocketMessenger> &messenger)
@ -46,12 +51,14 @@ AdbMessageProcessor::AdbMessageProcessor(
state_(waiting_for_guest_accept_command),
expected_command_(accept_command),
messenger_(messenger),
host_notify_timer_(rt->service()) {}
host_notify_timer_(rt->service()),
lock_(active_instance_, std::defer_lock) {}
AdbMessageProcessor::~AdbMessageProcessor() {
state_ = closed_by_host;
host_notify_timer_.cancel();
host_connector_.reset();
active_instance.unlock();
}
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.
// The container directly starts a second connection once the first
// one is established but will not use it until the active one is closed.
active_instance.lock();
lock_.lock();
if (state_ == closed_by_host) {
host_notify_timer_.cancel();
host_connector_.reset();
return;
}
@ -100,9 +108,12 @@ void AdbMessageProcessor::advance_state() {
}
void AdbMessageProcessor::wait_for_host_connection() {
if (state_ == closed_by_host || state_ == closed_by_container)
return;
if (!host_connector_) {
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_,
std::make_shared<
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
// proxy is waiting for incoming connections.
auto messenger = std::make_shared<network::TcpSocketMessenger>(
boost::asio::ip::address_v4::from_string("127.0.0.1"),
default_adb_client_port, runtime_);
auto message =
utils::string_format("host:emulator:%d", default_host_listen_port);
auto handshake =
utils::string_format("%04x%s", message.size(), message.c_str());
boost::asio::ip::address_v4::from_string(loopback_address), default_adb_client_port, runtime_);
auto message = 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());
} catch (std::exception &) {
} catch (...) {
// 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_.async_wait(
[&](const boost::system::error_code &) { wait_for_host_connection(); });
host_notify_timer_.async_wait([this](const boost::system::error_code &err) {
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() {
auto callback = std::bind(&AdbMessageProcessor::on_host_read_size, this, _1, _2);
host_messenger_->async_receive_msg(callback,
boost::asio::buffer(host_buffer_));
host_messenger_->async_receive_msg(callback, boost::asio::buffer(host_buffer_));
}
void AdbMessageProcessor::on_host_read_size(
const boost::system::error_code &error, std::size_t bytes_read) {
void AdbMessageProcessor::on_host_read_size(const boost::system::error_code &error, std::size_t bytes_read) {
if (error) {
state_ = closed_by_host;
BOOST_THROW_EXCEPTION(std::runtime_error(error.message()));
return;
}
messenger_->send(reinterpret_cast<const char *>(host_buffer_.data()), bytes_read);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -68,8 +68,7 @@ PlatformPolicy::PlatformPolicy(
window_size_immutable_ = true;
}
display_info_.horizontal_resolution = display_frame.width();
display_info_.vertical_resolution = display_frame.height();
graphics::emugl::DisplayInfo::get()->set_resolution(display_frame.width(), display_frame.height());
pointer_ = input_manager->create_device();
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) {
if (data.text.empty())
return;

View file

@ -41,8 +41,7 @@ class Manager;
namespace ubuntu {
class PlatformPolicy : public std::enable_shared_from_this<PlatformPolicy>,
public platform::Policy,
public Window::Observer,
public DisplayManager {
public Window::Observer {
public:
PlatformPolicy(const std::shared_ptr<input::Manager> &input_manager,
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,
const std::int32_t &height) override;
DisplayInfo display_info() const override;
void set_renderer(const std::shared_ptr<Renderer> &renderer);
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_;
std::shared_ptr<input::Device> pointer_;
std::shared_ptr<input::Device> keyboard_;
DisplayManager::DisplayInfo display_info_;
bool window_size_immutable_ = 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