Final Update - Solution - The installation after connecting to correct port failed because installation leaked file descriptors. Updating env variables as suggested in here solves the issue
UPDATE2 It seems environment variables changes the target port of gradle commands but not the wait-loop of emulator plugin itself. I decided to start emulator manually with
/var/lib/jenkins/android-sdk/emulator/emulator -avd testing24xlarge2 -wipe-data -no-window -no-audio -partition-size 4096 -ports 5558,5559&
EMULATOR_PID=$!
Here I realized, I don't specify the adb timeout so I decided to use a tcp port used by plugin before and try again but this doesn't help the slightest.
/var/lib/jenkins/android-sdk/emulator/emulator -report-console tcp:5829,max=96000 -avd testing24xlarge2 -wipe-data -no-window -no-audio -partition-size 4096 -ports 5558,5559&
EMULATOR_PID=$!
. One possible but unlikely reason I can think of is debug apk being too large(apps I try vary from 200 Mb to 700 mb) may cause this but error message doesn't seem to indicate that. Trying to install the app with adb commands instead of gradle tasks also didn't help
android {
adbOptions {
timeOutInMs 6000000 // set timeout to 100 minutes
}
}
./gradlew assembleStagingDebug --no-daemon -Dkotlin.compiler.execution.strategy="in-process"
./gradlew assembleStagingDebugAndroidTest --no-daemon -Dkotlin.compiler.execution.strategy="in-process"
/var/lib/jenkins/android-sdk/platform-tools/adb -s emulator-5558 shell input keyevent 82
/var/lib/jenkins/android-sdk/platform-tools/adb -s emulator-5558 install -r -t myapp/build/outputs/apk/staging/debug/myapp-staging-debug.apk
/var/lib/jenkins/android-sdk/platform-tools/adb -s emulator-5558 install -r -t myapp/build/outputs/apk/androidTest/staging/debug/myapp-staging-debug-androidTest.apk
#/var/lib/jenkins/android-sdk/platform-tools/adb -e shell am instrument -w mypackage.testcases.tests/androidx.test.runner.AndroidJUnitRunner
I will update this post again after I try this with an "acceptable apk size"
UPDATE: I think I have identified the problem correctly but I still can't get it to work.
Ddmlib looks for the ports between 5555,5586 and naturally app installation fails when the emulator is in a different port.
In official docs it suggests that we can make use of environment variables to make emulator plugin search for the device in the port we want. But none of the env variables related to port (ANDROID_SERIAL, ANDROID_AVD_DEVICE etc) (I set them in my main Jenkins config) changed the target of adb -s . So changing the port emulator runs in manually with ports 5558,5559 fails as the emulator starts in port 5558 but
/var/lib/jenkins/android-sdk/platform-tools/adb -s emulator-5776 wait-for-device shell getprop dev.bootcomplete
runs in the randomly assigned port of emulator plugin and it gets stuck as emulator starts in the port I selected.
_______________________________________________________________________________
After solving tens of different problems to open and run UI tests in emulator, I am hopefully stuck at the last problem and I tried everything I can think of but it didn't work.
Environment : I am using an emulator with API level: 24 in an app with Min SDK = 24 to avoid INCOMPATIBLE_DEVICE_ERROR. Jenkins runs in Ubuntu 20.04 but I don't think it matters.My target sdk and compile sdk are 28 (I will also try to downgrade them but since I have solved INCOMPATIBLE error I doubt this will solve the issue). Adb timeout is 96000 sec and startup delay is 20 sec for good measure.
As the scripts below will demonstrate, I am pretty sure, I can find the connected emulator via adb command but when it comes to install and run tests, I tried two different solutions but with both of them I am stuck.
First solution attempt
while [ "`/var/lib/jenkins/android-sdk/platform-tools/adb shell getprop service.bootanim.exit | tr -d '\r' `" != "1" ] ; do sleep 1; done
/var/lib/jenkins/android-sdk/platform-tools/adb devices -l
/var/lib/jenkins/android-sdk/platform-tools/adb shell input keyevent 82
./gradlew myapp:connectedStagingDebugAndroidTest --no-daemon -Dkotlin.compiler.execution.strategy="in-process"
It correctly waits for the device to launch(android emulator plugin also checks for sys.boot_completed before this) and it lists the connected device /passes the input key event 82
This results in the following error
om.android.build.gradle.internal.testing.ConnectedDevice > runTests[testing24xlarge2(AVD) - 7.0] [31mFAILED [0m
com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException
at com.android.build.gradle.internal.testing.ConnectedDevice.installPackage(ConnectedDevice.java:132)
[no message defined]
java.util.concurrent.ExecutionException: java.lang.RuntimeException: com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException
at java.util.concurrent.ForkJoinTask.get(ForkJoinTask.java:1006)
at com.android.ide.common.workers.ExecutorServiceAdapter.await(ExecutorServiceAdapter.kt:102)
at com.android.build.gradle.internal.testing.BaseTestRunner.runTests(BaseTestRunner.java:201)
at com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask.lambda$doTaskAction$2(DeviceProviderInstrumentTestTask.java:201)
at com.android.builder.testing.api.DeviceProvider.use(DeviceProvider.java:53)
at com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask.doTaskAction(DeviceProviderInstrumentTestTask.java:191)
at
Caused by: java.lang.RuntimeException: com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException
at com.android.build.gradle.internal.testing.SimpleTestRunnable.run(SimpleTestRunnable.java:231)
Caused by: com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException
at com.android.build.gradle.internal.testing.ConnectedDevice.installPackage(ConnectedDevice.java:132)
at com.android.build.gradle.internal.testing.SimpleTestRunnable.run(SimpleTestRunnable.java:134)
... 116 more
Caused by: com.android.ddmlib.InstallException
at com.android.ddmlib.Device.installRemotePackage(Device.java:1174)
at com.android.ddmlib.Device.installPackage(Device.java:998)
at com.android.ddmlib.Device.installPackage(Device.java:974)
at com.android.ddmlib.Device.installPackage(Device.java:963)
at com.android.build.gradle.internal.testing.ConnectedDevice.installPackage(ConnectedDevice.java:126)
... 117 more
Caused by: com.android.ddmlib.ShellCommandUnresponsiveException
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:553)
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:378)
at com.android.ddmlib.Device.executeShellCommand(Device.java:675)
at com.android.ddmlib.Device.installRemotePackage(Device.java:1165)
... 121 more
(I have tried to cut as much as the exception chain as possible without limiting important info)
Here you can see that emulator is attached
+ /var/lib/jenkins/android-sdk/platform-tools/adb devices -l
List of devices attached
emulator-5802 device product:sdk_google_phone_armv7 model:sdk_google_phone_armv7 device:generic transport_id:1
Second solution attempt which is advised here here also doesn't work
./gradlew clean
./gradlew assembleDebug
./gradlew assembleDebugAndroidTest
/var/lib/jenkins/android-sdk/platform-tools/adb install app/build/outputs/apk/app-debug.apk
/var/lib/jenkins/android-sdk/platform-tools/adb install app/build/outputs/apk/app-debug-androidTest-unaligned.apk
/var/lib/jenkins/android-sdk/platform-tools/adbshell am instrument -w com.google.samples.apps.topeka.test/android.support.test.runner.AndroidJUnitRunner
Problem here is that after
/var/lib/jenkins/android-sdk/platform-tools/adb shell input keyevent 82
/var/lib/jenkins/android-sdk/platform-tools/adb install -r -t -g myapp/build/outputs/apk/staging/debug/myapp-staging-debug.apk //I have also tried adb -e to target the emulator as it is the only running device
Console output just freezes at the install command (both with flags and without the flags -r -t -g) and as you might guess next commands do not get executed. After waiting for a lot of time, I get the following error which says adb might not work because of the port emulator is in.
adb: failed to install myapp/build/outputs/apk/staging/debug/myapp-staging-debug.apk: Performing Streamed Install
Build step 'Execute shell' marked build as failure
[android] Stopping Android emulator
emulator: WARNING: encryption is off
emulator: feeding guest with passive gps data, in headless mode
emulator: WARNING: Requested adb port (5775) is outside the recommended range [5555,5586]. ADB may not function properly for the emulator. See -help-port for details.
saving arm snapshot.... !!!
Does this fail because the port is wrong? How can I specify port number I want in Emulator Plugin? It only lets me
Assign unique TCP ports to avoid collisions. And if I specify it in emulator options, it still tries to execute adb commands with the random port no it allocated, so that doesn't work. Next I tried to copy the scripts I see in the console to launch emulator myself but it also doesn't seem to work(emulator doesn't start when I manually add the commands
/var/lib/jenkins/android-sdk/platform-tools/adb start-server
/var/lib/jenkins/android-sdk/emulator/emulator -report-console tcp:5845,max=96000 -avd testing24xlarge2 -wipe-data -no-window -partition-size 4096 -ports 5558,5559
while [ "`/var/lib/jenkins/android-sdk/platform-tools/adb shell getprop service.bootanim.exit | tr -d '\r' `" != "1" ] ; do sleep 1; done //Doesn't pass here
I am completely stuck here and probably lost most of my hair, either a fix to the first solution attempt or second solution attempt is acceptable.