Introducing: Android DebugPort 2.0

A drop-in tool to connect to your app and execute both Java and SQL commands from the comfort of your computer’s terminal.

Nowadays it’s fairly common for languages and platforms to provide a REPL (Read Eval Print Loop) to make it easy to execute arbitrary code from the command line. While a Java REPL is in the works for Java 9, I imagine we’re going to have to wait many years before we can use it with Android apps — if we ever get to use it.

With that in mind, about a year ago I started working on Android DebugPort. Version 1 allowed you to call into the library and start up two telnet servers: one that exposed a REPL into your app’s runtime, and another that exposed a SQLite console to run queries against your app’s databases.

Today, I released version 2.

The inner-workings of the REPL telnet servers has remained the same, however the big new feature in Android DebugPort 2 is that it is now a super-simple drop-in library. All you need to do to get it working with your app is add the dependencies to your build.gradle and a MIN_PRIORITY notification will be available in your device’s system tray which allows you to start and stop the servers.

Getting Started

Add the following to your project root’s build.gradle if you don’t already have jitpack defined as a repository:

Then, add Android DebugPort dependencies in your app module’s build.gradle:

Note: The lib-noop dependency for releaseCompile makes it so that your production builds do not include a working version of the DebugPortService at all, and avoids exposing your app via a REPL to your users in the Play Store.

Start up your app and you’ll see the DebugPort notification in your system tray, then tap on the “Start” button to start up the REPL servers. Tapping the “Kill” button will kill the notification and stop any running servers.

After tapping “Start”, you can use telnet on your computer to connect to your app!

The Debug REPL

$ telnet 192.168.2.27 8562
Trying 192.168.2.27...
Connected to 192.168.2.27.
Escape character is '^]'.
Android DebugPort v2.0.0
Report issues at https://github.com/jasonwyatt/Android-DebugPort/issues
BeanShell 2.0b6 - by Pat Niemeyer (pat@pat.net)
bsh %

The tool’s Debug REPL is based on beanshell and automatically exposes a variable referencing your app’s Application class: app. Aside from being able to run just about any Java statement, it also contains a number of pre-defined helper methods you can use to inspect state. Run help(); to see what they are:

bsh % help();
Available Commands:
Access:
call(Object obj, String method, Object... params)
Call a method, regardless of access modifiers, on the
provided object.
get(Object obj, String fieldName)
Get the value of a field, regardless of access modifiers,
on the provided object.
set(Object obj, String fieldName, Object value)
Set the value of a field on the provided object to the
given value, regardless of access modifiers.
Field Inspection:
fields(Class class)
List all of the fields available for a particular class.
fields(Object obj)
List all of the fields available for a particular object.
fieldsLocal(Class class)
List all of the fields defined locally for a particular
class.
fieldsLocal(Object obj)
List all of the fields defined locally for an object.
Method Inspection:
methods(Class class)
Get the available methods for the provided class.
methods(Object obj)
Get the available methods for the provided object.
methodsLocal(Class class)
Show all of the locally-declared methods for the provided
class.
methodsLocal(Object obj)
Show all of the locally-declared methods for the provided
object.
Other:
exit()
Exit this interpreter.
help()
Show this help message.
source(String scriptPath)
Load and run a Beanshell script within your app's assets
folder.
bsh % 

One particular command that can be quite helpful is source(scriptPath);. Using it, you can run any beanshell script contained in your app’s assets folder. This helps when you want to be able to run a particular operation over and over.

For example: Imagine your app has a feature which highlights an element when an event is seen on an event bus. To do this manually in the REPL you would need to import any classes needed to trigger the event, then trigger it. With source(scriptPath) you pass the name of a script that encapsulates all that code and does the work for you, without requiring you to type it all into the command line every time.

The SQLite REPL

It can be a real pain in the rear to figure out the state of your app’s SQLite databases without help: you need to root your phone, then extract the database file using adb and open it locally on your computer.

With Android DebugPort, you no-longer need to go through that pain. Instead, just telnet to the SQLite server, pick one of your databases, and start running queries!

$ telnet 192.168.2.27 8563
Trying 192.168.2.27...
Connected to 192.168.2.27.
Escape character is '^]'.
Android DebugPort v2.0.0
Report issues at https://github.com/jasonwyatt/Android-DebugPort/issues
SQLite Database REPL
sqlite> show databases;
+----------+
| Database |
+----------+
| my_data |
+----------+
sqlite> use my_data;
Using database `my_data`
sqlite> 

As with the Debug REPL, the SQLite REPL also provides some help to explain the added functionality built into Android DebugPort for working with your databases:

sqlite> help;
Help:
As you'd expect, you can execute any valid SQLite statements
against the database to which you're currently connected (see:
`USE [database name];` below).
  In addition to regular SQLite commands, Android DebugPort provides 
additional functionality via several additional commands.
  Available non-SQLite commands (case insensitive):
Databases:
CREATE DATABASE [database name];
Create a new database called [database name].
DROP DATABASE [database name];
Drop the database named [database name] from the app's
collection of databases.
USE [database name];
Connect to the database called [database name]. All SQL
commands will be executed against this database until
USE is called again.
    Inspection:
SHOW CREATE TABLE [table name];
Show the CREATE TABLE command used to create [table
name].
SHOW DATABASES;
Show all available databases for the app, including
temporary databases.
SHOW TABLES;
Show all of the tables defined for the database to which
you are currently connected.
    Other:
exit; or quit;
Exit this interpreter.
help;
Show this help message.
sqlite>

Wrapping Up

In the project’s README, there are additional instructions for how you can customize the ports on which to run the servers. It also explains how to provide some additional beanshell commands to run when the Debug REPL starts up.

I want to thank GitHub user nohum for pointing me in the right direction for implementing the drop-in support for version 2.0.

I hope you find Android DebugPort as useful in your projects as I have in mine!