Merge pull request #38 from morphis/feature/package-kernel-modules

Split out binder/ashmem kernel modules into a dkms package
This commit is contained in:
Simon Fels 2017-02-09 12:02:56 +01:00 committed by GitHub
commit 7fb5c4f08d
22 changed files with 230 additions and 202 deletions

View file

@ -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.

13
kernel/Makefile Normal file
View file

@ -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

7
kernel/ashmem/dkms.conf Normal file
View file

@ -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"

View file

@ -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,

7
kernel/binder/dkms.conf Normal file
View file

@ -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"

View file

@ -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.

5
kernel/debian/changelog Normal file
View file

@ -0,0 +1,5 @@
anbox-modules-dkms (1) xenial; urgency=low
* Initial release.
-- Simon Fels <morphis@gravedo.de> Mon, 06 Feb 2017 21:43:58 +0100

1
kernel/debian/compat Normal file
View file

@ -0,0 +1 @@
7

14
kernel/debian/control Normal file
View file

@ -0,0 +1,14 @@
Source: anbox-modules-dkms
Section: misc
Priority: optional
Maintainer: Simon Fels <morphis@gravedo.de>
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.

37
kernel/debian/copyright Normal file
View file

@ -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 <morphis@gravedo.de>
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 <http://www.gnu.org/licenses/>.
.
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.

1
kernel/debian/dirs Normal file
View file

@ -0,0 +1 @@
usr/src

51
kernel/debian/postinst Executable file
View file

@ -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

28
kernel/debian/prerm Executable file
View file

@ -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

15
kernel/debian/rules Executable file
View file

@ -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

View file

@ -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

View file

@ -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 <<EOF > "$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"

View file

@ -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

View file

@ -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<<EOF > $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() {

View file

@ -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:

View file

@ -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);

View file

@ -29,6 +29,9 @@ namespace cmds {
class ContainerManager : public cli::CommandWithFlagsAndAction {
public:
ContainerManager();
private:
std::string data_path_;
};
} // namespace cmds
} // namespace anbox

View file

@ -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(),