diff --git a/README.md b/README.md index de04255..7aee100 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,18 @@ For more details have a look at the following documentation pages: ## Installation +As first step you need to install additional kernel drivers for the +Android binder and ashmem subsystems. Those drivers are packaged as +a DKMS package for Ubuntu 16.04 already. You can install them from +a ppa with the following commands: + +``` + $ sudo apt install software-properties-common + $ sudo add-apt-repository ppa:morphis/anbox-support + $ sudo apt update + $ sudo apt install anbox-modules-dkms +``` + Anbox is available as a snap in the public Ubuntu Store. Currently it is only available in the edge channel and requires to be installed in devmode as we don't have proper confinement for it in place yet. diff --git a/kernel/Makefile b/kernel/Makefile new file mode 100644 index 0000000..6f2908f --- /dev/null +++ b/kernel/Makefile @@ -0,0 +1,13 @@ +#/usr/bin/make +VERSION = 1 +SRC = $(DESTDIR)/usr/src + +all: + +clean: + +install: + install -d $(SRC) + for d in ashmem binder ; do \ + cp -a $$d $(SRC)/anbox-modules-$$d-$(VERSION) ; \ + done diff --git a/kernel/ashmem/dkms.conf b/kernel/ashmem/dkms.conf new file mode 100644 index 0000000..bde1557 --- /dev/null +++ b/kernel/ashmem/dkms.conf @@ -0,0 +1,7 @@ +PACKAGE_NAME="anbox-ashmem" +PACKAGE_VERSION="1" +CLEAN="make clean" +MAKE[0]="make all KVERSION=$kernelver" +BUILT_MODULE_NAME[0]="ashmem_linux" +DEST_MODULE_LOCATION[0]="/updates" +AUTOINSTALL="yes" diff --git a/kernel/binder/binder.c b/kernel/binder/binder.c index 16268a1..8afcb01 100644 --- a/kernel/binder/binder.c +++ b/kernel/binder/binder.c @@ -451,7 +451,9 @@ static void binder_set_nice(long nice) set_user_nice(current, min_nice); if (min_nice <= MAX_NICE) return; +#if 0 binder_user_error("%d RLIMIT_NICE not set\n", current->pid); +#endif } static size_t binder_buffer_size(struct binder_proc *proc, diff --git a/kernel/binder/dkms.conf b/kernel/binder/dkms.conf new file mode 100644 index 0000000..8484321 --- /dev/null +++ b/kernel/binder/dkms.conf @@ -0,0 +1,7 @@ +PACKAGE_NAME="anbox-binder" +PACKAGE_VERSION="1" +CLEAN="make clean" +MAKE[0]="make all KVERSION=$kernelver" +BUILT_MODULE_NAME[0]="binder_linux" +DEST_MODULE_LOCATION[0]="/updates" +AUTOINSTALL="yes" diff --git a/kernel/debian/README.Debian b/kernel/debian/README.Debian new file mode 100644 index 0000000..f8495d9 --- /dev/null +++ b/kernel/debian/README.Debian @@ -0,0 +1,5 @@ +MODULE_NAME DKMS module for Debian + +This package was automatically generated by the DKMS system, +for distribution on Debian based operating systems. + diff --git a/kernel/debian/changelog b/kernel/debian/changelog new file mode 100644 index 0000000..b707d67 --- /dev/null +++ b/kernel/debian/changelog @@ -0,0 +1,5 @@ +anbox-modules-dkms (1) xenial; urgency=low + + * Initial release. + + -- Simon Fels Mon, 06 Feb 2017 21:43:58 +0100 diff --git a/kernel/debian/compat b/kernel/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/kernel/debian/compat @@ -0,0 +1 @@ +7 diff --git a/kernel/debian/control b/kernel/debian/control new file mode 100644 index 0000000..128ba37 --- /dev/null +++ b/kernel/debian/control @@ -0,0 +1,14 @@ +Source: anbox-modules-dkms +Section: misc +Priority: optional +Maintainer: Simon Fels +Build-Depends: debhelper (>= 7), dkms +Standards-Version: 3.9.7 + +Package: anbox-modules-dkms +Architecture: all +Depends: dkms (>= 1.95), ${misc:Depends} +Description: Android kernel driver (binder, ashmem) in DKMS format. + . + This package contains a out-of-tree version of the core Android + kernel functionalities binder and ashmem. diff --git a/kernel/debian/copyright b/kernel/debian/copyright new file mode 100644 index 0000000..650f695 --- /dev/null +++ b/kernel/debian/copyright @@ -0,0 +1,37 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: anbox +Source: http://github.com/anbox + +files: debian/* Makefile +Copyright: 2017 Simon Fels +License: GPL-3 + This program is free software: you can redistribute it and/or modify it + under the terms of the 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 applicable version of the GNU Lesser 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 . + . + On Debian systems, the complete text of the GNU General Public License + can be found in `/usr/share/common-licenses/GPL-3' + + +files: ashmem/* binder/* +Copyright: 2008-2012 Google Inc. +License: GPL-2 + Copyright (C) 2008-2012 Google, Inc. + . + This software is licensed under the terms of the GNU General Public + License version 2, as published by the Free Software Foundation, and + may be copied, distributed, and modified under those terms. + . + 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 General Public License for more details. diff --git a/kernel/debian/dirs b/kernel/debian/dirs new file mode 100644 index 0000000..b601f22 --- /dev/null +++ b/kernel/debian/dirs @@ -0,0 +1 @@ +usr/src diff --git a/kernel/debian/postinst b/kernel/debian/postinst new file mode 100755 index 0000000..6634ce3 --- /dev/null +++ b/kernel/debian/postinst @@ -0,0 +1,51 @@ +#!/bin/sh +# Copyright (C) 2002-2005 Flavio Stanchina +# Copyright (C) 2005-2006 Aric Cyr +# Copyright (C) 2007 Mario Limonciello +# Copyright (C) 2009 Alberto Milone + +set -e + +NAME=anbox-modules +PACKAGE_NAME=$NAME-dkms +DEB_NAME=$(echo $PACKAGE_NAME | sed 's,_,-,') +CVERSION=`dpkg-query -W -f='${Version}' $DEB_NAME | awk -F "-" '{print $1}' | cut -d\: -f2` +ARCH=`dpkg --print-architecture` + +dkms_configure () { + for POSTINST in /usr/lib/dkms/common.postinst "/usr/share/$PACKAGE_NAME/postinst"; do + if [ -f "$POSTINST" ]; then + for d in ashmem binder ; do + "$POSTINST" "$NAME-$d" "$CVERSION" "/usr/share/$PACKAGE_NAME" "$ARCH" "$2" + done + return 0 + fi + echo "WARNING: $POSTINST does not exist." >&2 + done + echo "ERROR: DKMS version is too old and $PACKAGE_NAME was not" >&2 + echo "built with legacy DKMS support." >&2 + echo "You must either rebuild $PACKAGE_NAME with legacy postinst" >&2 + echo "support or upgrade DKMS to a more current version." >&2 + return 1 +} + +case "$1" in + configure) + dkms_configure + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/kernel/debian/prerm b/kernel/debian/prerm new file mode 100755 index 0000000..0b83484 --- /dev/null +++ b/kernel/debian/prerm @@ -0,0 +1,28 @@ +#!/bin/sh + +NAME=anbox-modules-dkms +VERSION=1 + +set -e + +case "$1" in + remove|upgrade|deconfigure) + if [ "`dkms status -m $NAME`" ]; then + dkms remove -m $NAME -v $VERSION --all + fi + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/kernel/debian/rules b/kernel/debian/rules new file mode 100755 index 0000000..b15c649 --- /dev/null +++ b/kernel/debian/rules @@ -0,0 +1,15 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +DEB_NAME=anbox-modules + +include /usr/share/dpkg/default.mk + +%: + dh $@ --parallel --fail-missing + +override_dh_install: + $(MAKE) DESTDIR=$(CURDIR)/debian/$(DEB_NAME)-dkms install diff --git a/scripts/classic b/scripts/classic deleted file mode 100755 index ab5ca89..0000000 --- a/scripts/classic +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh - -set -e - -ROOT=$SNAP_COMMON/classic - -# $1: source -# $2: target -# $3: if not empty, bind mount will be read-only -# note that we do NOT clean these up at the end, as the user might start many -# classic shells in parallel; we could start all of them in their own mount -# namespace, but that would make the classic shell less useful for -# developing/debugging the snappy host -do_bindmount() { - if ! mountpoint -q "$ROOT/$2"; then - if [ -d "$1" -a ! -L "$1" ]; then - mkdir -p "$ROOT/$2" - fi - mount --make-rprivate --rbind -o rbind "$1" "$ROOT/$2" - if [ -n "${3:-}" ]; then - mount --rbind -o remount,ro "$1" "$ROOT/$2" - fi - fi -} - -if [ "$(id -u)" != "0" ]; then - echo "needs to run as root" - exit 1 -fi - -if [ ! -d $ROOT ]; then - # IMPORTANT: do not run the classic.create as this will run it with - # snap-confine again and this will cause havoc with current - # snap-confine - $SNAP/bin/create -fi - -# FIXME: confinement will prevent this -do_bindmount /home /home -do_bindmount /run /run -do_bindmount /proc /proc -do_bindmount /sys /sys -do_bindmount /dev /dev -do_bindmount / /snappy - -SUDO_USER=root - -# fix LP: #1619455 -cp -a /var/lib/extrausers/* $ROOT/var/lib/extrausers/ -cp -a /etc/sudoers.d/* $ROOT/etc/sudoers.d/ - -# assemble command line -DEVPTS="mount -o mode=666,ptmxmode=666 -t devpts devpts /dev/pts" -SUDOCMD="sudo debian_chroot=classic -u ${SUDO_USER} -i $@" -# FIXME: workaround for https://bugs.launchpad.net/snappy/+bug/1611493 -SCRIPT="script --quiet --return --command \"$SUDOCMD\" /dev/null" - -CMD="$DEVPTS; $SCRIPT" - -systemd-run --quiet --scope --unit=classic-$$.scope --description="Classic shell" chroot "$ROOT" sh -c "$CMD" - -# kill leftover processes after exiting, if it's still around -systemctl stop classic-$$.scope 2>/dev/null || true diff --git a/scripts/classic-create b/scripts/classic-create deleted file mode 100755 index 10b8efa..0000000 --- a/scripts/classic-create +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh - -set -eu - -ROOT=$SNAP_COMMON/classic - -if [ -d $ROOT ]; then - echo "classic already enabled" - exit 1 -fi - -if [ $(id -u) -ne 0 ]; then - echo "This script needs to be called as root" >&2 - exit 1 -fi - -CORE="" -if [ -e /snap/core/current ]; then - CORE="core" -elif [ -e /snap/ubuntu-core/current ]; then - CORE="ubuntu-core" -else - echo "Cannot find core snap" - exit 1 -fi - -# FIXME: confinement will prevent this -echo "Creating classic environment" -VERSION="$(/bin/readlink /snap/${CORE}/current)" -SNAPROOT="/var/lib/snapd/snaps/${CORE}_${VERSION}.snap" -/usr/bin/unsquashfs -d $ROOT $SNAPROOT -mkdir $ROOT/snappy - -# enable -sudo chroot $ROOT /var/lib/classic/enable.sh - -# copy important config -for f in hostname timezone localtime; do - cp -a /etc/writable/$f $ROOT/etc/writable -done -for f in hosts; do - cp -a /etc/$f $ROOT/etc/ -done - - -# don't start services in the chroot on apt-get install -cat < "$ROOT/usr/sbin/policy-rc.d" -#!/bin/sh -while true; do - case "\$1" in - -*) shift ;; - makedev) exit 0;; - x11-common) exit 0;; - *) exit 101;; - esac -done -EOF -chmod 755 "$ROOT/usr/sbin/policy-rc.d" - -# workaround bug in livecd-rootfs -chmod 1777 "$ROOT/tmp" diff --git a/scripts/classic-reset b/scripts/classic-reset deleted file mode 100755 index 62c4329..0000000 --- a/scripts/classic-reset +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -set -eu - -ROOT=$SNAP_COMMON/classic - -if [ "$(id -u)" != "0" ]; then - echo "needs to run as root" - exit 1 -fi - -for d in /home /run /proc /sys /dev /var/lib/extrausers /etc/sudoers /etc/sudoers.d /snappy; do - if mountpoint -q "$ROOT/$d"; then - umount "$ROOT/$d" - fi -done - -# cleanup -rm -rf $ROOT diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index ba708eb..568995a 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -6,7 +6,7 @@ set -x # Other than that nothing should ever modify the content of the # rootfs. -DATA_PATH=$SNAP_COMMON/var/lib/anbox +DATA_PATH=$SNAP_COMMON/ ROOTFS_PATH=$DATA_PATH/rootfs ANDROID_IMG=$SNAP/android.img CONTAINER_BASE_UID=100000 @@ -16,45 +16,18 @@ if [ ! -e $ANDROID_IMG ]; then exit 1 fi -build_kernel_modules() { - kversion=$1 - - rm -rf $SNAP_COMMON/kernel-* - - $SNAP/bin/classic-create || true - - rm -rf $SNAP_COMMON/classic/build - mkdir -p $SNAP_COMMON/classic/build - cp -rav $SNAP/ashmem $SNAP_COMMON/classic/build/ - cp -rav $SNAP/binder $SNAP_COMMON/classic/build/ - - cat< $SNAP_COMMON/classic/build/run.sh -#!/bin/sh -set -ex -apt update -apt install -y --force-yes linux-headers-$kversion build-essential -cd /build/ashmem -make -cd /build/binder -make -EOF - - chmod +x $SNAP_COMMON/classic/build/run.sh - $SNAP/bin/classic /build/run.sh - - mkdir -p $SNAP_COMMON/kernel-$kversion - cp $SNAP_COMMON/classic/build/ashmem/ashmem_linux.ko \ - $SNAP_COMMON/kernel-$kversion/ - cp $SNAP_COMMON/classic/build/binder/binder_linux.ko \ - $SNAP_COMMON/kernel-$kversion/ -} - load_kernel_modules() { kversion=`uname -r` rmmod ashmem_linux binder_linux || true echo "Loading kernel modules for version $kversion.." - insmod $SNAP_COMMON/kernel-$kversion/binder_linux.ko - insmod $SNAP_COMMON/kernel-$kversion/ashmem_linux.ko + if ! `modprobe binder_linux` ; then + echo "ERROR: Failed to load kernel binder driver" + return + fi + if ! `modprobe ashmem_linux` ; then + echo "ERROR: Failed to load kernel ashmem driver" + return + fi sleep 0.5 chmod 666 /dev/binder chmod 666 /dev/ashmem @@ -81,23 +54,15 @@ start() { # possible. See snapcraft.yaml for further details. $SNAP/bin/anbox-bridge.sh start - # Building and loading the necessary kernel modules is only possible - # on Ubuntu 16.04 (xenial) - if [ -e /var/lib/snapd/hostfs/etc/os-release ]; then - . /var/lib/snapd/hostfs/etc/os-release - if [ $UBUNTU_CODENAME = xenial ]; then - kversion=`uname -r` - if [ ! -e $SNAP_COMMON/kernel-$kversion ]; then - build_kernel_modules $kversion - fi - load_kernel_modules - fi - fi + # This will try to load the kernel modules. If this fails we will + # continue as normal and anbox will fail later on and report a + # visible error message to the user. + load_kernel_modules # Ensure FUSE support for user namespaces is enabled echo Y | sudo tee /sys/module/fuse/parameters/userns_mounts || echo "WARNING: kernel doesn't support fuse in user namespaces" - exec $SNAP/usr/sbin/aa-exec -p unconfined -- $SNAP/bin/anbox-wrapper.sh container-manager + exec $SNAP/usr/sbin/aa-exec -p unconfined -- $SNAP/bin/anbox-wrapper.sh container-manager --data-path=$DATA_PATH } stop() { diff --git a/snapcraft.yaml b/snapcraft.yaml index a9f4f7a..31f407e 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -22,9 +22,6 @@ parts: source: android-images files: android.img: android.img - kernel-modules: - plugin: dump - source: kernel anbox-common: plugin: copy source: . @@ -32,16 +29,10 @@ parts: scripts/snap-wrapper.sh: bin/anbox-wrapper.sh scripts/container-manager.sh: bin/container-manager.sh scripts/anbox-bridge.sh: bin/anbox-bridge.sh - scripts/classic: bin/classic - scripts/classic-create: bin/classic-create - scripts/classic-reset: bin/classic-reset snap: - bin/anbox-bridge.sh - bin/anbox-wrapper.sh - bin/container-manager.sh - - bin/classic - - bin/classic-create - - bin/classic-reset apparmor: plugin: nil stage-packages: diff --git a/src/anbox/cmds/container_manager.cpp b/src/anbox/cmds/container_manager.cpp index 9ff9c22..fa8d0d2 100644 --- a/src/anbox/cmds/container_manager.cpp +++ b/src/anbox/cmds/container_manager.cpp @@ -19,6 +19,7 @@ #include "anbox/container/service.h" #include "anbox/logger.h" #include "anbox/runtime.h" +#include "anbox/config.h" #include "core/posix/signal.h" @@ -26,7 +27,12 @@ anbox::cmds::ContainerManager::ContainerManager() : CommandWithFlagsAndAction{ cli::Name{"container-manager"}, cli::Usage{"container-manager"}, cli::Description{"Start the container manager service"}} { - action([](const cli::Command::Context&) { + + flag(cli::make_flag(cli::Name{"data-path"}, + cli::Description{"Path where the container and its data is stored"}, + data_path_)); + + action([&](const cli::Command::Context&) { 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) { @@ -34,6 +40,9 @@ anbox::cmds::ContainerManager::ContainerManager() trap->stop(); }); + if (!data_path_.empty()) + SystemConfiguration::instance().set_data_path(data_path_); + auto rt = Runtime::create(); auto service = container::Service::create(rt); diff --git a/src/anbox/cmds/container_manager.h b/src/anbox/cmds/container_manager.h index 866e85f..14d10fb 100644 --- a/src/anbox/cmds/container_manager.h +++ b/src/anbox/cmds/container_manager.h @@ -29,6 +29,9 @@ namespace cmds { class ContainerManager : public cli::CommandWithFlagsAndAction { public: ContainerManager(); + + private: + std::string data_path_; }; } // namespace cmds } // namespace anbox diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index 64cd13e..e3bea66 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -104,6 +104,11 @@ anbox::cmds::Run::Run(const BusFactory &bus_factory) trap->stop(); }); + 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; + } + utils::ensure_paths({ SystemConfiguration::instance().socket_dir(), SystemConfiguration::instance().input_device_dir(),