From 32a5eaca696667312624f551087ba046eee96b81 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sat, 3 Dec 2016 14:14:33 +0100 Subject: [PATCH 01/12] Fix permissions of extracted rootfs content --- scripts/container-manager.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index 6798363..b642187 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -13,6 +13,7 @@ if [ ! -e $ROOTFS_PATH ] || [ "$ROOTFS_VERSION" != "$(cat $ROOTFS_PATH/.version) echo "Copying rootfs into $ROOTFS_PATH .." mkdir -p $ROOTFS_PATH tar xf $SNAP/android-rootfs.tar -C $ROOTFS_PATH/ --strip-components=1 + chown -R root:root $ROOTFS_PATH echo $ROOTFS_VERSION > $ROOTFS_PATH/.version fi From 54c81ae7ecb4dde35e7990013b70d3991ec5ff6e Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sat, 3 Dec 2016 14:15:15 +0100 Subject: [PATCH 02/12] Ignore directories and files created by snapcraft --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index aa90563..bf05908 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ build*/ +parts/ +stage/ +prime/ +*.snap CMakeLists.txt.user From 4e07be375460caca6c12834c93fa2f5e2ded3489 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sat, 3 Dec 2016 15:23:23 +0100 Subject: [PATCH 03/12] Use correct target paths inside rootfs path for bind mounts --- src/anbox/container/lxc_container.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/anbox/container/lxc_container.cpp b/src/anbox/container/lxc_container.cpp index ab721bd..33eddb1 100644 --- a/src/anbox/container/lxc_container.cpp +++ b/src/anbox/container/lxc_container.cpp @@ -136,9 +136,12 @@ void LxcContainer::start(const Configuration &configuration) { if (fs::is_directory(bind_mount.first)) create_type = "dir"; auto target_path = bind_mount.second; - // LXC wants target paths relative to the container rootfs so - // prividing an absolute path doesn't work. - if (utils::string_starts_with(target_path, "/")) target_path.erase(0, 1); + // The target path needs to be absolute and pointing to the right + // location inside the target rootfs as otherwise we get problems + // when running in confined environments like snap's. + if (!utils::string_starts_with(target_path, "/")) + target_path = std::string("/") + target_path; + target_path = config::rootfs_path() + target_path; set_config_item( "lxc.mount.entry", From 9c89d8247efc8d460e8e6b117d04649005849713 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sat, 3 Dec 2016 17:11:24 +0100 Subject: [PATCH 04/12] Use run command as default when no command is supplied --- src/anbox/daemon.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/anbox/daemon.cpp b/src/anbox/daemon.cpp index 69fb079..80e77de 100644 --- a/src/anbox/daemon.cpp +++ b/src/anbox/daemon.cpp @@ -42,7 +42,10 @@ Daemon::Daemon() } int Daemon::Run(const std::vector &arguments) try { - return cmd.run({std::cin, std::cout, arguments}); + auto argv = arguments; + if (arguments.size() == 0) + argv = {"run"}; + return cmd.run({std::cin, std::cout, argv}); } catch (std::exception &err) { ERROR("%s", err.what()); return EXIT_FAILURE; From cb9814fb02d636e13efd1c55393046929ffc0126 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sat, 3 Dec 2016 17:11:50 +0100 Subject: [PATCH 05/12] Don't supply any argument for anbox command --- snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snapcraft.yaml b/snapcraft.yaml index bd76cee..771bc80 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -10,7 +10,7 @@ grade: devel apps: anbox: - command: bin/anbox-wrapper.sh run + command: bin/anbox-wrapper.sh container-manager: command: bin/container-manager.sh daemon: simple From b31d79ca087d0de9c593c9bf32dd1723f85d3a30 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sun, 4 Dec 2016 11:53:58 +0100 Subject: [PATCH 06/12] Only use bridge if available to prevent container startup failures LXC doesn't start the container when the configured network interface (the bridge in this case) is not available. --- src/anbox/container/lxc_container.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/anbox/container/lxc_container.cpp b/src/anbox/container/lxc_container.cpp index 33eddb1..4167a1a 100644 --- a/src/anbox/container/lxc_container.cpp +++ b/src/anbox/container/lxc_container.cpp @@ -113,9 +113,11 @@ void LxcContainer::start(const Configuration &configuration) { "lxc.logfile", utils::string_format("%s/container.log", config::log_path()).c_str()); - set_config_item("lxc.network.type", "veth"); - set_config_item("lxc.network.flags", "up"); - set_config_item("lxc.network.link", "anboxbr0"); + if (fs::exists("/sys/class/net/anboxbr0")) { + set_config_item("lxc.network.type", "veth"); + set_config_item("lxc.network.flags", "up"); + set_config_item("lxc.network.link", "anboxbr0"); + } #if 0 // Android uses namespaces as well so we have to allow nested namespaces for LXC From a8704556da0c3113358644fb522a4c522c9c06fb Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sun, 4 Dec 2016 17:07:44 +0100 Subject: [PATCH 07/12] Unload AppArmor profile for container management process If we run the management process with the AppArmor profile loaded from snap-confine various ashmem/binder operations are failing with permission denied errors. To workaround this until this problem is fixed we simply unload the AppArmor profile and continue to execute completely without any profile loaded. --- scripts/container-manager.sh | 2 +- snapcraft.yaml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index b642187..60a4327 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -29,4 +29,4 @@ chmod 666 /dev/ashmem # this path. mkdir -p $SNAP_COMMON/lxc -exec $SNAP/bin/anbox-wrapper.sh container-manager +exec $SNAP/usr/sbin/aa-exec -p unconfined -- $SNAP/bin/anbox-wrapper.sh container-manager diff --git a/snapcraft.yaml b/snapcraft.yaml index 771bc80..a066de7 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -36,6 +36,10 @@ parts: - bin/anbox-bridge.sh - bin/anbox-wrapper.sh - bin/container-manager.sh + apparmor: + plugin: nil + stage-packages: + - apparmor lxc: source: git://github.com/morphis/lxc source-branch: snappy-support From a86a5847f8fea12e0fe57103ac0abe179c27cd2c Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sun, 4 Dec 2016 17:16:55 +0100 Subject: [PATCH 08/12] Start bridge as part of the container manager --- scripts/container-manager.sh | 10 +++++++++- snapcraft.yaml | 10 ++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index 60a4327..864c17a 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -29,4 +29,12 @@ chmod 666 /dev/ashmem # this path. mkdir -p $SNAP_COMMON/lxc -exec $SNAP/usr/sbin/aa-exec -p unconfined -- $SNAP/bin/anbox-wrapper.sh container-manager +# We start the bridge here as long as a oneshot service unit is not +# possible. See snapcraft.yaml for further details. +$SNAP/bin/anbox-bridge.sh start + +$SNAP/usr/sbin/aa-exec -p unconfined -- $SNAP/bin/anbox-wrapper.sh container-manager +pid=$! +waitpid $pid + +$SNAP/bin/anbox-bridge.sh stop diff --git a/snapcraft.yaml b/snapcraft.yaml index a066de7..40352db 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -14,10 +14,12 @@ apps: container-manager: command: bin/container-manager.sh daemon: simple - bridge: - command: bin/anbox-bridge.sh start - stop-command: bin/anbox-bridge.sh stop - daemon: oneshot +# FIXME: a oneshot unit with start/stop commands needs also RemainAfterExit=yes +# but this isn't supported by snapd yet. See LP #1647169 for details. +# bridge: +# command: bin/anbox-bridge.sh start +# stop-command: bin/anbox-bridge.sh stop +# daemon: oneshot parts: android-rootfs: From 457bd794fffea3668dc83bd3259e02127b8d1a26 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sun, 4 Dec 2016 17:17:33 +0100 Subject: [PATCH 09/12] Don't load kernel modules anymore --- scripts/container-manager.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index 864c17a..0c90121 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -17,13 +17,6 @@ if [ ! -e $ROOTFS_PATH ] || [ "$ROOTFS_VERSION" != "$(cat $ROOTFS_PATH/.version) echo $ROOTFS_VERSION > $ROOTFS_PATH/.version fi -# Load binder and ashmem kernel drivers. This will just horrible break -# if kernel versions are changing ... -insmod $SNAP/binder_linux.ko || true -chmod 666 /dev/binder -insmod $SNAP/ashmem_linux.ko || true -chmod 666 /dev/ashmem - # Make sure our setup path for the container rootfs # is present as lxc is statically configured for # this path. From 637523b8cf39a4b191eabc109dd40e7ac3091b22 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Sun, 4 Dec 2016 17:20:21 +0100 Subject: [PATCH 10/12] Drop scripts we don't need anymore --- create-click.sh | 27 ----------------- scripts/container-shell.sh | 11 ------- scripts/iptables-wrapper | 2 -- scripts/launch-abox.sh | 60 -------------------------------------- scripts/setup-rootfs.sh | 16 ---------- scripts/shell.sh | 3 -- 6 files changed, 119 deletions(-) delete mode 100755 create-click.sh delete mode 100755 scripts/container-shell.sh delete mode 100755 scripts/iptables-wrapper delete mode 100755 scripts/launch-abox.sh delete mode 100755 scripts/setup-rootfs.sh delete mode 100755 scripts/shell.sh diff --git a/create-click.sh b/create-click.sh deleted file mode 100755 index 3e11618..0000000 --- a/create-click.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -set -e -set -x - -if [ ! -e android-rootfs.tar ] ; then - echo "ERROR: Missing Android rootfs package!" - exit 1 -fi - -./cross-compile-chroot.sh -a armhf -d vivid - -if [ -e click ] ; then - rm -rf click -fi - -mkdir click -cp data/manifest.json click/ -cp data/apparmor.json click/ -cp data/anbox.desktop click/ - -(cd click ; tar xf ../android-rootfs.tar ; mv rootfs android-rootfs) - -cp build-armhf-vivid/src/anbox click/ -cp build-armhf-vivid/src/anbox-container click/ - -(cd click ; click build .) diff --git a/scripts/container-shell.sh b/scripts/container-shell.sh deleted file mode 100755 index 2f94bb9..0000000 --- a/scripts/container-shell.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -$SNAP/bin/lxc-attach \ - --lxcpath=$SNAP_COMMON/var/lib/anbox/containers \ - --name default \ - --clear-env \ - --set-var PATH=/system/bin:/system/sbin:/system/xbin \ - --set-var ANDROID_DATA=/data \ - --set-var ANDROID_ROOT=/system \ - -- \ - /system/bin/sh diff --git a/scripts/iptables-wrapper b/scripts/iptables-wrapper deleted file mode 100755 index 73e9421..0000000 --- a/scripts/iptables-wrapper +++ /dev/null @@ -1,2 +0,0 @@ -#!/system/bin/sh -echo "Dummy iptables wrapper" diff --git a/scripts/launch-abox.sh b/scripts/launch-abox.sh deleted file mode 100755 index b37cdf5..0000000 --- a/scripts/launch-abox.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash -set -e -set -x - -basepath=/home/phablet/android-box -rootfs=$basepath/rootfs -rootfs_overrides=$basepath/overrides -ramdisk=$basepath/ramdisk.img -systemdisk=$basepath/system.img -init_cmd="/init" - -if [ "$1" = "shell" ] ; then - init_cmd=/system/bin/sh -fi - -if [ -d $rootfs ] ; then - sudo umount --recursive $rootfs || true - rm -rf $rootfs -fi - -mkdir -p $rootfs -sudo mount -t tmpfs none $rootfs -(cd $rootfs ; cat $ramdisk | gzip -d | cpio -i) - -mkdir -p $rootfs/dev/pts -sudo mount -o ro,loop $systemdisk $rootfs/system - -if [ -d "$rootfs_overrides" ] ; then - for f in `ls $rootfs_overrides` ; do - if [ "$f" = "system" ] ; then - for f2 in `find $rootfs_overrides/system -type f` ; do - real_path=`echo $f2 | sed -e s:$rootfs_overrides::g` - sudo mount -o bind $f2 $rootfs/$real_path - done - else - cp $rootfs_overrides/$f $rootfs - fi - done -fi - -/home/phablet/bwrap \ - --ro-bind $rootfs / \ - --bind /home/phablet/android-box/iptables-wrapper /system/bin/iptables \ - --bind /home/phablet/android-box/iptables-wrapper /system/bin/ip6tables \ - --dev /dev \ - --proc /proc \ - --tmpfs /data \ - --unshare-user \ - --unshare-ipc \ - --unshare-pid \ - --unshare-net \ - --unshare-uts \ - --uid 0 \ - --gid 0 \ - --setenv PATH /system/bin:/system/sbin:/system/xbin \ - --chdir / \ - $init_cmd - -sudo umount --recursive $rootfs -rm -rf $rootfs diff --git a/scripts/setup-rootfs.sh b/scripts/setup-rootfs.sh deleted file mode 100755 index f83b6e6..0000000 --- a/scripts/setup-rootfs.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# We need to put the rootfs somewhere where we can modify some -# parts of the content on first boot (namely file permissions). -# Other than that nothing should ever modify the content of the -# rootfs. - -ROOTFS_PATH=$SNAP_COMMON/var/lib/anbox/rootfs - -if [ -d $ROOTFS_PATH ] ; then - rm -rf $ROOTFS_PATH -fi - -echo "Copying rootfs into $ROOTFS_PATH .." -mkdir -p $ROOTFS_PATH -tar xf $SNAP/android-rootfs.tar -C $ROOTFS_PATH/ --strip-components=1 diff --git a/scripts/shell.sh b/scripts/shell.sh deleted file mode 100755 index 89d1294..0000000 --- a/scripts/shell.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -exec /bin/bash $@ From 0c4668d02972fe175455ea7f6818593da12b7151 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Mon, 5 Dec 2016 07:10:21 +0100 Subject: [PATCH 11/12] Extend README with installation and build details --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/README.md b/README.md index 1395920..4c585a2 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,53 @@ For more details have a look at the following documentation pages: * The Android "qemud" multiplexing daemon (https://goo.gl/DeYa5J) * Android Qemud services (https://goo.gl/W8Lx6t) +## Installation + +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. + +Additionally you need to manually load the binder and ashmem kernel +drivers everytime as we build them out-of-tree with a hack as this +isn't officially supported. Before you start anbox you always need +to execute + +$ cd anbox +$ scripts/load-kmods.sh + +Anbox can be installed from the Ubuntu Store with + +$ snap install --edge --devmode anbox + +Afterwards run it with + +$ anbox + +After the first installation the container management service needs +a few minutes to setup the container the first time before it is +available. + +Applications can be launched via the launch subcommand of the anbox +binary. For example + +$ anbox launch --package com.android.settings + +## Build from source + +To build the Anbox runtime itself there is nothing special to know +about. We're using cmake as build system. + +$ mkdir build +$ cd build +$ cmake .. +$ make + +That will build the whole stack. A simple + +$ make install + +will install the necessary bits into your system. + ## Copyright and Licensing Anbox reuses code from other projects like the Android Qemu emulator From 6860338c4b0d61d56de8755b25b7ba925a93e131 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Mon, 5 Dec 2016 10:02:59 +0100 Subject: [PATCH 12/12] Use disk images instead of a rootfs tarball --- scripts/anbox-init.sh | 28 ---------------------- scripts/container-manager.sh | 45 ++++++++++++++++++++++++++++-------- snapcraft.yaml | 5 ++-- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/scripts/anbox-init.sh b/scripts/anbox-init.sh index 55badda..ce61cce 100644 --- a/scripts/anbox-init.sh +++ b/scripts/anbox-init.sh @@ -23,34 +23,6 @@ function prepare_filesystem() { chown system:system /dev/$f chmod 0666 /dev/$f done - - if [ ! -e /.anbox_setup_done ] ; then - echo "Fixing up all permissions ..." - - # Fixup permissions of the android binaries in /system - while read line - do - file=`echo $line | cut -d' ' -f 1` - user=`echo $line | cut -d' ' -f 2` - group=`echo $line | cut -d' ' -f 3` - mode=`echo $line | cut -d' ' -f 4` - # Avoid changing symlinks - if [ ! -h /$file ] ; then - chmod $mode /$file - chown -h $user:$group /$file - fi - done < "/filesystem_config.txt" - - # Additional ones not listed in the config generated from the build - for f in qemu_pipe qemu_trace goldfish_pipe ; do - [ ! -e /dev/$f ] && continue - chown system:system /dev/$f - chmod 0666 /dev/$f - done - - echo "Setup done!" - echo $VERSION > /.anbox_setup_done - fi } prepare_filesystem & diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index 0c90121..f923209 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -5,18 +5,42 @@ # Other than that nothing should ever modify the content of the # rootfs. -ROOTFS_PATH=$SNAP_COMMON/var/lib/anbox/rootfs -ROOTFS_VERSION=1 +DATA_PATH=$SNAP_COMMON/var/lib/anbox +ROOTFS_PATH=$DATA_PATH/rootfs +RAMDISK_PATH=$DATA_PATH/ramdisk +INITRD=$SNAP/ramdisk.img +SYSTEM_IMG=$SNAP/system.img +ANDROID_DATA_PATH=$DATA_PATH/android-data -if [ ! -e $ROOTFS_PATH ] || [ "$ROOTFS_VERSION" != "$(cat $ROOTFS_PATH/.version)" ] ; then - rm -rf $ROOTFS_PATH - echo "Copying rootfs into $ROOTFS_PATH .." - mkdir -p $ROOTFS_PATH - tar xf $SNAP/android-rootfs.tar -C $ROOTFS_PATH/ --strip-components=1 - chown -R root:root $ROOTFS_PATH - echo $ROOTFS_VERSION > $ROOTFS_PATH/.version +if [ ! -e $INITRD ]; then + echo "ERROR: boot ramdisk does not exist" + exit 1 fi +if [ ! -e $SYSTEM_IMG ]; then + echo "ERROR: system image does not exist" + exit 1 +fi + +# Extract ramdisk content instead of trying to bind mount the +# cpio image file to allow modifications. +rm -Rf $RAMDISK_PATH +mkdir -p $RAMDISK_PATH +cd $RAMDISK_PATH +cat $INITRD | gzip -d | cpio -i + +# FIXME those things should be fixed in the build process +chmod +x $RAMDISK_PATH/anbox-init.sh + +# Setup the read-only rootfs +mkdir -p $ROOTFS_PATH +mount -o bind,ro $RAMDISK_PATH $ROOTFS_PATH +mount -o loop,ro $SYSTEM_IMG $ROOTFS_PATH/system + +# ... but we keep /data in the read/write space +mkdir -p $ANDROID_DATA_PATH +mount -o bind $ANDROID_DATA_PATH $ROOTFS_PATH/data + # Make sure our setup path for the container rootfs # is present as lxc is statically configured for # this path. @@ -31,3 +55,6 @@ pid=$! waitpid $pid $SNAP/bin/anbox-bridge.sh stop + +umount $ROOTFS_PATH/system +umount $ROOTFS_PATH/data diff --git a/snapcraft.yaml b/snapcraft.yaml index 40352db..95abac0 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -22,11 +22,12 @@ apps: # daemon: oneshot parts: - android-rootfs: + android: plugin: copy source: . files: - android-rootfs.tar: android-rootfs.tar + system.img: system.img + ramdisk.img: ramdisk.img anbox-common: plugin: copy source: .