We are developing a ruby script that executes a bunch of shell commands to launch the emulator and run some calabash tests.
PID = fork do
Signal.trap('HUP') { puts 'PROCESS ENDED'; exit }
exec 'emulator -avd TestDevice1'
end
fork do
sleep(55)
exec 'adb shell input keyevent 82'
end
fork do
sleep(60)
exec 'calabash-android run ~/MyApp/MyApp.apk'
Process.Kill('HUP', PID)
end
We are currently using sleep commands so that the calabash tests don't run until the emulator is fully ready. This is not ideal. Is there an Android command to check if the device is ready? By that I mean Android has booted up and the lock screen is displayed.
The most reliable way I have found to detect if the emulator is ready for use, and for Calabash to start the installation process, is to detect when the bootanim has stopped.
You can check whether the emulator has finished booting manually with using ADB in a terminal:
adb shell getprop init.svc.bootanim
I have the following in a Rake command as part of a Calabash test suite which does the trick:
booting = ''
while booting != 'stopped'
booting = `adb shell getprop init.svc.bootanim`.strip
puts 'Waiting for emulator to boot'
sleep 2
end
Hope it works for you!
Related
I use a Genymotion android emulator for my automated Xamarin UI tests through the bash commands.
The issue is that the emulator is killed by the test runner app after tests are done. So this causes some kind of corruption on the emulator's virtual device file, I suppose.
When I try to start the emulator next time using the same script, I get the following error from Genymotion:
After clicking the update button, Genymotion dashboard opens. Then I can run the emulator by double clicking. But, I cannot do these steps through the shell.
If I could figure out what Genymotion does to repair the emulator, I would do the same thing in the shell script.
Here is my script to run the GM emulator;
cd $HOME
emulatorId=$(VBoxManage list vms | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})" | shuf -n 1)
open -a /Applications/Genymotion.app/Contents/MacOS/player.app --args --vm-name $emulatorId
sleep 5
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done; input keyevent 82'
After this command is executed I run my tests like following;
dotnet test Droid.UI.test.dll
Any solution or workaround for skipping this prompt is highly appreciated,
Thanks!
Your script completely overrides the launchpad; that's the problem. Why not use gmtool? It has been designed especially for this type of use.
I try to develop script to launch armeabi-v7a emulator and execute gradle connectedAndroidTest task to run android device tests targeted to my app.
I wrote script which successfully check required emulator target and download and install it if it is missed and then launch emulator. All these points work well. But After I launch emulator I have to wait until it will be completely booted.
I guess my problem is that I cannot rightful detect that emulator was completely finish his boot operation and is ready to install apps as well.
According to suggestions in web we can use two following system properties to detect complete boot, it is
init.svc.bootanim - state of boot animation
sys.boot_completed - system state of boot operation
We can revise them by calling
adb -e shell getprop init.svc.bootanim and adb -e shell getprop init.svc.bootanim accordingly
I figured out that sys.boot_completed more reliable than init.svc.bootanim, but anyway I wait both of them. But it does not help, because if after waiting device boot I start connectedAndroidTest task after running about 4 minutes it fails with next exception
Unable to install /Users/busylee/temp/TestRun/app/build/outputs/apk/debug/app-debug.apk
com.android.ddmlib.InstallException
at com.android.ddmlib.Device.installRemotePackage(Device.java:1011)
at com.android.ddmlib.Device.installPackage(Device.java:911)
...
Caused by: com.android.ddmlib.ShellCommandUnresponsiveException
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:557)
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:383)
...
But if I wait for a while it completes. Which I guess means that I do not wait something before install test app.
Do you have any ideas what I can rely on while waiting an emulator start?
We have a Xamarin test application, that we run automatically from command line on macOS Sierra. Before it we automatically launch Android emulator from command line. As Android emulator we use x86 emulator, accelerated with Intel HAXM. The script for emulator launching looks in the following way:
function isEmulatorReady {
pathToSDK=$1
#Check that emulator is booted by checking that boot animation is stopped
$pathToSDK/platform-tools/adb wait-for-device shell getprop init.svc.bootanim | grep -m 1 stopped
}
androidSDK=~/Library/Developer/Xamarin/android-sdk-macosx
$androidSDK/platform-tools/adb kill-server
$androidSDK/platform-tools/adb start-server
$androidSDK/tools/emulator -avd Android_Accelerated_x86 -wipe-data -partition-size 512 &
emulatorPID=$!
until isEmulatorReady $androidSDK; do
sleep 1
done
#launch application and wait for end
kill $emulatorPID
Ocassionally adb wait-for-device shell getprop command hangs and script can't detect that emulator is booted, while Android emulator is successfully booted and works. I don't know how to deal with it. The restart of adb server at the beginning doesn't help actually.
I started an Android emulator using the following shell command:
emulator -avd TEST_AVD
The emulator starts just fine, but the shell script never finishes executing. It just hangs there even after the emulator has completed startup. I have tried with a number of other arguments that I could find, but nothing could quite do what I want it to. How do I know, or stop the shell command, when the emulator is ready to go?
I am setting up our Jenkins CI to use a Jenkinsfile to start the emulator, and then run a series of gradle commands. In short, I'd like to do this:
sh "emulator -avd TEST_AVD"
sh "./gradlew clean test spoon"
However, I don't want to run the gradle tasks until the emulator has finished startup, and I can't figure out how to do that in the terminal.
If you want to do something after you start the emulator you should start it in the background
emulator -avd TEST_AVD &
adb wait-for-device
# other stuff here
adb can wait for a device over a transport to be in a particular state
adb wait-for[-<transport>]-<state>
- wait for device to be in the given state:
device, recovery, sideload, or bootloader
Transport is: usb, local or any [default=any]
To wait until device (or emulator) boots, you can do something like this (as was already answered by Пионерка):
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;'
Basically:
Wait for device/emulator to be in adb device state
Open shell & sleep in 1 second intervals until the sys.boot_completed property becomes true
If anybody would be interested what Android Studio does, when running emulator, the answer is this class:
If device is online, then it is ready. No need to go to further steps.
Checks system property adb shell getprop dev.bootcomplete until it is equal to 1
For API 23+ devices runs command to unlock screen: adb shell wm dismiss-keyguard
Waits 1 second.
I am trying to run a shell script in the background on an Android phone via ADB. To simplify let's make it sleep 100:
$ adb shell
$ echo "nohup sleep 100&" > /data/local/tmp/test.sh
$ sh /data/local/tmp/test.sh
(does not block and returns to the shell immediately as expected. However:)
$ exit
(blocks until the sleep process is done)
Doing the same thing through a single adb command line is blocking as well:
$ adb shell sh /data/local/tmp/test.sh
Does run the script correctly, but the adb call blocks until 'sleep 100' is done. The sleep process keeps running if I CTRL-C out of adb, so the nohup part seems to be working correctly.
How can I get adb to exit after spawning the subprocess without forcefully killing the adb process on the host side?
adb shell 'nohup sleep 10 2>/dev/null 1>/dev/null &' works as expected - starts the process and does not block.