Code Monkey home page Code Monkey logo

dadb's Introduction

dadb

Maven Central

Blog Post: Our First Open-Source Project

A Kotlin/Java library to connect directly to an Android device without an adb binary or an ADB server

dependencies {
  implementation("dev.mobile:dadb:<version>")
}

Example Usage

Connect to emulator-5554 and install apkFile:

Dadb.create("localhost", 5555).use { dadb ->
    dadb.install(apkFile)
}

Note: Connect to the odd adb daemon port (5555), not the even emulator console port (5554)

Discover a Device

The following discovers and returns a connected device or emulator. If there are multiple it returns the first one found.

val dadb = Dadb.discover()
if (dadb == null) throw RuntimeException("No adb device found")

Use the following API if you want to list all available devices:

val dadbs = Dadb.list()

Connecting to a physical device

Prerequisite: Connecting to a physical device requires a running adb server. In most cases, this means that you must have the adb binary installed on your machine.

The Dadb.discover() and Dadb.list() methods now both support USB-connected devices.

// Both of these will include any USB-connected devices if they are available
val dadb = Dadb.discover()
val dadbs = Dadb.list()

If you'd like to connect directly to a physical device via its serial number. Use the following API:

val dadb = AdbServer.createDadb(
    adbServerHost = "localhost",
    adbServerPort = 5037,
    deviceQuery = "host:transport:${serialNumber}"
)

Install / Uninstall APK

dadb.install(exampleApkFile)
dadb.uninstall("com.example.app")

Push / Pull Files

dadb.push(srcFile, "/data/local/tmp/dst.txt")
dadb.pull(dstFile, "/data/local/tmp/src.txt")

Execute Shell Command

val response = dadb.shell("echo hello")
assert(response.exitCode == 0)
assert(response.output == "hello\n")

TCP Forwarding

dadb.tcpForward(
    hostPort = 7001,
    targetPort = 7001
).use {
    // localhost:7001 is now forwarded to device's 7001 port
    // Do operations that depend on port forwarding
}

Authentication

Dadb will use your adb key at ~/.android/adbkey by default. If none exists at this location, private and public keys will be generated by dadb.

If you need to specify a custom path to your adb key, use the optional keyPair argument:

val adbKeyPair = AdbKeyPair.read(privateKeyFile, publicKeyFile)
Dadb.create("localhost", 5555, adbKeyPair)

License

Copyright (c) 2021 mobile.dev inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

dadb's People

Contributors

axelniklasson avatar championswimmer avatar dmitry-zaitsev avatar goooler avatar hrimnir avatar igorsmotto avatar leland-takamine avatar mfilenko avatar salvatoret avatar tiann avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dadb's Issues

adb push failed on Android 8.1 devices

	at java.base/java.net.SocketOutputStream.socketWrite0(Native Method)
	at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:110)
	at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:150)
	at okio.OutputStreamSink.write(JvmOkio.kt:56)
	at okio.AsyncTimeout$sink$1.write(AsyncTimeout.kt:99)
	at okio.RealBufferedSink.flush(RealBufferedSink.kt:267)
	at dadb.AdbWriter.write(AdbWriter.kt:92)
	at dadb.AdbWriter.writeClose(AdbWriter.kt:60)
	at dadb.AdbStream.close(AdbStream.kt:118)
	at dadb.AdbStream.nextMessage(AdbStream.kt:109)
	at dadb.AdbStream.access$nextMessage(AdbStream.kt:24)
	at dadb.AdbStream$source$1.message(AdbStream.kt:61)
	at dadb.AdbStream$source$1.read(AdbStream.kt:40)
	at okio.RealBufferedSource.request(RealBufferedSource.kt:206)
	at okio.RealBufferedSource.require(RealBufferedSource.kt:199)
	at okio.RealBufferedSource.readByte(RealBufferedSource.kt:209)
	at dadb.AdbSyncStream.send(AdbSync.kt:73)
	at dadb.Dadb$DefaultImpls.push(Dadb.kt:54)
	at dadb.TestDadb.push(DadbTest.kt:331)
	at dadb.DadbTest$adbPush_basic$1.invoke(DadbTest.kt:119)
	at dadb.DadbTest$adbPush_basic$1.invoke(DadbTest.kt:113)

Use Dadb to connect two Android devices (phone/watch)

Hi, I'm interested in using this library to connect an Android phone to an Android (WearOS) watch, with the Dadb-enabled app running on the phone. ADB over wifi would be enabled on the watch, and I would know the ip address. What I'd hope for is that the phone app makes an adb connection request to the watch's ip address. This would generate a prompt on the watch that the user can accept or reject. If the request is accepted, then the connection is established. This is broadly how I've seen other ADB libraries work.

But I can't figure out how to accomplish that using Dadb. The only example given is connecting to an emulator. The real power of this library would be to connect two actual Android devices over wifi. Please say if this is possible with the current version of Dadb and, if so, give some brief example code.

Thanks.

dadb.install fails when abb_exec is not available

When abb_exec isn't available, the install method falls back to pushing the apk file to the remote device in the /data/local/tmp/ folder and then using 'shell pm install' to try to install it from there. However this will fail with "java.lang.IllegalArgumentException: Error: Can't open file" because the required permissions are missing. After pushing the apk file and before installing there needs to be a further step, something like: shell("chmod 705 "$remotePath"")

Discover and create are hanging endlessly

The discover and create functions are hanging as long as the allow button has not been clicked.
Internally this is the open function that blocks endlessly.
Is this the desired behavior? If so, why?

val dadb = Dadb.discover("192.168.1.62")

screen

It would be great to throw timeout exception after x seconds.
Or throwing something like AuthorizationRequiredException or FailedAuthenticationException would be even better.

It's trivial with the official binary, you just have to check the connect output.

adb connect 192.168.1.62
* daemon not running; starting now at tcp:5037
* daemon started successfully
failed to authenticate to 192.168.1.62:5555

Documentation for dadb.push needs updating

The example given is: dadb.push(srcFile, "/data/local/tmp/dst.txt")

That does not work since push requires 4 parameters including 'mode' and 'last modified time'. I'm actually not sure what the valid values are for 'mode' and couldn't immediately figure it out from the source code.

What are the steps for connecting remotely?

Hi

I need to connect to my device from a CI server to run some automated tests. Is it possible with DADB?

Right now I can connect to a Wireless debugging device that I paired device manually by specifying the serial.


    val dadb = AdbServer.createDadb(
        adbServerHost = "localhost",
        adbServerPort = 5037,
        deviceQuery = "host:transport:192.168.0.55:44973"
    )

The problem with this is that the device must be first connected via USB then paired wirelessly and manually before it can be connected to my device without doing these steps?

@Leland-Takamine

dadb.install-multiple gives error because session is not finalized

I'm trying to install a base.apk and various split.apks using dadb.install-multiple()

This command fails with an error saying that the session isn't finalized. The equivalent ADB command from a Windows command prompt works just fine. As a workaround, I'm using:

dadb.install(base.apk)

then

dadb.install(split1.apk, -p, packageName)
dadb.install(split2.apk, -p, packageName)
dadb.install(split3.apk, -p, packageName)

It would be great if dadb.install-multiple could be fixed though. Thanks.

Usage on android

I want to ask. What is the effort to use it as an android library? is it even possible? I see the JVM target. Thank you. :)

Can port forwarding be done with dadb?

Hi, there. I've been enjoying playing with this library. Thank you so much for it!

I have a need to set up port forwarding, as in adb -s emulator-5554 forward tcp:6100 tcp:7100. I suspect this requires the adb server itself, but I'm still green, figuring out how the protocols work. I've tried my own hand at adding a reboot command, via a simple dadb.open("reboot:"), and that worked. So I toyed with something like that I thought might work for forwarding (e.g. dadb.open("host-serial:5554:forward:tcp:10001;tcp:10001)) based on looking at the ddmlib source for forwarding, but I barely know what I'm doing. Obviously, that didn't work for me. Any advice?

Thanks again for the great library and any help.

Install failed: cmd: Can't find service: package

Trying to run Maestro against an emulator with image system-images;android-31;default;x86_64 but getting an exception while installing the Maestro apk.

here is the full exception:

Running on emulator-5554
java.io.IOException: Failed to install apk /tmp/maestro-app7402534504180399756.apk: Install failed: cmd: Can't find service: package
	at maestro.drivers.AndroidDriver.install(AndroidDriver.kt:426)
	at maestro.drivers.AndroidDriver.installMaestroApks(AndroidDriver.kt:406)
	at maestro.drivers.AndroidDriver.open(AndroidDriver.kt:74)
	at maestro.Maestro$Companion.android(Maestro.kt:403)
	at maestro.Maestro$Companion.android$default(Maestro.kt:401)
	at maestro.cli.util.MaestroFactory.createMaestro(MaestroFactory.kt:40)
	at maestro.cli.command.TestCommand.call(TestCommand.kt:74)
	at maestro.cli.command.TestCommand.call(TestCommand.kt:36)
	at picocli.CommandLine.executeUserObject(CommandLine.java:1933)
	at picocli.CommandLine.access$1200(CommandLine.java:145)
	at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2332)
	at picocli.CommandLine$RunLast.handle(CommandLine.java:2326)
	at picocli.CommandLine$RunLast.handle(CommandLine.java:2291)
	at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2159)
	at picocli.CommandLine.execute(CommandLine.java:2058)
	at maestro.cli.AppKt.main(App.kt:105)
Caused by: java.io.IOException: Install failed: cmd: Can't find service: package
	at dadb.Dadb$DefaultImpls.install(Dadb.kt:85)
	at dadb.adbserver.AdbServerDadb.install(AdbServer.kt:118)
	at maestro.drivers.AndroidDriver.install(AndroidDriver.kt:424)
	... 15 more
cmd: Can't find service: package
cmd: Can't find service: package

Let me know if I can try anything for you to debug this?

Test failures

While trying to add support for API 23 to maestro, I noticed some test failures:
image

Especially the tcp forwarding tests, I suspect that there might be a bug in there which prevents maestro's grpc server to work on 23, but i could be wrong.

Also my cpu usage goes up a lot after running the tests and only goes down after a restart.

SocketException: Broken pipe

On the latest version I get this exception on push and install:

Caused by: java.net.SocketException: Broken pipe
at okio.OutputStreamSink.write(JvmOkio.kt:56)
at okio.AsyncTimeout$sink$1.write(AsyncTimeout.kt:99)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.kt:255)
at okio.RealBufferedSink.writeIntLe(RealBufferedSink.kt:230)
at dadb.AdbWriter.write(AdbWriter.kt:78)
at dadb.AdbWriter.writeOpen(AdbWriter.kt:52)
at dadb.AdbConnection.open(AdbConnection.kt:47)
at dadb.DadbImpl.open(DadbImpl.kt:31)
at dadb.Dadb$DefaultImpls.openShell(Dadb.kt:43)
at dadb.DadbImpl.openShell(DadbImpl.kt:23)
at dadb.Dadb$DefaultImpls.shell(Dadb.kt:36)
at dadb.DadbImpl.shell(DadbImpl.kt:23)

On 1.2.3 file upload is working, but the installation is hanging endlessly. It seems like #41 solved the broken pipe issue, but a later commit reverted it.

I would really appreciate some help!

Upgrade okio dependency to the latest

After adding dadb dependency, got following warning

Provides transitive vulnerable dependency maven:com.squareup.okio:okio:2.10.0
CVE-2023-3635 7.5 Incorrect Conversion between Numeric Types vulnerability with High severity found

It appears we can safely update to okio 3.x (square/okio#982)

Any particular reason for sticking to an old release?

Feature Request: programmatic logging control

Logging is fixed at process start. And always to println()

private val ENABLED = "true" == System.getenv("DADB_LOGGING")

I wanted to use a connection for a sustained period but control logging. Is there a plan to adopt a logging framework (slf4j?) that would allow changing logging.

Does it work with Android application?

I am using computer with adb installed to update some apps on my nvidia shield.
My nvidia shield has network debugging enabled.

I would like to create an android app that could "send adb commands" to my shield.
Can I use your library for this purpose or is it only intended to be used on desktop?
Is there any special permission to give to the android application?

Issue while discovering local device

I am using dadb and it was not able to discover local device,

I am using following code to discover locally connected device
val dadb = Dadb.discover("localhost")
if (dadb == null) throw RuntimeException("No adb device found")

I ran into following error
java.lang.RuntimeException: No adb device found

Base64 not found

error:
java.lang.NoClassDefFoundError: Failed resolution of: Ljava/util/Base64;

Looks like java.util.Base64 is only available on Android starting with API level 26. On older Android versions we'd need to use android.util.Base64

Failed to run shell on marshmallow physical device

Running simple shell:

val dabd = Dadb.discover()
dabd.shell("echo test")

Fails on physical device 6.0 (Marshmallow):

Exception in thread "main" java.io.IOException: Command failed (shell,v2,raw:echo test): closed
	at dadb.adbserver.AdbServer.send$dadb(AdbServer.kt:99)
	at dadb.adbserver.AdbServerDadb.open(AdbServer.kt:138)
	at dadb.Dadb$DefaultImpls.openShell(Dadb.kt:43)
	at dadb.adbserver.AdbServerDadb.openShell(AdbServer.kt:118)
	at dadb.Dadb$DefaultImpls.shell(Dadb.kt:36)
	at dadb.adbserver.AdbServerDadb.shell(AdbServer.kt:118)

Android Debug Bridge version 1.0.41
Version 33.0.3-8952118

Any ideas why?

Any hint about KeyPair?

Thank you so much for this library.
I request to put something about Authentication in documentation.

Dadb.list throws IOException on unauthorized device (OFFLINE)?

Exception in thread "main" java.io.IOException: Command failed (host:transport:131xxxxxxx19J): device unauthorized.
This adb server's $ADB_VENDOR_KEYS is not set
Try 'adb kill-server' if that seems wrong.
Otherwise check for a confirmation dialog on your device.
	at dadb.adbserver.AdbServer.send$dadb(AdbServer.kt:99)
	at dadb.adbserver.AdbServerDadb.open(AdbServer.kt:137)
	at dadb.adbserver.AdbServerDadb.<init>(AdbServer.kt:128)
	at dadb.adbserver.AdbServer.createDadb(AdbServer.kt:52)
	at dadb.adbserver.AdbServer.listDadbs(AdbServer.kt:81)
	at dadb.adbserver.AdbServer.listDadbs$default(AdbServer.kt:60)
	at dadb.Dadb$Companion.list(Dadb.kt:244)
	at dadb.Dadb$Companion.list$default(Dadb.kt:243)
	at LogcatKt.list(Logcat.kt:36)

Discover returns an error

Hi guys,

I'm Victor, and I'm trying to run the library in a poc application to know how to use it. But the first method that I'm trying is "discover", but it returning me a FileNotFoundException

I'm doing:

fun discover(){
        try {
            val result = Dadb.discover("localhost")
            binding.tvcommandline.text = "" + result.toString()
        }catch (ex: java.lang.RuntimeException){
            binding.tvcommandline.text = "Failed to discover emulator. No adb device found"
            ex.printStackTrace()
        }
    }

The error is:

Caused by: java.io.FileNotFoundException: .android/adbkey: open failed: ENOENT (No such file or directory)

Some advice?

I'm testing on a Samsung S20 Ultra with Android 12 and connected via USB.

Thank you

[Discussion] KMP support

I'm trying to use a combination of dadb and grpc to the emulator to implement some useful functions when using emulators.

This led me to a couple of questions

  1. Have you considered Kotlin multiplatform support? You are already using Okio, which is KMP enabled and there is code for KMP Certificate handling code in github.com/cashapp/certifikit. Generally seems like a incremental change that could unlock a lot of other cases.
  2. Have you considered supporting gRPC in Dadb also?

I have a working implementation of gRPC using Square's Wire project (again KMP native)

https://github.com/yschimke/emulator-tools/blob/main/src/jvmMain/kotlin/ee/schimke/emulatortools/Main.kt#L41-L48

again, please close if this it undesired or out of scope and I'll maintain the bits I need separately.

Crash with Command failed (host:features): more than one device/emulator

I am using DADB but it fails with Command failed (host:features): more than one device/emulator

supportedFeatures = open("host:features").use {

Exception in thread "main" java.io.IOException: Command failed (host:features): more than one device/emulator
	at dadb.adbserver.AdbServer.send$dadb(AdbServer.kt:99)
	at dadb.adbserver.AdbServerDadb.open(AdbServer.kt:138)
	at dadb.adbserver.AdbServerDadb.<init>(AdbServer.kt:128)
	at dadb.adbserver.AdbServer.createDadb(AdbServer.kt:52)
	at dadb.adbserver.AdbServer.listDadbs(AdbServer.kt:81)
	at dadb.adbserver.AdbServer.listDadbs$default(AdbServer.kt:60)
	at dadb.Dadb$Companion.list(Dadb.kt:251)
	at dadb.Dadb$Companion.list$default(Dadb.kt:250)

dadb.AdbStreamClosed: ADB stream is closed for localId: e2527064

I'm getting the following error when calling dadb.install.

dadb.AdbStreamClosed: ADB stream is closed for localId: e2527064

It looks like it returns a close command immediately when it receives the abb_execute command.

When the server receives the message it only returns the close command if it can't read the response for some reason.
https://cs.android.com/android/platform/superproject/+/master:packages/modules/adb/adb.cpp;drc=867c71e5114e76b4f64e9f38e1be060fd9ba3a26;l=475

Sending shell commands work fine. Calling the install command through adb on my local machine to the same target host also works fine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.