commit
0887abe263
13 changed files with 124 additions and 176 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,2 +1,6 @@
|
|||
build*/
|
||||
parts/
|
||||
stage/
|
||||
prime/
|
||||
*.snap
|
||||
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)
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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 &
|
||||
|
|
|
|||
|
|
@ -5,27 +5,56 @@
|
|||
# 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
|
||||
echo $ROOTFS_VERSION > $ROOTFS_PATH/.version
|
||||
if [ ! -e $INITRD ]; then
|
||||
echo "ERROR: boot ramdisk does not exist"
|
||||
exit 1
|
||||
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
|
||||
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.
|
||||
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:
|
||||
anbox:
|
||||
command: bin/anbox-wrapper.sh run
|
||||
command: bin/anbox-wrapper.sh
|
||||
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:
|
||||
android:
|
||||
plugin: copy
|
||||
source: .
|
||||
files:
|
||||
android-rootfs.tar: android-rootfs.tar
|
||||
system.img: system.img
|
||||
ramdisk.img: ramdisk.img
|
||||
anbox-common:
|
||||
plugin: copy
|
||||
source: .
|
||||
|
|
@ -36,6 +39,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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -136,9 +138,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",
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ Daemon::Daemon()
|
|||
}
|
||||
|
||||
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) {
|
||||
ERROR("%s", err.what());
|
||||
return EXIT_FAILURE;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue