diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 6c04d72..1881bb6 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -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:**
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 957664b..c6432a1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
+
diff --git a/README.md b/README.md
index 4d28005..eeeb5d9 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,23 @@
+[](https://build.snapcraft.io/user/anbox/anbox)
+[](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.
diff --git a/cmake/FindGMock.cmake b/cmake/FindGMock.cmake
new file mode 100644
index 0000000..2078030
--- /dev/null
+++ b/cmake/FindGMock.cmake
@@ -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 .
+
+# 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)
diff --git a/data/anbox.service.in b/data/anbox.service.in
index 933b4d1..7cdd14f 100644
--- a/data/anbox.service.in
+++ b/data/anbox.service.in
@@ -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
diff --git a/data/ui/loading-screen.png b/data/ui/loading-screen.png
new file mode 100644
index 0000000..2678361
Binary files /dev/null and b/data/ui/loading-screen.png differ
diff --git a/debian/anbox-common.install b/debian/anbox-common.install
index 4700a8e..bf67a97 100644
--- a/debian/anbox-common.install
+++ b/debian/anbox-common.install
@@ -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
diff --git a/debian/changelog b/debian/changelog
index eccc558..a7152a9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -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 Sat, 29 Apr 2017 12:06:56 +0200
+
anbox (5) zesty; urgency=medium
* Rework packaging to also ship things we installed through the snap
diff --git a/debian/control b/debian/control
index 8696f8e..9dfb528 100644
--- a/debian/control
+++ b/debian/control
@@ -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
diff --git a/debian/rules b/debian/rules
index b141034..85b38d1 100755
--- a/debian/rules
+++ b/debian/rules
@@ -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/
diff --git a/docs/build-android.md b/docs/build-android.md
index 7f4b76e..cfd0a56 100644
--- a/docs/build-android.md
+++ b/docs/build-android.md
@@ -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
diff --git a/external/android-emugl/host/libs/GLESv1_dec/CMakeLists.txt b/external/android-emugl/host/libs/GLESv1_dec/CMakeLists.txt
index e8d83e2..c0b79af 100644
--- a/external/android-emugl/host/libs/GLESv1_dec/CMakeLists.txt
+++ b/external/android-emugl/host/libs/GLESv1_dec/CMakeLists.txt
@@ -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)
diff --git a/external/android-emugl/host/libs/GLESv2_dec/CMakeLists.txt b/external/android-emugl/host/libs/GLESv2_dec/CMakeLists.txt
index 140d061..6bd78c5 100644
--- a/external/android-emugl/host/libs/GLESv2_dec/CMakeLists.txt
+++ b/external/android-emugl/host/libs/GLESv2_dec/CMakeLists.txt
@@ -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)
diff --git a/external/android-emugl/host/libs/Translator/GLcommon/CMakeLists.txt b/external/android-emugl/host/libs/Translator/GLcommon/CMakeLists.txt
index 79339f6..9f553f9 100644
--- a/external/android-emugl/host/libs/Translator/GLcommon/CMakeLists.txt
+++ b/external/android-emugl/host/libs/Translator/GLcommon/CMakeLists.txt
@@ -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)
diff --git a/external/android-emugl/host/libs/libOpenGLESDispatch/CMakeLists.txt b/external/android-emugl/host/libs/libOpenGLESDispatch/CMakeLists.txt
index 715fa8b..c4bd232 100644
--- a/external/android-emugl/host/libs/libOpenGLESDispatch/CMakeLists.txt
+++ b/external/android-emugl/host/libs/libOpenGLESDispatch/CMakeLists.txt
@@ -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
diff --git a/external/android-emugl/host/libs/renderControl_dec/CMakeLists.txt b/external/android-emugl/host/libs/renderControl_dec/CMakeLists.txt
index cb67c5a..4b0786f 100644
--- a/external/android-emugl/host/libs/renderControl_dec/CMakeLists.txt
+++ b/external/android-emugl/host/libs/renderControl_dec/CMakeLists.txt
@@ -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)
diff --git a/external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt b/external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt
index 67606d7..fe3db64 100644
--- a/external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt
+++ b/external/android-emugl/shared/OpenglCodecCommon/CMakeLists.txt
@@ -12,4 +12,4 @@ set(SOURCES
Makefile
ProtocolUtils.h)
-add_library(OpenglCodecCommon ${SOURCES})
+add_library(OpenglCodecCommon STATIC ${SOURCES})
diff --git a/external/android-emugl/shared/emugl/common/CMakeLists.txt b/external/android-emugl/shared/emugl/common/CMakeLists.txt
index ef8b6d2..09388c6 100644
--- a/external/android-emugl/shared/emugl/common/CMakeLists.txt
+++ b/external/android-emugl/shared/emugl/common/CMakeLists.txt
@@ -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)
diff --git a/external/process-cpp-minimal/include/core/posix/child_process.h b/external/process-cpp-minimal/include/core/posix/child_process.h
index d6b3b31..fde7977 100644
--- a/external/process-cpp-minimal/include/core/posix/child_process.h
+++ b/external/process-cpp-minimal/include/core/posix/child_process.h
@@ -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.
diff --git a/external/process-cpp-minimal/src/CMakeLists.txt b/external/process-cpp-minimal/src/CMakeLists.txt
index 8daf938..dec4659 100644
--- a/external/process-cpp-minimal/src/CMakeLists.txt
+++ b/external/process-cpp-minimal/src/CMakeLists.txt
@@ -15,6 +15,8 @@
# Authored by: Thomas Voss
add_library(
process-cpp
+
+ STATIC
core/posix/backtrace.h
core/posix/backtrace.cpp
diff --git a/external/process-cpp-minimal/src/core/posix/child_process.cpp b/external/process-cpp-minimal/src/core/posix/child_process.cpp
index b121b89..ad16571 100644
--- a/external/process-cpp-minimal/src/core/posix/child_process.cpp
+++ b/external/process-cpp-minimal/src/core/posix/child_process.cpp
@@ -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()
{
diff --git a/external/xdg/CMakeLists.txt b/external/xdg/CMakeLists.txt
index f19f69d..249da48 100644
--- a/external/xdg/CMakeLists.txt
+++ b/external/xdg/CMakeLists.txt
@@ -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})
diff --git a/external/xdg/xdg.cpp b/external/xdg/xdg.cpp
index de9b043..d54fdfe 100644
--- a/external/xdg/xdg.cpp
+++ b/external/xdg/xdg.cpp
@@ -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
diff --git a/kernel/ashmem/dkms.conf b/kernel/ashmem/dkms.conf
index bde1557..715fa57 100644
--- a/kernel/ashmem/dkms.conf
+++ b/kernel/ashmem/dkms.conf
@@ -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"
diff --git a/kernel/binder/dkms.conf b/kernel/binder/dkms.conf
index 8484321..1b5fd7a 100644
--- a/kernel/binder/dkms.conf
+++ b/kernel/binder/dkms.conf
@@ -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"
diff --git a/kernel/patches/0001-ipc-namespace-a-generic-per-ipc-pointer-and-peripc_o.patch b/kernel/patches/0001-ipc-namespace-a-generic-per-ipc-pointer-and-peripc_o.patch
new file mode 100644
index 0000000..0acd5e9
--- /dev/null
+++ b/kernel/patches/0001-ipc-namespace-a-generic-per-ipc-pointer-and-peripc_o.patch
@@ -0,0 +1,185 @@
+From 8f8ac2552c4a411cf1b8c6328409f861248e8d0d Mon Sep 17 00:00:00 2001
+From: Oren Laadan
+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
+Signed-off-by: Amir Goldstein
+---
+ 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
+
diff --git a/kernel/patches/0002-binder-implement-namepsace-support-for-Android-binde.patch b/kernel/patches/0002-binder-implement-namepsace-support-for-Android-binde.patch
new file mode 100644
index 0000000..74595a0
--- /dev/null
+++ b/kernel/patches/0002-binder-implement-namepsace-support-for-Android-binde.patch
@@ -0,0 +1,428 @@
+From fcd9d70190dd7e6536878a6379122f06e3b90919 Mon Sep 17 00:00:00 2001
+From: Oren Laadan
+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
+Acked-by: Amir Goldstein
+---
+ 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
+ #include
+ #include
++#include
+ #include
+ #include
+
+@@ -47,19 +48,98 @@
+ #include
+ #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
+
diff --git a/scripts/anbox-bridge.sh b/scripts/anbox-bridge.sh
index e6793b5..46f34b7 100755
--- a/scripts/anbox-bridge.sh
+++ b/scripts/anbox-bridge.sh
@@ -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
diff --git a/scripts/clean-build.sh b/scripts/clean-build.sh
index b2de311..ab659bb 100755
--- a/scripts/clean-build.sh
+++ b/scripts/clean-build.sh
@@ -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
diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh
index 993a150..440f7ea 100755
--- a/scripts/container-manager.sh
+++ b/scripts/container-manager.sh
@@ -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() {
diff --git a/scripts/snap-wrapper.sh b/scripts/snap-wrapper.sh
index 0122ad3..0ca2d83 100755
--- a/scripts/snap-wrapper.sh
+++ b/scripts/snap-wrapper.sh
@@ -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
diff --git a/snapcraft.yaml b/snapcraft.yaml
index 0318ead..3ed6b2b 100644
--- a/snapcraft.yaml
+++ b/snapcraft.yaml
@@ -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-*/
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5675ccb..3fb6a7e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -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}
diff --git a/src/anbox/android/intent.cpp b/src/anbox/android/intent.cpp
index aa40f2c..1b7b0e3 100644
--- a/src/anbox/android/intent.cpp
+++ b/src/anbox/android/intent.cpp
@@ -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
diff --git a/src/anbox/android/intent.h b/src/anbox/android/intent.h
index a628f8f..57f2add 100644
--- a/src/anbox/android/intent.h
+++ b/src/anbox/android/intent.h
@@ -31,6 +31,8 @@ struct Intent {
std::string package;
std::string component;
std::vector categories;
+
+ bool valid() const;
};
std::ostream &operator<<(std::ostream &out, const Intent &intent);
diff --git a/src/anbox/android/ip_config_builder.cpp b/src/anbox/android/ip_config_builder.cpp
new file mode 100644
index 0000000..8ba13ce
--- /dev/null
+++ b/src/anbox/android/ip_config_builder.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 Simon Fels
+ *
+ * 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 .
+ *
+ */
+
+#include "anbox/android/ip_config_builder.h"
+
+#include
+
+#include
+#include
+
+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(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 &dns_servers) {
+ dns_servers_ = dns_servers;
+}
+
+void IpConfigBuilder::set_id(uint32_t id) {
+ id_ = id;
+}
+} // namespace android
+} // namespace anbox
diff --git a/src/anbox/android/ip_config_builder.h b/src/anbox/android/ip_config_builder.h
new file mode 100644
index 0000000..812da7c
--- /dev/null
+++ b/src/anbox/android/ip_config_builder.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 Simon Fels
+ *
+ * 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 .
+ *
+ */
+
+#ifndef ANBOX_ANDROID_IPCONFIGBUILDER_H_
+#define ANBOX_ANDROID_IPCONFIGBUILDER_H_
+
+#include "anbox/common/binary_writer.h"
+
+#include
+#include
+#include
+
+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 &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 dns_servers_;
+ std::uint32_t id_;
+};
+} // namespace android
+} // namespace anbox
+
+#endif
diff --git a/src/anbox/bridge/platform_api_skeleton.h b/src/anbox/bridge/platform_api_skeleton.h
index 7a9891b..843416e 100644
--- a/src/anbox/bridge/platform_api_skeleton.h
+++ b/src/anbox/bridge/platform_api_skeleton.h
@@ -18,6 +18,7 @@
#ifndef ANBOX_BRIDGE_PLATFORM_SERVER_H_
#define ANBOX_BRIDGE_PLATFORM_SERVER_H_
+#include
#include
namespace google {
diff --git a/src/anbox/build/version.cpp b/src/anbox/build/version.cpp
new file mode 100644
index 0000000..b63b804
--- /dev/null
+++ b/src/anbox/build/version.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 Simon Fels
+ *
+ * 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 .
+ *
+ */
+
+#include "anbox/build/version.h"
+#include "anbox/utils.h"
+
+#include
+
+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
diff --git a/src/anbox/version.cpp b/src/anbox/build/version.h.in
similarity index 55%
rename from src/anbox/version.cpp
rename to src/anbox/build/version.h.in
index 8759db7..fb7983a 100644
--- a/src/anbox/version.cpp
+++ b/src/anbox/build/version.h.in
@@ -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
+#include
+
+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_
diff --git a/src/anbox/cmds/container_manager.cpp b/src/anbox/cmds/container_manager.cpp
index 4716303..a71f07b 100644
--- a/src/anbox/cmds/container_manager.cpp
+++ b/src/anbox/cmds/container_manager.cpp
@@ -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;
diff --git a/src/anbox/cmds/container_manager.h b/src/anbox/cmds/container_manager.h
index 4525756..679c802 100644
--- a/src/anbox/cmds/container_manager.h
+++ b/src/anbox/cmds/container_manager.h
@@ -42,6 +42,7 @@ class ContainerManager : public cli::CommandWithFlagsAndAction {
std::shared_ptr android_img_loop_dev_;
std::vector> mounts_;
bool privileged_ = false;
+ bool daemon_ = false;
};
} // namespace cmds
} // namespace anbox
diff --git a/src/anbox/cmds/launch.cpp b/src/anbox/cmds/launch.cpp
index a73e2b6..3e0f885 100644
--- a/src/anbox/cmds/launch.cpp
+++ b/src/anbox/cmds/launch.cpp
@@ -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
+#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 &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(signal));
@@ -69,42 +95,95 @@ anbox::cmds::Launch::Launch()
auto bus = std::make_shared(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 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 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();
+
+ std::vector args = {"session-manager"};
+
+ std::map 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();
});
diff --git a/src/anbox/cmds/launch.h b/src/anbox/cmds/launch.h
index b7a6dfe..7fc71c9 100644
--- a/src/anbox/cmds/launch.h
+++ b/src/anbox/cmds/launch.h
@@ -23,6 +23,7 @@
#include
#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 &stub);
+
android::Intent intent_;
wm::Stack::Id stack_;
};
diff --git a/src/anbox/cmds/session_manager.cpp b/src/anbox/cmds/session_manager.cpp
index 5c294d0..731de0a 100644
--- a/src/anbox/cmds/session_manager.cpp
+++ b/src/anbox/cmds/session_manager.cpp
@@ -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(rt);
+ container_->register_terminate_handler([&]() {
+ WARNING("Lost connection to container manager, terminating.");
+ trap->stop();
+ });
+ }
auto input_manager = std::make_shared(rt);
@@ -159,8 +177,6 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory)
display_frame = window_size_;
auto policy = std::make_shared(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();
@@ -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();
diff --git a/src/anbox/cmds/session_manager.h b/src/anbox/cmds/session_manager.h
index 9ffb419..25185ac 100644
--- a/src/anbox/cmds/session_manager.h
+++ b/src/anbox/cmds/session_manager.h
@@ -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_;
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
diff --git a/src/anbox/cmds/system_info.cpp b/src/anbox/cmds/system_info.cpp
index 421f11c..e8f7443 100644
--- a/src/anbox/cmds/system_info.cpp
+++ b/src/anbox/cmds/system_info.cpp
@@ -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
#include
@@ -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);
}
}
diff --git a/src/anbox/cmds/version.cpp b/src/anbox/cmds/version.cpp
index c405e48..d8aef39 100644
--- a/src/anbox/cmds/version.cpp
+++ b/src/anbox/cmds/version.cpp
@@ -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;
});
}
diff --git a/src/anbox/common/binary_writer.cpp b/src/anbox/common/binary_writer.cpp
new file mode 100644
index 0000000..3202199
--- /dev/null
+++ b/src/anbox/common/binary_writer.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 Thomas Voss
+ * Simon Fels
+ *
+ * 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 .
+ *
+ */
+
+#include "anbox/common/binary_writer.h"
+
+#include
+#include
+
+#include
+
+namespace {
+bool is_little_endian() {
+ static const std::uint32_t v = 1;
+ return (*reinterpret_cast(&v) == 1);
+}
+}
+
+namespace anbox {
+namespace common {
+
+BinaryWriter::BinaryWriter(std::vector::iterator begin,
+ std::vector::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(&(*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(&(*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
diff --git a/src/anbox/common/binary_writer.h b/src/anbox/common/binary_writer.h
new file mode 100644
index 0000000..23708c6
--- /dev/null
+++ b/src/anbox/common/binary_writer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 Thomas Voss
+ * Simon Fels
+ *
+ * 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 .
+ *
+ */
+
+#ifndef ANBOX_COMMON_BINARY_WRITER_H_
+#define ANBOX_COMMON_BINARY_WRITER_H_
+
+#include
+#include
+#include
+
+namespace anbox {
+namespace common {
+class BinaryWriter {
+ public:
+ enum class Order {
+ Big,
+ Little,
+ };
+
+ explicit BinaryWriter(std::vector::iterator begin_,
+ std::vector::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::iterator begin_;
+ std::vector::iterator current_;
+ std::vector::iterator end_;
+ Order byte_order_;
+};
+} // namespace common
+} // namespace anbox
+
+#endif
diff --git a/src/anbox/config.cpp b/src/anbox/config.cpp
index 7c0961e..a13aa43 100644
--- a/src/anbox/config.cpp
+++ b/src/anbox/config.cpp
@@ -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;
diff --git a/src/anbox/config.h b/src/anbox/config.h
index 91f72c6..0fce571 100644
--- a/src/anbox/config.h
+++ b/src/anbox/config.h
@@ -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
diff --git a/src/anbox/container/lxc_container.cpp b/src/anbox/container/lxc_container.cpp
index 3faf842..a2e0705 100644
--- a/src/anbox/container/lxc_container.cpp
+++ b/src/anbox/container/lxc_container.cpp
@@ -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