commit
0887abe263
13 changed files with 124 additions and 176 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,2 +1,6 @@
|
||||||
build*/
|
build*/
|
||||||
|
parts/
|
||||||
|
stage/
|
||||||
|
prime/
|
||||||
|
*.snap
|
||||||
CMakeLists.txt.user
|
CMakeLists.txt.user
|
||||||
|
|
|
||||||
47
README.md
47
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)
|
* The Android "qemud" multiplexing daemon (https://goo.gl/DeYa5J)
|
||||||
* Android Qemud services (https://goo.gl/W8Lx6t)
|
* 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
|
## Copyright and Licensing
|
||||||
|
|
||||||
Anbox reuses code from other projects like the Android Qemu emulator
|
Anbox reuses code from other projects like the Android Qemu emulator
|
||||||
|
|
|
||||||
|
|
@ -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 .)
|
|
||||||
|
|
@ -23,34 +23,6 @@ function prepare_filesystem() {
|
||||||
chown system:system /dev/$f
|
chown system:system /dev/$f
|
||||||
chmod 0666 /dev/$f
|
chmod 0666 /dev/$f
|
||||||
done
|
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 &
|
prepare_filesystem &
|
||||||
|
|
|
||||||
|
|
@ -5,27 +5,56 @@
|
||||||
# Other than that nothing should ever modify the content of the
|
# Other than that nothing should ever modify the content of the
|
||||||
# rootfs.
|
# rootfs.
|
||||||
|
|
||||||
ROOTFS_PATH=$SNAP_COMMON/var/lib/anbox/rootfs
|
DATA_PATH=$SNAP_COMMON/var/lib/anbox
|
||||||
ROOTFS_VERSION=1
|
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
|
if [ ! -e $INITRD ]; then
|
||||||
rm -rf $ROOTFS_PATH
|
echo "ERROR: boot ramdisk does not exist"
|
||||||
echo "Copying rootfs into $ROOTFS_PATH .."
|
exit 1
|
||||||
mkdir -p $ROOTFS_PATH
|
|
||||||
tar xf $SNAP/android-rootfs.tar -C $ROOTFS_PATH/ --strip-components=1
|
|
||||||
echo $ROOTFS_VERSION > $ROOTFS_PATH/.version
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Load binder and ashmem kernel drivers. This will just horrible break
|
if [ ! -e $SYSTEM_IMG ]; then
|
||||||
# if kernel versions are changing ...
|
echo "ERROR: system image does not exist"
|
||||||
insmod $SNAP/binder_linux.ko || true
|
exit 1
|
||||||
chmod 666 /dev/binder
|
fi
|
||||||
insmod $SNAP/ashmem_linux.ko || true
|
|
||||||
chmod 666 /dev/ashmem
|
# 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
|
# Make sure our setup path for the container rootfs
|
||||||
# is present as lxc is statically configured for
|
# is present as lxc is statically configured for
|
||||||
# this path.
|
# this path.
|
||||||
mkdir -p $SNAP_COMMON/lxc
|
mkdir -p $SNAP_COMMON/lxc
|
||||||
|
|
||||||
exec $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
|
||||||
|
|
||||||
|
umount $ROOTFS_PATH/system
|
||||||
|
umount $ROOTFS_PATH/data
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
#!/system/bin/sh
|
|
||||||
echo "Dummy iptables wrapper"
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
exec /bin/bash $@
|
|
||||||
|
|
@ -10,21 +10,24 @@ grade: devel
|
||||||
|
|
||||||
apps:
|
apps:
|
||||||
anbox:
|
anbox:
|
||||||
command: bin/anbox-wrapper.sh run
|
command: bin/anbox-wrapper.sh
|
||||||
container-manager:
|
container-manager:
|
||||||
command: bin/container-manager.sh
|
command: bin/container-manager.sh
|
||||||
daemon: simple
|
daemon: simple
|
||||||
bridge:
|
# FIXME: a oneshot unit with start/stop commands needs also RemainAfterExit=yes
|
||||||
command: bin/anbox-bridge.sh start
|
# but this isn't supported by snapd yet. See LP #1647169 for details.
|
||||||
stop-command: bin/anbox-bridge.sh stop
|
# bridge:
|
||||||
daemon: oneshot
|
# command: bin/anbox-bridge.sh start
|
||||||
|
# stop-command: bin/anbox-bridge.sh stop
|
||||||
|
# daemon: oneshot
|
||||||
|
|
||||||
parts:
|
parts:
|
||||||
android-rootfs:
|
android:
|
||||||
plugin: copy
|
plugin: copy
|
||||||
source: .
|
source: .
|
||||||
files:
|
files:
|
||||||
android-rootfs.tar: android-rootfs.tar
|
system.img: system.img
|
||||||
|
ramdisk.img: ramdisk.img
|
||||||
anbox-common:
|
anbox-common:
|
||||||
plugin: copy
|
plugin: copy
|
||||||
source: .
|
source: .
|
||||||
|
|
@ -36,6 +39,10 @@ parts:
|
||||||
- bin/anbox-bridge.sh
|
- bin/anbox-bridge.sh
|
||||||
- bin/anbox-wrapper.sh
|
- bin/anbox-wrapper.sh
|
||||||
- bin/container-manager.sh
|
- bin/container-manager.sh
|
||||||
|
apparmor:
|
||||||
|
plugin: nil
|
||||||
|
stage-packages:
|
||||||
|
- apparmor
|
||||||
lxc:
|
lxc:
|
||||||
source: git://github.com/morphis/lxc
|
source: git://github.com/morphis/lxc
|
||||||
source-branch: snappy-support
|
source-branch: snappy-support
|
||||||
|
|
|
||||||
|
|
@ -113,9 +113,11 @@ void LxcContainer::start(const Configuration &configuration) {
|
||||||
"lxc.logfile",
|
"lxc.logfile",
|
||||||
utils::string_format("%s/container.log", config::log_path()).c_str());
|
utils::string_format("%s/container.log", config::log_path()).c_str());
|
||||||
|
|
||||||
|
if (fs::exists("/sys/class/net/anboxbr0")) {
|
||||||
set_config_item("lxc.network.type", "veth");
|
set_config_item("lxc.network.type", "veth");
|
||||||
set_config_item("lxc.network.flags", "up");
|
set_config_item("lxc.network.flags", "up");
|
||||||
set_config_item("lxc.network.link", "anboxbr0");
|
set_config_item("lxc.network.link", "anboxbr0");
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Android uses namespaces as well so we have to allow nested namespaces for LXC
|
// Android uses namespaces as well so we have to allow nested namespaces for LXC
|
||||||
|
|
@ -136,9 +138,12 @@ void LxcContainer::start(const Configuration &configuration) {
|
||||||
if (fs::is_directory(bind_mount.first)) create_type = "dir";
|
if (fs::is_directory(bind_mount.first)) create_type = "dir";
|
||||||
|
|
||||||
auto target_path = bind_mount.second;
|
auto target_path = bind_mount.second;
|
||||||
// LXC wants target paths relative to the container rootfs so
|
// The target path needs to be absolute and pointing to the right
|
||||||
// prividing an absolute path doesn't work.
|
// location inside the target rootfs as otherwise we get problems
|
||||||
if (utils::string_starts_with(target_path, "/")) target_path.erase(0, 1);
|
// 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(
|
set_config_item(
|
||||||
"lxc.mount.entry",
|
"lxc.mount.entry",
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,10 @@ Daemon::Daemon()
|
||||||
}
|
}
|
||||||
|
|
||||||
int Daemon::Run(const std::vector<std::string> &arguments) try {
|
int Daemon::Run(const std::vector<std::string> &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) {
|
} catch (std::exception &err) {
|
||||||
ERROR("%s", err.what());
|
ERROR("%s", err.what());
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue