Set-Top-Box and experiments with Android in the container LXC

How did the strange need to run Android in a Linux container arise, and what came of it

Prehistory


In my opinion, launching Android in the LXC container is quite a logical decision if you want to have Bare Linux transparency and reliability and use the huge potential of good (and not so good) third-party Android applications. Also, this configuration is of interest as a platform for debugging your own AOSP image in conditions as close as possible to the combat ones.
For the experiments, a progressive and inexpensive Chinese console based on 64-bit ARMv8 from Amlogic S905x (CPU - 4 cores, RAM - 2GB, MMC - 8GB) was chosen. Just a good argument was a good (compared to other vendors) code base in OpenSource and the availability of a kernel source for Mali-450. And the user space of the Mali library is now publicly available on the official website of ARM Limited. Libraries are accessed in binary form for Linux-FB, Linux-Wayland and Android.

The main objective of the experiments were online cinema applications and applications for working with network media hosting services. For example, from Youtube to Linux, trouble started right away. Firstly: the hacker method of obtaining links to content, by parsing the JS script and generating the signature (previously implemented in the minitube from Tordini and in youtube-dl), began to break down regularly, as a result of Google’s relentless struggle with advertising circumvention techniques. Secondly: the maximum resolution of the content was 720p - I did not give out more Google API. Thirdly: WebKit has lost its normal maintenance and lately it has been supported only by a small group of enthusiasts. The same fate befell his Qt-port. As a result, at one point, the youtube / tv page refused to work, citing the web-engine's old age. Well, at the end of a surprise brought WebEngine (Qt-Chromium). It turns out this beauty does not support hardware acceleration. An exception is made only for its Android port, and the marginal VAAPI branch in Linux. Dead end. In general, I did not find a simple way to enable hardware acceleration of video decoding for Chromium in Linux. Implementing VAAPI for Amlogic seemed like hard and useless work. I also felt the pepper plugin - unfortunately PPAPI does not allow playing offscreen video.

Android


Why not run Android in a container? The feat inspired the project Anbox. Careful examination of Anbox has shown that it does not suit us. But the idea was clear. In articles by other authors, it was argued that launching Android in a container is a pleasurable task. But in actual fact everything turned out to be much more complicated. We couldn’t get rid of simple configuration files.

So, I collect LXC and install it in the system. Kernel configuration test reveals problems: namespace support must be enabled. Since the platform is built-in, all unnecessary things have been disabled. I had to identify these unnecessary use.

The first test was to check the work of the Busybox in the container. Making sure everything works, I started the experiments.

Initial view of /var/lib/lxc/abox.conf:

lxc.rootfs = /var/lib/lxc/abox/rootfs lxc.rootfs.backend = dir lxc.utsname = abox lxc.pts = 1024 lxc.cap.drop = mac_admin mac_override 

Downloading the AOSP 6.0.19. It is distinguished from the vanilla version by the presence of a normal launcher, sharpened for disassembly and patched surfacelinger with support for some features of the Amlogic hardware platform. Vanilla AOSP was subsequently also tested.

A small digression from the topic: The Chinese, adapting software, spit on all the rules set by the community. For example, the kernel is 3.14.29. This silent kernel release number is used on almost all pieces of hardware on Amlogic S8xx and S9xx processors. But, almost always, they are very different from each other, up to the complete incompatibility of old modules with new images and vice versa. It seems that the core was governed by the principle: “the fastest possible entry of the product to the market”. The code is not just dirty - it is of disgusting quality. Configuration changes usually lead to errors when compiling or linking an image or modules. Patched Android of the same quality, and the principles of adaptation are similar. Almost all the recommendations of the AOSP team are ignored.

Well, there is nowhere to go! We collect.

Attempt No. 1 Install the image in the container, run. Does not work. The analysis shows that there are no kernel objects: binder and ashmem. We assemble kernel modules.

Attempt # 2 Run again. Installd crashes. It turns out that the original binder does not know about the namespaces. We pull binder from Anbox.

Attempt # 3 Starts and immediately goes to reboot. It turns out that init wants SELinux and refuses to work without it.

Attempt # 4 Turn on SELinux. We get a bunch of problems for the host system. I had to turn it off, in any case for now - until the essence of the process and the theory of the process were clarified. SELinux can also be disabled on the command line when booting the kernel, but I still don’t understand how to transfer parameters to the container. I had to get into the source of init and roughly correct its behavior. This was the first and last surgery that came back to me later.

Attempt No. 5 The boot process has reached the zygotes. In logs swearing from the kernel on UID init. In a binder (and a binder from Anbox), the UID of the owner process of the process is compared to one. The only way is to disable the check, especially since this check is meaningless in the container.

Attempt # 6 : Conflicts related to sharing access to equipment management have surfaced. I comment on USB and Bluetooth control in init scripts. I remove all entries from fstab, and prohibit mounting and checking all media in scripts. Now add the mount card to the container configuration. It contains only one line. The /mnt/lxc.data directory is mounted on the host in a real MMC partition.

 lxc.mount.entry = /mnt/lxc.data data auto rw,bind 0 0 

Attempt # 7 Bouncing balls appeared on the screen, the download lasts a long time, because the Android image is mounted on NFS, and dexx is being generated in the / data directory. Re-loading is much faster. And finally, a launcher appeared.
We will consider this the last attempt, because, in general, everything works and we need to finish the details.

The network does not work, it works more precisely, but some applications evaluate its performance based on the state of network interfaces. Curved hands, in one word. To eliminate this disadvantage on the host we raise the network bridge (bridge) and the virtual interface (veth).

 lxc.network.type = veth lxc.network.flags = up lxc.network.name = eth1 lxc.network.link = br0 lxc.network.veth.pair = veth-01 lxc.network.ipv4 = 10.0.0.10/24 lxc.network.ipv4.gateway = 10.0.0.1 lxc.network.hwaddr = 00:FE:CD:BA:09:87 

It is also necessary to raise the DHCP server, otherwise there will be problems with the DNS. Unfortunately, Android does not analyze resolv.conf and its location in the file system does not play any role. You can configure the network connection manually, but if you delete data from the data section, all settings will be reset.

Results


All stock applications work. With installed from the market there are problems. For example: Youtube.tv version 3 required updating the Google service framework, after which the system broke down. A problem with the keystore has surfaced (not yet resolved). Also TEE is temporarily disabled, accordingly widevine does not work. Toys and applications without special hardware requirements work fine. Chrome turns HTML5 video with a software decoder, the hardware decoder refuses to cling. On this occasion, there is an opinion about crookedly washed down by the Chinese AOSP. But vanilla AOSP launches a launcher with a touchscreen - it's impossible to control distash.

Afterword


In the near future - to make a launcher launch Android applications directly from Linux. An example of this is in the wpa-supplicant source. You can also peep how it is done in Anbox.

Thanks for attention!

Supplement 1


Recently I checked the scalability of Qt applications. Initially, the IPTV client application is written in QML for Linux. The player works through the QtMultimedia plugin. During the compilation, problem dependencies surfaced. Fortunately, everything was limited to QtDbus, which is not in Android. Until now, I can not understand why for Android it was necessary to reinvent the wheel - binder. Than DBus developers did not suit? So that it works in user space? Or licensing considerations?
Disconnected DBus. It was painless, as the channel was needed for a small functionality related to the operating system. Gathered apk. There is no difficulty with the build, as I use QtCreator (and I recommend it to you).
In AOSP, I had to draw the Mediaplayer bridge, the heir from android :: MediaPlayerInterface. It implemented the setDataSource () and stop () methods. For the rest made plugs. setDataSource has three interfaces. It only took to implement:
 setDataSource(const sp<IMediaHTTPService> &httpService, const char *uri, const KeyedVector<String8, String8> *headers) 


If you want to turn files from media carriers, you will have to tinker with
 setDataSource(int fd, int64_t offset, int64_t length) 

The file name will need to be obtained via "/ proc / self / fd /" + fd;

After installation, the application earned and went broadcast. Super! I expected a lot of problems, but they are almost none. Thanks to the Qt and QtCreator developers for their great and useful work!
As a result, I received such a bundle: a demon of the player is running on the host. In the container - the client program and the laying transmitting calls android :: Mediaplayer on a host. The bundle works through a UDP socket.

Source: https://habr.com/ru/post/413809/


All Articles