1ANDROID REMOTE HCI APP 2====================== 3 4This application allows using an android phone's built-in Bluetooth controller with 5a Bumble host stack running outside the phone (typically a development laptop or desktop). 6The app runs an HCI proxy between a TCP socket on the "outside" and the Bluetooth HCI HAL 7on the "inside". (See [this page](https://source.android.com/docs/core/connect/bluetooth) for a high level 8description of the Android Bluetooth HCI HAL). 9The HCI packets received on the TCP socket are forwarded to the phone's controller, and the 10packets coming from the controller are forwarded to the TCP socket. 11 12 13Building 14-------- 15 16You can build the app by running `./gradlew build` (use `gradlew.bat` on Windows) from the `extras/android/RemoteHCI` top level directory. 17You can also build with Android Studio: open the `RemoteHCI` project. You can build and/or debug from there. 18 19If the build succeeds, you can find the app APKs (debug and release) at: 20 21 * [Release] ``app/build/outputs/apk/release/app-release-unsigned.apk`` 22 * [Debug] ``app/build/outputs/apk/debug/app-debug.apk`` 23 24 25Running 26------- 27 28!!! note 29 In the following examples, it is assumed that shell commands are executed while in the 30 app's root directory, `extras/android/RemoteHCI`. If you are in a different directory, 31 adjust the relative paths accordingly. 32 33### Preconditions 34When the proxy starts (tapping the "Start" button in the app's main activity, or running the proxy 35from an `adb shell` command line), it will try to bind to the Bluetooth HAL. 36This requires that there is no other HAL client, and requires certain privileges. 37For running as a regular app, this requires disabling SELinux temporarily. 38For running as a command-line executable, this just requires a root shell. 39 40#### Root Shell 41!!! tip "Restart `adb` as root" 42 ```bash 43 $ adb root 44 ``` 45 46#### Disabling SELinux 47Binding to the Bluetooth HCI HAL requires certain SELinux permissions that can't simply be changed 48on a device without rebuilding its system image. To bypass these restrictions, you will need 49to disable SELinux on your phone (please be aware that this is global, not just for the proxy app, 50so proceed with caution). 51In order to disable SELinux, you need to root the phone (it may be advisable to do this on a 52development phone). 53 54!!! tip "Disabling SELinux Temporarily" 55 Restart `adb` as root: 56 ```bash 57 $ adb root 58 ``` 59 60 Then disable SELinux 61 ```bash 62 $ adb shell setenforce 0 63 ``` 64 65 Once you're done using the proxy, you can restore SELinux, if you need to, with 66 ```bash 67 $ adb shell setenforce 1 68 ``` 69 70 This state will also reset to the normal SELinux enforcement when you reboot. 71 72#### Stopping the bluetooth process 73Since the Bluetooth HAL service can only accept one client, and that in normal conditions 74that client is the Android's bluetooth stack, it is required to first shut down the 75Android bluetooth stack process. 76 77!!! tip "Checking if the Bluetooth process is running" 78 ```bash 79 $ adb shell "ps -A | grep com.google.android.bluetooth" 80 ``` 81 If the process is running, you will get a line like: 82 ``` 83 bluetooth 10759 876 17455796 136620 do_epoll_wait 0 S com.google.android.bluetooth 84 ``` 85 If you don't, it means that the process is not running and you are clear to proceed. 86 87Simply turning Bluetooth off from the phone's settings does not ensure that the bluetooth process will exit. 88If the bluetooth process is still running after toggling Bluetooth off from the settings, you may try enabling 89Airplane Mode, then rebooting. The bluetooth process should, in theory, not restart after the reboot. 90 91!!! tip "Stopping the bluetooth process with adb" 92 ```bash 93 $ adb shell cmd bluetooth_manager disable 94 ``` 95 96### Running as a command line app 97 98You push the built APK to a temporary location on the phone's filesystem, then launch the command 99line executable with an `adb shell` command. 100 101!!! tip "Pushing the executable" 102 ```bash 103 $ adb push app/build/outputs/apk/release/app-release-unsigned.apk /data/local/tmp/remotehci.apk 104 ``` 105 Do this every time you rebuild. Alternatively, you can push the `debug` APK instead: 106 ```bash 107 $ adb push app/build/outputs/apk/debug/app-debug.apk /data/local/tmp/remotehci.apk 108 ``` 109 110!!! tip "Start the proxy from the command line" 111 ```bash 112 adb shell "CLASSPATH=/data/local/tmp/remotehci.apk app_process /system/bin com.github.google.bumble.remotehci.CommandLineInterface" 113 ``` 114 This will run the proxy, listening on the default TCP port. 115 If you want a different port, pass it as a command line parameter 116 117!!! tip "Start the proxy from the command line with a specific TCP port" 118 ```bash 119 adb shell "CLASSPATH=/data/local/tmp/remotehci.apk app_process /system/bin com.github.google.bumble.remotehci.CommandLineInterface 12345" 120 ``` 121 122### Running as a normal app 123You can start the app from the Android launcher, from Android Studio, or with `adb` 124 125#### Launching from the launcher 126Just tap the app icon on the launcher, check the TCP port that is configured, and tap 127the "Start" button. 128 129#### Launching with `adb` 130Using the `am` command, you can start the activity, and pass it arguments so that you can 131automatically start the proxy, and/or set the port number. 132 133!!! tip "Launching from adb with auto-start" 134 ```bash 135 $ adb shell am start -n com.github.google.bumble.remotehci/.MainActivity --ez autostart true 136 ``` 137 138!!! tip "Launching from adb with auto-start and a port" 139 In this example, we auto-start the proxy upon launch, with the port set to 9995 140 ```bash 141 $ adb shell am start -n com.github.google.bumble.remotehci/.MainActivity --ez autostart true --ei port 9995 142 ``` 143 144#### Selecting a TCP port 145The RemoteHCI app's main activity has a "TCP Port" setting where you can change the port on 146which the proxy is accepting connections. If the default value isn't suitable, you can 147change it there (you can also use the special value 0 to let the OS assign a port number for you). 148 149### Connecting to the proxy 150To connect the Bumble stack to the proxy, you need to be able to reach the phone's network 151stack. This can be done over the phone's WiFi connection, or, alternatively, using an `adb` 152TCP forward (which should be faster than over WiFi). 153 154!!! tip "Forwarding TCP with `adb`" 155 To connect to the proxy via an `adb` TCP forward, use: 156 ```bash 157 $ adb forward tcp:<outside-port> tcp:<inside-port> 158 ``` 159 Where ``<outside-port>`` is the port number for a listening socket on your laptop or 160 desktop machine, and <inside-port> is the TCP port selected in the app's user interface. 161 Those two ports may be the same, of course. 162 For example, with the default TCP port 9993: 163 ```bash 164 $ adb forward tcp:9993 tcp:9993 165 ``` 166 167Once you've ensured that you can reach the proxy's TCP port on the phone, either directly or 168via an `adb` forward, you can then use it as a Bumble transport, using the transport name: 169``tcp-client:<host>:<port>`` syntax. 170 171!!! example "Connecting a Bumble client" 172 Connecting the `bumble-controller-info` app to the phone's controller. 173 Assuming you have set up an `adb` forward on port 9993: 174 ```bash 175 $ bumble-controller-info tcp-client:localhost:9993 176 ``` 177 178 Or over WiFi with, in this example, the IP address of the phone being ```192.168.86.27``` 179 ```bash 180 $ bumble-controller-info tcp-client:192.168.86.27:9993 181 ``` 182