Android tests fail on Travis with ShellCommandUnresponsiveException

Sean Barbeau picture Sean Barbeau · Mar 9, 2015 · Viewed 7.3k times · Source

We're seeing a lot of build failures on the first and even second execution of pull requests for our Android project on Travis. However, if we restart the exact same build enough times it eventually passes.

Here's what the error looks like on failures:

:onebusaway-android:connectedAndroidTest
09:48:14 E/Device: Error during shell execution: null
Unable to install /home/travis/build/OneBusAway/onebusaway-android/onebusaway-android/build/outputs/apk/onebusaway-android-debug.apk
com.android.ddmlib.InstallException
at com.android.ddmlib.Device.installPackages(Device.java:927)
at com.android.builder.testing.ConnectedDevice.installPackages(ConnectedDevice.java:105)
at com.android.builder.internal.testing.SimpleTestCallable.call(SimpleTestCallable.java:125)
at com.android.builder.internal.testing.SimpleTestCallable.call(SimpleTestCallable.java:48)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.android.ddmlib.ShellCommandUnresponsiveException
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:513)
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:390)
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:359)
at com.android.ddmlib.Device.executeShellCommand(Device.java:566)
at com.android.ddmlib.Device.createMultiInstallSession(Device.java:987)
at com.android.ddmlib.Device.installPackages(Device.java:884)
... 9 more
com.android.builder.testing.ConnectedDevice > runTests[test(AVD) - 5.0.1] FAILED 
com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException
    at com.android.builder.testing.ConnectedDevice.installPackages(ConnectedDevice.java:108)
null
com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException
at com.android.builder.testing.ConnectedDevice.installPackages(ConnectedDevice.java:108)
at com.android.builder.internal.testing.SimpleTestCallable.call(SimpleTestCallable.java:125)
at com.android.builder.internal.testing.SimpleTestCallable.call(SimpleTestCallable.java:48)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.android.ddmlib.InstallException
at com.android.ddmlib.Device.installPackages(Device.java:927)
at     com.android.builder.testing.ConnectedDevice.installPackages(ConnectedDevice.java:105)
... 8 more
Caused by: com.android.ddmlib.ShellCommandUnresponsiveException
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:513)
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:390)
at com.android.ddmlib.AdbHelper.executeRemoteCommand(AdbHelper.java:359)
at com.android.ddmlib.Device.executeShellCommand(Device.java:566)
at com.android.ddmlib.Device.createMultiInstallSession(Device.java:987)
at com.android.ddmlib.Device.installPackages(Device.java:884)
... 9 more
:onebusaway-android:connectedAndroidTest FAILED
FAILURE: Build failed with an exception.

We're running tests on the emulator on Travis using gradlew connectedTest.

Here's our .travis.yml:

# Test format changes to this .travis.yml file before submitting a PR with:
# http://lint.travis-ci.org/OneBusAway/onebusaway-android

language: android
jdk: oraclejdk7
# Turn off caching to avoid any caching problems
cache: false
# Use the Travis Container-Based Infrastructure (see #203)
sudo: false
env:
  global:
    - ANDROID_API_LEVEL=21
    - ANDROID_BUILD_TOOLS_VERSION=21.1.2
    - ANDROID_ABI=google_apis/armeabi-v7a

android:
  components:
    - platform-tools
    - tools
    - build-tools-$ANDROID_BUILD_TOOLS_VERSION
    - android-$ANDROID_API_LEVEL
    # For Google Maps API v1
    - addon-google_apis-google-$ANDROID_API_LEVEL
    # Google Play Services
    - extra-google-google_play_services
    # Support library
    - extra-android-support
    # Latest artifacts in local repository
    - extra-google-m2repository
    - extra-android-m2repository
    # Specify at least one system image
    - sys-img-armeabi-v7a-addon-google_apis-google-$ANDROID_API_LEVEL

before_script:
  # Create and start emulator
  - echo no | android create avd --force -n test -t "Google Inc.:Google APIs:"$ANDROID_API_LEVEL --abi $ANDROID_ABI
  - emulator -avd test -no-skin -no-audio -no-window &

script:
  - ./wait_for_emulator
  - ./gradlew connectedCheck -PdisablePreDex

# Integration with Gitter (https://gitter.im/OneBusAway/onebusaway-android)
notifications:
  webhooks:
    urls:
      - https://webhooks.gitter.im/e/493b93a98ed03a010c4c
    on_success: change  # options: [always|never|change] default: always
    on_failure: always  # options: [always|never|change] default: always
    on_start: false     # default: false

Answer

Sean Barbeau picture Sean Barbeau · Mar 9, 2015

You can set the environmental variable ADB_INSTALL_TIMEOUT on Travis to a value such as 8 minutes to avoid this problem.

For example, in your .travis.yml:

language: android
jdk: oraclejdk7
# Turn off caching to avoid any caching problems
cache: false
# Use the Travis Container-Based Infrastructure
sudo: false
env:
  global:
    - ANDROID_API_LEVEL=21
    - ANDROID_BUILD_TOOLS_VERSION=21.1.2
    - ANDROID_ABI=armeabi-v7a
    - ADB_INSTALL_TIMEOUT=8 # minutes (2 minutes by default)

android:
  components:
    - platform-tools
    - tools
    - build-tools-$ANDROID_BUILD_TOOLS_VERSION
    - android-$ANDROID_API_LEVEL

The ShellCommandUnresponsiveException is related to AOSP issue 69735: Ddmlib is too agressive with timeouts in Device.java, which causes ddmlib to timeout quickly if it doesn't receive input. The above environmental variable extends this timeout period on the Travis VM.

Also please be sure you're using the latest API level SDK and Build tools (at least the version above), since earlier versions don't allow setting this environmental variable.

Note that this may only resolve your problem if your tests occasionally pass on Travis - if your build always fails you may have other problems going on.

EDIT March 2016

Note that if you're still seeing failures, especially on API Level 23 emulator, there is another emulator timeout issue that may be causing you problems.

To get around this, you'll need to update your Gradle plugin to at least 2.0.0-beta3 - for example:

dependencies {
    classpath 'com.android.tools.build:gradle:2.0.0-beta5'
}

For details see: