Proper use of AndroidDebugBridge

207 views
Skip to first unread message

Roman Mazur

unread,
Apr 22, 2015, 6:15:19 PM4/22/15
to adt...@googlegroups.com

AndroidDebugBridge is a part of ddms Java library. It provides Java interface to what we can do with adb command line.

To get an ADB client using this library, one can use a sequence of init and createBridge methods.
AndroidDebugBridge also has terminate method. And its documentation says that this method must be called when you are done with the client.

AndroidDebugBridge is apparently used by Android Gradle plugin. For example, in tasks that install APK on a device.
Here is an example:
https://android.googlesource.com/platform/tools/base/+/gradle_1.1.3/build-system/builder/src/main/java/com/android/builder/testing/ConnectedDeviceProvider.java#60
Although we can see how init and createBridge are used, I cannot find any calls to terminate() in Android Gradle plugin. Usage search in IDEA shows only 2 usages in AndroidDebugBridgeTest.

This was the reason I contributed some changes to the Spoon tool. This tool runs instrumentation test on devices accessible via USB and generates pretty test reports that include screenshots. To do this, the tool uses AndroidDebugBridge to install APKs and pull screenshot files from a device.

In older versions ADB was initialized with init(false) method (that cannot be called twice beforeterminate is invoked) and createBridge invocation that was forcing a new bridge.
https://github.com/square/spoon/blob/parent-1.1.5/spoon-runner/src/main/java/com/squareup/spoon/SpoonUtils.java#L100-L104
When all the tests have been run and screenshots pulled from the device, Spoon would call terminate()method:
https://github.com/square/spoon/blob/parent-1.1.5/spoon-runner/src/main/java/com/squareup/spoon/SpoonDeviceRunner.java#L359

Such an implementation was causing troubles when spoon was run from the Gradle plugin for multiple flavors:
stanfy/spoon-gradle-plugin#4 (comment)

As a result I changed how AndroidDebugBridge is used in Spoon. Now initialization matches the code inConnectedDevice
https://github.com/square/spoon/blob/parent-1.1.9/spoon-runner/src/main/java/com/squareup/spoon/SpoonUtils.java#L101-L105
and terminate() is not used.

Now it works well with Gradle plugin and I can easily get Spoon reports for multiple application/library bariants.
However, this seems to have sparked new problems to some guys that use standalone Spoon tool.
square/spoon#251
Standalone tool hangs after reports are generated.

Hence, I'm going to push another change :). And my guess is that correct usage would be gettingterminate() invocation back to the code but stick to not forcing a new bridge in createBridge.

Could somebody clarify what is the correct usage scenario for AndroidDebugBridge taking into account that we want to call createBridge multiple times (to get Spoon reports for different build variants)?.
Thanks!

Siva Velusamy

unread,
Apr 22, 2015, 6:51:13 PM4/22/15
to adt...@googlegroups.com
The usage as followed by Studio is:

To create:
  1. AndroidDebugBridge.init(clientSupport);
  2. bridge = AndroidDebugBridge.createBridge(myAdb.getPath(), false);
Finally, when the IDE is closing:
  1. AndroidDebugBridge.disconnectBridge();
  2. AndroidDebugBridge.terminate();


The issue here is that terminate() will result in the adb server being killed. This is not always appropriate, see https://code.google.com/p/android/issues/detail?id=73772: some users run Studio from the command line, and expect adb server to be running after Studio quits. The proposed solution right now would be to kill the server only if it was actually started by Studio. But we don't have an API for that yet in ddmlib.

Coming to your use case, I don't know the exact interactions between the gradle plugin and the spoon plugin, but if your plugin terminates adb server that it launched, then that would be ok, but if it happens to terminate adb launched by gradle, then it seems like you are violating the assumption of the gradle plugin.

So for now, you could call terminate() if you know somehow that the entire gradle invocation is terminating, or not call it and live with the issue that the adb server will keep running..


--
You received this message because you are subscribed to the Google Groups "adt-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to adt-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Roman Mazur

unread,
Apr 23, 2015, 2:22:57 AM4/23/15
to adt...@googlegroups.com
So is it true that Android Gradle plugin does not call terminate? Because otherwise it would kill adb server started by Android Studio?

You received this message because you are subscribed to a topic in the Google Groups "adt-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/adt-dev/1BgTs8Bs6_Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to adt-dev+u...@googlegroups.com.

Siva Velusamy

unread,
Apr 23, 2015, 11:36:20 AM4/23/15
to adt...@googlegroups.com
I'm not sure what the gradle plugin does, maybe xav@ can chime in.

But as far as gradle invoked from Studio goes, we don't invoke anything that uses the device directly from the IDE...Unless ofcourse you explicitly invoke a gradle task such as the one for running tests.

Xavier Ducrohet

unread,
Apr 23, 2015, 1:36:07 PM4/23/15
to adt...@googlegroups.com
terminate() doesn't kill adb, it just stops a few long running ddmlib threads. We should absolutely call it, if we're not doing it it's a a bug.

The trick is to kill it at the right time. I'll look into it.
Xavier Ducrohet
Android SDK Tech Lead
Google Inc.
http://developer.android.com | http://tools.android.com

Please do not send me questions directly. Thanks!

Roman Mazur

unread,
Jul 5, 2015, 9:03:26 AM7/5/15
to adt...@googlegroups.com
Xavier, any updates here?
Reply all
Reply to author
Forward
0 new messages