I have am using Docker inside a VM (Debian Stable). I want to run an Android emulator for x86_64 in a Docker container.
Here is how the Docker image is built:
FROM debian:stable
RUN apt-get update && apt-get install --yes curl unzip openjdk-8-jdk libqt5widgets5
RUN useradd foo --shell /bin/bash --create-home --user-group
USER foo
WORKDIR /home/foo
RUN curl --output sdk-tools-linux.zip https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
RUN unzip sdk-tools-linux.zip && rm sdk-tools-linux.zip
RUN yes | tools/bin/sdkmanager 'system-images;android-24;default;x86_64' 'emulator' 'build-tools;26.0.1' 'platform-tools' 'platforms;android-24'
RUN echo no | tools/bin/avdmanager create avd --package 'system-images;android-24;default;x86_64' --name android-x86_64
When starting the emulator like this inside the container:
emulator/emulator -avd android-x86_64 -no-window -no-audio -no-boot-anim -no-accel -gpu off
I get the following error:
emulator: WARNING: encryption is off
emulator: WARNING: x86_64 emulation may not work without hardware acceleration!
path /home/foo/.android/avd/android-x86_64.avd/system.img.qcow2
qemu-system-x86_64: -device virtio-blk-pci,drive=system,iothread=disk-iothread,modern-pio-notify: ioeventfd is required for iothread
It seems to be related to hardware acceleration (is it?). Disregarding the purposefulness of such environment (emulator inside Docker inside a VM), is it possible to run the emulator in such context? How can I solve my problem?
Thanks,
We're using (or trying to use) this exact same scenario for automated testing.
The problem: The x86 and x86_64 emulator requires hardware acceleration. Hardware acceleration (VT-X or AMD-V) is not typically available inside a virtual environment (See: https://askubuntu.com/questions/328748/how-to-enable-nested-virtualization-in-ubuntu)
This means your best option is to use the ARM emulator, which is really slow. Running this inside Docker inside a VM will be even slower.
You can create the emulator like this:
# NOTE: Must use ARM, since x86 requires hardware acceleration, which is not available inside
# a docker container running inside a virtual machine
echo no | ${ANDROID_HOME}/tools/bin/avdmanager create avd \
--abi "armeabi-v7a" \
--device 'Nexus 4' \
--force \
--name arm_emulator \
--package "system-images;android-25;google_apis;armeabi-v7a" \
--sdcard 64M
You can then start the emulator like this:
${ANDROID_HOME}/emulator/emulator \
-avd arm_emulator \
-gpu swiftshader_indirect \
-memory 512 \
-no-audio \
-no-boot-anim \
-no-window &
Running this inside Docker on my local machine takes the emulator about 4-5 minutes to finish booting. When the Docker environment runs inside VirtualBox expect it to be even slower.
Even with this working, some commands like app installation through ADB fail because they take simply too long.
If possible, it may be a better option to start the emulator parallel to the virtual machine (e.g. on the same host) and then connect to the emulator through network.
Related
We are building an app in React Native using wix/Detox for writing e2e tests.
We are using Docker for doing builds and running tests. Specifically, we're using community react-native-android Docker image.
I have added fastlane to the image for building / publishing our app and now trying to add an emulator so that we can run tests as well.
This is our Dockerfile:
# reactnativecommunity/react-native-android:4.0
FROM reactnativecommunity/react-native-android#sha256:c3ad9b8ed5caac0718b1c1b8f10469eb75b0ac77c86143c94f9616ee46b80b4b
RUN gem install fastlane -NV
RUN sdkmanager --install "system-images;android-31;google_apis;arm64-v8a"
RUN echo no | avdmanager create avd --name default -k "system-images;android-31;google_apis;arm64-v8a"
However, when I run the container and attempt to start the emulator, I get the following:
root#7b862aa149c8:/# emulator -no-audio -no-boot-anim -no-window -use-system-libs #default
emulator: Android emulator version 30.7.5.0 (build_id 7491168) (CL:N/A)
emulator: INFO: ignore sdcard for arm at api level >= 30
emulator: feeding guest with passive gps data, in headless mode
emulator: ERROR: AdbHostServer.cpp:102: Unable to connect to adb daemon on port: 5037
cannot add library /opt/android/emulator/qemu/linux-x86_64/lib64/vulkan/libvulkan.so: failed
added library /opt/android/emulator/lib64/vulkan/libvulkan.so
emulator: INFO: ignore sdcard for arm at api level >= 30
emulator: INFO: userspace-boot-properties.cpp:242: Sending adb public key [QAAAACG/f/Yfe1MON5LKVoRU+iuzZRCKQTvsqLWcWh8i5ii03oHLY7y7U+0uKSE5x84OrGS0g6G9HTU7Mazh18yhbmPAQociSCfrSRIWg3IAdduFDgYPnY2G3Lj11ZLQoyRt4+xXO7zVcUPtwERpgpYQXEN5KkkEZBUxxWvrejENPAffPp4DHFqJf63sAUPh9qo6cwfSMylnl7RTBicxZ+tuDwrxA1JgcvklAs38E9gzxjNDed+1VibNUjzCtRl4DnPPmIk1OqhvjU0xZV//YXDrdhb++jQOpcKAzkCvVks4RUjJ1okytnmDfh+YUH4thQYuqNdEBnGM4wz8cPQH0YjO1SsK2sOrD0VJaGjSDAwsjne2QCFy5ET+HOUcMNKCaC60MAcCgWXLm8MdoaVLgjoG0jbUEkr/BJ2hpN7/p+qi8qMSg3Vv2M/4kdHmIEzDpJTd8TFD1bbrRjdUIheDzE1b00SKhQzDJ39sQim31IqWGuRIJ4Cb39VaHCFK6ZwZPpG9KKLSV1ww5KCKVgSsJ5zaAvhagCjXXXVrtl40v72zYq/c0BtUG4LhLixtz/zuT1WFKq8HoGFkJBvw5fBVqcvOn6yN7xI3DAuzAlQcHPyRQdHm72+//KimCVHnkxlL3hpRMir06QhMk2DsKTntXjbYuhCCn0aetEUUpai6gl1NuCbv92QlDgEAAQA= #unknown]
emulator: INFO: GrpcServices.cpp:315: Started GRPC server at 127.0.0.1:8554, security: Local
WARNING. Using fallback path for the emulator registration directory.
emulator: INFO: EmulatorAdvertisement.cpp:93: Advertising in: /root/.android/avd/running/pid_9.ini
qemu-system-aarch64-headless: PCI bus not available for hda
saving arm snapshot.... !!!
saving done.... !!!
root#7b862aa149c8:/#
This is what worked in the end BUT required bare metal machine
# reactnativecommunity/react-native-android:4.0
FROM reactnativecommunity/react-native-android#sha256:c3ad9b8ed5caac0718b1c1b8f10469eb75b0ac77c86143c94f9616ee46b80b4b
ARG IMAGE="system-images;android-31;google_apis;x86_64"
RUN sdkmanager --install "${IMAGE}"
RUN echo no | avdmanager create avd --name emulator_for_e2e_testing -k "${IMAGE}"
ENTRYPOINT adb start-server && emulator -avd emulator_for_e2e_testing -no-audio -no-window -no-boot-anim
So,
Is it possible to run the (Android) emulator through Docker? yes.
I don't know much about Fastlane|wix/Detox, but I made this in a e2e/Appium project
If so, how?
Do you need a hardware that support virtualization
In Linux find out if CPU Support Intel VT/AMD-V Virtualization For KVM
lscpu | grep Virtualization
Virtualization: VT-x (if 'Intel VT-x' or 'VT-x' feature supported)
or
Virtualization: full (if 'full' not supported)
On AWS, you need a bare metal instance (supported x86) like c5.metal
Android Emulator Container Scripts
https://github.com/google/android-emulator-container-scripts
Follow this git, create an image with google API (I my case, 27-google-x86) and put in docker repo, like AWS ECR.
And, I created an image too to Appium (I believe with is possible with wix/detox)
To SDK
Dockerfile
FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
# Installs i386 architecture required for running 32 bit Android tools
RUN dpkg --add-architecture i386 && \
apt-get update && \
apt-get dist-upgrade -y && \
apt-get install -y --no-install-recommends openjdk-8-jdk && \
apt-get install -y --no-install-recommends git wget unzip curl make && \
rm -rf /var/lib/apt/lists/* && \
apt-get autoremove -y && \
apt-get clean
ENV JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64/jre" \
PATH=$PATH:$JAVA_HOME/bin
# Installs Android SDK
ENV ANDROID_HOME=/android-sdk
ENV ANDROID_SDK_HOME $ANDROID_HOME
ARG ANDROID_SDK_VERSION=6514223
ARG ANDROID_BUILD_TOOLS_VERSION=27.0.0
ARG ANDROID_PLATFORM_VERSION="android-27"
RUN mkdir -p ${ANDROID_SDK_HOME}/cmdline-tools && \
wget -q https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_VERSION}_latest.zip && \
unzip *tools*linux*.zip -d ${ANDROID_SDK_HOME}/cmdline-tools && \
rm *tools*linux*.zip
ENV PATH ${PATH}:${ANDROID_SDK_HOME}/tools:${ANDROID_SDK_HOME}/platform-tools
RUN mkdir -p ~/.android && \
touch ~/.android/repositories.cfg && \
echo y | ${ANDROID_SDK_HOME}/cmdline-tools/tools/bin/sdkmanager --licenses && \
echo y | ${ANDROID_SDK_HOME}/cmdline-tools/tools/bin/sdkmanager "platform-tools" && \
echo y | ${ANDROID_SDK_HOME}/cmdline-tools/tools/bin/sdkmanager "build-tools;$ANDROID_BUILD_TOOLS_VERSION" && \
echo y | ${ANDROID_SDK_HOME}/cmdline-tools/tools/bin/sdkmanager "platforms;$ANDROID_PLATFORM_VERSION"
# Installs Node
ARG NODE_VERSION=12.x
RUN curl -sL https://deb.nodesource.com/setup_${NODE_VERSION} | bash
RUN apt-get install --yes nodejs
Finally, I orchestrated everything a Jenkinsfile
I'm trying to create a android emulator inside a docker container but got some problems.
The SDK updates and AVD creation were successful and i try to create the emulator, the following error appears:
./emulator -avd test-22 -no-skin -no-audio -no-window
sh: 1: file: not found
sh: 1: file: not found
WARNING: Cannot decide host bitness because $SHELL is not properly defined; 32 bits assumed.
ERROR: 32-bit Linux Android emulator binaries are DEPRECATED, to use them
Notes: Running last docker version and using java:8-jdk image.
My dockerfile can be found here => https://gist.github.com/leoGalani/1f74621b8e82bd5bc8db586d1f34b8a2
-- Some people told me to install a x86 intel ABI/ARM for the API22 but i cant manage to find the package name so i can install it by command line.
I have same issue and i fix this with install file comman via apt. But still not working yet, i will update when i found a solution.
apt-get install -y --no-install-recommends file libmagic1 libglu1-mesa mesa-utils libpci3 pciutils libpulse0
Edit:
I found a solution after add packages to your docker file
add your docker file these commands too
mv /bin/sh /bin/sh.backup
cp /bin/bash /bin/sh
And create new container with
--device /dev/dri --device /dev/video0 --device /dev/snd --device /dev/kvm
Most probably is work now.
I solved the same problem by using emulator64 instead emulator.
In this case:
emulator64 -avd test-22 -no-skin -no-audio -no-window
I have python wrapper-library for adb where I have unit-test which depend on emulator or real device (since they execute adb commands).
I want also to use Travis CI as build environment along with executing those unit tests for each build.
Is there a way to have android emulator available somewhow in Travis CI, so that unit tests can execute adb commands?
Thanks in advance!
According to the Travis CI documentation, you can start an emulator with the following script in your .travis.yml:
# Emulator Management: Create, Start and Wait
before_script:
- echo no | android create avd --force -n test -t android-19 --abi armeabi-v7a
- emulator -avd test -no-skin -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
Just specify the system image you need in components.
Bruno Parmentier's answer includes what Travis-CI is currently recommending, but I had issues with the VM running out of memory. So instead of running the emulator while the build is running, I changed my config to run the build, then start the emulator, then run the tests.
sudo: false
language: android
env:
global:
# switch glibc to a memory conserving mode
- MALLOC_ARENA_MAX=2
# wait up to 10 minutes for adb to connect to emulator
- ADB_INSTALL_TIMEOUT=10
android:
components:
- platform-tools
- extra-android-m2repository
- build-tools-22.0.1
- android-22
- sys-img-armeabi-v7a-android-22
script:
- ./gradlew assemble lint
after_script:
# Emulator Management: Create, Start and Wait
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
- emulator -avd test -no-skin -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
# now run the tests
- ./gradlew connectedCheck
I'm trying to build & test my project on Travis CI. It keeps showing me same repetitive output every time on all my repositories.
Here is my travis.yml https://github.com/carts-uiet/cartsbusboarding/blob/master/.travis.yml
language: android
android:
components:
# Uncomment the lines below if you want to
# use the latest revision of Android SDK Tools
# - platform-tools
# - tools
# The BuildTools version used by your project
- build-tools-21.0.0
# The SDK version used to compile your project
- android-21
# Additional components
- add-on
- extra
# Specify at least one system image,
# if you need to run emulator(s) during your tests
- sys-img-armeabi-v7a-android-21
# Emulator Management: Create, Start and Wait
before_script:
- echo no | android create avd --force -n test -t android-21 --abi armeabi-v7a
- emulator -avd test -no-skin -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
Here is one such build https://travis-ci.org/carts-uiet/cartsbusboarding/builds/39447907
$ javac -version
javac 1.7.0_60
before_script.1
3.53s$ echo no | android create avd --force -n test -t android-21 --abi armeabi-v7a
Android 5.0 is a basic Android platform.
Do you wish to create a custom hardware profile [no]Created AVD 'test' based on Android 5.0, ARM (armeabi-v7a) processor,
with the following hardware config:
hw.cpu.model=cortex-a8
hw.lcd.density=240
hw.ramSize=512
vm.heapSize=48
before_script.2
0.01s
$ emulator -avd test -no-skin -no-audio -no-window &
$ android-wait-for-emulator
Failed to Initialize backend EGL display
emulator: WARNING: Could not initialize OpenglES emulation, using software renderer.
error: device offline
error: device offline
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
error: device offline
error: device offline
running
running
running
running
running
running
All these builds time-out.
What am I doing wrong here?
Updated response: VM images already include fixed android-wait-for-emulator script and android SDK tools version 24.0.0 by default solving this issue. I deleted my outdated response and workaround.
Build Environment Updates - 2014-12-09
This sounds like the best alternative to get the latest version of the script:
I added this to my before script:
# Emulator Management: Create, Start and Wait
before_script:
- echo no | android create avd --force -n test -t android-21 --abi armeabi-v7a
- emulator -avd test -no-skin -no-audio -no-window &
- curl http://is.gd/android_wait_for_emulator > android-wait-for-emulator
- chmod u+x android-wait-for-emulator
- ./android-wait-for-emulator
- adb shell input keyevent 82 &
The url points to the latest script available on github.
Hope that helps . . .
You need to instruct your travis build to actually run unit tests:
# run tests against the emulator
- ./gradlew connectedAndroidTest
# run tests against the JVM
- ./gradlew test
I am able to pull down the latest android source code into a Ubuntu virtual machine 32-bit (Host: Windows 7 64-bit). The build completes without any errors.
Then I tried to follow these instructions, where it mentions that I should run the emulator on the root of my source code. However, when I tried that, I get an error stating that this command is not found.
So I went to the folder out/host/linux-x86/bin and I found out that there are couple files for emulator*:
emulator
emulator-arm
emulator_renderer
emulator-ui
emulator-x86
When I typed the emulator and emulator-x86 here, it also doesn't work. Here is the error I'm getting:
xxxx/out/host/linux-x86/bin$ ./emulator-x86
emulator: ERROR: You did not specify a virtual device name, and the system
directory could not be found.
If you are an Android SDK user, please use '#<name>' or '-avd <name>'
to start a given virtual device (see -help-avd for details).
Otherwise, follow the instructions in -help-disk-images to start the emulator
So when I run ./emulator-x86 -help-disk-images, I see the following:
If you are building from the Android build system, you should
have ANDROID_PRODUCT_OUT defined in your environment, and the
emulator shall be able to pick-up the right image files automatically.
See -help-build-images for more details.
I built this myself, so I would think that ANDROID_PRODUCT_OUT is set in my environment variables, but I don't see it. So I think that I should run some other shell script to get that set.
I looked at the img files, I saw couple at the location out/target/product/generic:
ramdisk.img
system.img
userdata.img
Could anyone shed some light on this and assist me on what I should do next? I am new to Android and I did some research on this but I couldn't find any similar issues.
I do not know for which product you do your build but to run emulator you can use the following command:
out/host/linux-x86/bin/emulator -sysdir out/target/product/generic/ -system out/target/product/generic/system.img -ramdisk out/target/product/generic/ramdisk.img -data out/target/product/generic/userdata.img -kernel prebuilt/android-arm/kernel/kernel-qemu -sdcard sdcard.img -skindir sdk/emulator/skins -skin WVGA800 -scale 0.7 -memory 512 -partition-size 1024
Just copy it into .sh file into the root of your Android source folder and run this file. Or you can just run it but you should chdir to your Android source folder root at first.
And do not forget to create an sdcard image in the root folder with command mksdcard.
After much puzzling and encountering many of the same problems, I've found a way to get everything working from a new environment.
Environment
First of all, make sure you set your environment with the changes to ~/.bashrc that Android recommends, including:
export USE_CCACHE=1
ccache -M 10G
Follow the steps for downloading the Android source, if you haven't already done so.
Then set up some functions for the environment:
$ . build/envsetup.sh
You now should actually execute one of those functions to get the paths set correctly (as Pingzhong Li pointed out, this is not mentioned in the Android build instructions!):
$ set_stuff_for_environment
First build
Start building! For instance:
$ lunch full-eng
$ make -j4
(Here, 4 threads is ideal for my machine. Change as you see fit.)
When the build finishes, simply launch the emulator:
$ emulator
Subsequent builds
I've found that to get the system.img to rebuild, you need to remove the following files/directories:
out/target/product/generic/obj/PACKAGING/
out/target/product/generic/system.img
Then simply repeat:
$ make -j4
$ emulator
How to run Emulator step by step guide.
Running emulator in downloaded android AOSP source code is as below :-
Step 1
If you have finished your build and generated System image correctly in current running Terminal(Ubuntu), Then it is stragiht forward. Just type below command in your terminal:-
emulator
Step 2
If you have generated system image earlier and you have started a fresh terminal(Ubuntu) then run the following command one by one :-
source build/envsetup.sh
lunch 1 here 1 is my lunch type, you can replace it with yours like(7, 8 etc) and in the last
emulator
Thats it it will lunch your emulator correctly.
Thanks Guys Happy Coding !!!!
Just for reference I had this similar problem and after trying different things I found the solution to be running lunch(after running envsetup.sh) and picking the target in this case aosp_arm-eng. You have to do this everytime you start a new shell because it sets up certain environment variables the emulator needs to run the avd.Provided you have built the target.
#!/usr/bin/env bash
ANDROID_BUILD_OUT=/path/to/android/build/output/
ANDROID_SDK_LINUX=/path/to/android/sdk
ANDROID_BUILD=${ANDROID_BUILD_OUT}/android/target/product/generic
${ANDROID_SDK_LINUX}/tools/emulator \
-sysdir ${ANDROID_BUILD} \
-system ${ANDROID_BUILD}/system.img \
-ramdisk ${ANDROID_BUILD}/ramdisk.img \
-data ${ANDROID_BUILD}/userdata.img \
-kernel ${ANDROID_SDK_LINUX}/system-images/android-18/armeabi-v7a/kernel-qemu \
-skindir ${ANDROID_SDK_LINUX}/platforms/android-18/skins \
-skin WVGA800 \
-scale 0.7 \
-memory 512 \
-partition-size 1024
On a mac, you can add the following lines into your ~/.bash_profile file. Change your disk image and src folders accordingly.
# start emulator
function startEmulator { hdiutil attach ~/android.dmg.sparseimage -mountpoint /Volumes/android;
cd /Volumes/android/AndroidSrc;
source build/envsetup.sh;
lunch aosp_arm-eng;
/Volumes/android/AndroidSrc/out/host/darwin-x86/bin/emulator; }
After that, create a new terminal and type:
startEmulator
Your emulator can be started. This works on mac.
Just type emulator on your shell and it will launch the emulator of the latest build as its path is set to the PATH variable of your shell.
If you have the "android sdk" on your machine, then your "emulator" could be picked up from there instead of /out/.... dir.
When you want to work with your "own" emulator, you can rename the "android sdk" directory. Then your "emulator" will be picked up.
Hope this helps you!
Regards
Sammoh
export MY_PWD=/work/ABC/Google_Android
export ANDROID_BUILD_TOP=/work/ABC/Google_Android
export PATH=$PATH:$MY_PWD/prebuilts/gcc/linux
export ANDROID_PRODUCT_OUT=$MY_PWD/out/target/product/generic
The above is my env setting.
ANDROID_BUILD_TOP solved the
"emulator: ERROR: You did not specify a virtual device name, and the system
directory could not be found"
on my machine
I performed this way
I modified the ./build/envsetup.sh file, I only changed the set_stuff_for_environment
function set_stuff_for_environment()
{
setpaths
set_sequence_number
export ANDROID_BUILD_TOP=$(gettop)
# With this environment variable new GCC can apply colors to warnings/errors
export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
export ASAN_OPTIONS=detect_leaks=0
export ANDROID_PRODUCT_OUT=/var/www/android/out/target/product/generic_x86_64
echo $ANDROID_PRODUCT_OUT
}
At the root of the project I created a file named start.sh
#!/usr/bin/env bash
ANDROID_BUILD_OUT=/var/www/android/out
ANDROID_SDK_LINUX=/opt/android-studio/sdk
ANDROID_BUILD=${ANDROID_BUILD_OUT}/target/product/generic_x86_64
sudo chmod -R 777 /dev/kvm
source build/envsetup.sh
set_stuff_for_environment
./prebuilts/android-emulator/linux-x86_64/emulator \
-debug-init -logcat '*:v' -verbose \
-sysdir ${ANDROID_BUILD} \
-system ${ANDROID_BUILD}/system.img \
-ramdisk ${ANDROID_BUILD}/ramdisk.img \
-skindir ${ANDROID_SDK_LINUX}/platforms/android-28/skins \
-skin WVGA800 \
-partition-size 2000
-scale 0.7 \
-memory 2000 \
-data ${ANDROID_BUILD}/userdata.img \