diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml index 82a6f419..67bdd7ca 100644 --- a/docs/mkdocs/mkdocs.yml +++ b/docs/mkdocs/mkdocs.yml @@ -67,6 +67,9 @@ nav: - Zephyr: platforms/zephyr.md - Examples: - Overview: examples/index.md + - Extras: + - Overview: extras/index.md + - Android Remote HCI: extras/android_remote_hci.md copyright: Copyright 2021-2023 Google LLC diff --git a/docs/mkdocs/src/extras/android_remote_hci.md b/docs/mkdocs/src/extras/android_remote_hci.md new file mode 100644 index 00000000..4eab132e --- /dev/null +++ b/docs/mkdocs/src/extras/android_remote_hci.md @@ -0,0 +1,141 @@ +ANDROID REMOTE HCI APP +====================== + +This application allows using an android phone's built-in Bluetooth controller with +a Bumble host stack running outside the phone (typically a development laptop or desktop). +The app runs an HCI proxy between a TCP socket on the "outside" and the Bluetooth HCI HAL +on the "inside". (See [this page](https://source.android.com/docs/core/connect/bluetooth) for a high level +description of the Android Bluetooth HCI HAL). +The HCI packets received on the TCP socket are forwarded to the phone's controller, and the +packets coming from the controller are forwarded to the TCP socket. + + +Building +-------- + +You can build the app by running `./gradlew build` (use `gradlew.bat` on Windows) from the `RemoteHCI` top level directory. +You can also build with Android Studio: open the `RemoteHCI` project. You can build and/or debug from there. + +If the build succeeds, you can find the app APKs (debug and release) at: + + * [Release] ``app/build/outputs/apk/release/app-release-unsigned.apk`` + * [Debug] ``app/build/outputs/apk/debug/app-debug.apk`` + + +Running +------- + +### Preconditions +When the proxy starts (tapping the "Start" button in the app's main activity), it will try to +bind to the Bluetooth HAL. This requires disabling SELinux temporarily, and being the only HAL client. + +#### Disabling SELinux +Binding to the Bluetooth HCI HAL requires certain SELinux permissions that can't simply be changed +on a device without rebuilding its system image. To bypass these restrictions, you will need +to disable SELinux on your phone (please be aware that this is global, not just for the proxy app, +so proceed with caution). +In order to disable SELinux, you need to root the phone (it may be advisable to do this on a +development phone). + +!!! tip "Disabling SELinux Temporarily" + Restart `adb` as root: + ```bash + $ adb root + ``` + + Then disable SELinux + ```bash + $ adb shell setenforce 0 + ``` + + Once you're done using the proxy, you can restore SELinux, if you need to, with + ```bash + $ adb shell setenforce 1 + ``` + + This state will also reset to the normal SELinux enforcement when you reboot. + +#### Stopping the bluetooth process +Since the Bluetooth HAL service can only accept one client, and that in normal conditions +that client is the Android's bluetooth stack, it is required to first shut down the +Android bluetooth stack process. + +!!! tip "Checking if the Bluetooth process is running" + ```bash + $ adb shell "ps -A | grep com.google.android.bluetooth" + ``` + If the process is running, you will get a line like: + ``` + bluetooth 10759 876 17455796 136620 do_epoll_wait 0 S com.google.android.bluetooth + ``` + If you don't, it means that the process is not running and you are clear to proceed. + +Simply turning Bluetooth off from the phone's settings does not ensure that the bluetooth process will exit. +If the bluetooth process is still running after toggling Bluetooth off from the settings, you may try enabling +Airplane Mode, then rebooting. The bluetooth process should, in theory, not restart after the reboot. + +!!! tip "Stopping the bluetooth process with adb" + ```bash + $ adb shell cmd bluetooth_manager disable + ``` + +### Starting the app +You can start the app from the Android launcher, from Android Studio, or with `adb` + +#### Launching from the launcher +Just tap the app icon on the launcher, check the TCP port that is configured, and tap +the "Start" button. + +#### Launching with `adb` +Using the `am` command, you can start the activity, and pass it arguments so that you can +automatically start the proxy, and/or set the port number. + +!!! tip "Launching from adb with auto-start" + ```bash + $ adb shell am start -n com.github.google.bumble.remotehci/.MainActivity --ez autostart true + ``` + +!!! tip "Launching from adb with auto-start and a port" + In this example, we auto-start the proxy upon launch, with the port set to 9995 + ```bash + $ adb shell am start -n com.github.google.bumble.remotehci/.MainActivity --ez autostart true --ei port 9995 + ``` + +#### Selecting a TCP port +The RemoteHCI app's main activity has a "TCP Port" setting where you can change the port on +which the proxy is accepting connections. If the default value isn't suitable, you can +change it there (you can also use the special value 0 to let the OS assign a port number for you). + +### Connecting to the proxy +To connect the Bumble stack to the proxy, you need to be able to reach the phone's network +stack. This can be done over the phone's WiFi connection, or, alternatively, using an `adb` +TCP forward (which should be faster than over WiFi). + +!!! tip "Forwarding TCP with `adb`" + To connect to the proxy via an `adb` TCP forward, use: + ```bash + $ adb forward tcp: tcp: + ``` + Where ```` is the port number for a listening socket on your laptop or + desktop machine, and is the TCP port selected in the app's user interface. + Those two ports may be the same, of course. + For example, with the default TCP port 9993: + ```bash + $ adb forward tcp:9993 tcp:9993 + ``` + +Once you've ensured that you can reach the proxy's TCP port on the phone, either directly or +via an `adb` forward, you can then use it as a Bumble transport, using the transport name: +``tcp-client::`` syntax. + +!!! example "Connecting a Bumble client" + Connecting the `bumble-controller-info` app to the phone's controller. + Assuming you have set up an `adb` forward on port 9993: + ```bash + $ bumble-controller-info tcp-client:localhost:9993 + ``` + + Or over WiFi with, in this example, the IP address of the phone being ```192.168.86.27``` + ```bash + $ bumble-controller-info tcp-client:192.168.86.27:9993 + ``` diff --git a/docs/mkdocs/src/extras/index.md b/docs/mkdocs/src/extras/index.md new file mode 100644 index 00000000..ae906c1b --- /dev/null +++ b/docs/mkdocs/src/extras/index.md @@ -0,0 +1,11 @@ +EXTRAS +====== + +A collection of add-ons, apps and tools, to the Bumble project. + +Android Remote HCI +------------------ + +Allows using an Android phone's built-in Bluetooth controller with a Bumble +stack running on a development machine. +See [Android Remote HCI](android_remote_hci.md) for details. \ No newline at end of file diff --git a/docs/mkdocs/src/hardware/index.md b/docs/mkdocs/src/hardware/index.md index 986532ba..9eabab0a 100644 --- a/docs/mkdocs/src/hardware/index.md +++ b/docs/mkdocs/src/hardware/index.md @@ -3,7 +3,7 @@ HARDWARE The Bumble Host connects to a controller over an [HCI Transport](../transports/index.md). To use a hardware controller attached to the host on which the host application is running, the transport is typically either [HCI over UART](../transports/serial.md) or [HCI over USB](../transports/usb.md). -On Linux, the [VHCI Transport](../transports/vhci.md) can be used to communicate with any controller hardware managed by the operating system. Alternatively, a remote controller (a phyiscal controller attached to a remote host) can be used by connecting one of the networked transports (such as the [TCP Client transport](../transports/tcp_client.md), the [TCP Server transport](../transports/tcp_server.md) or the [UDP Transport](../transports/udp.md)) to an [HCI Bridge](../apps_and_tools/hci_bridge) bridging the network transport to a physical controller on a remote host. +On Linux, the [VHCI Transport](../transports/vhci.md) can be used to communicate with any controller hardware managed by the operating system. Alternatively, a remote controller (a phyiscal controller attached to a remote host) can be used by connecting one of the networked transports (such as the [TCP Client transport](../transports/tcp_client.md), the [TCP Server transport](../transports/tcp_server.md) or the [UDP Transport](../transports/udp.md)) to an [HCI Bridge](../apps_and_tools/hci_bridge.md) bridging the network transport to a physical controller on a remote host. In theory, any controller that is compliant with the HCI over UART or HCI over USB protocols can be used. diff --git a/extras/android/RemoteHCI/.gitignore b/extras/android/RemoteHCI/.gitignore new file mode 100644 index 00000000..10cfdbfa --- /dev/null +++ b/extras/android/RemoteHCI/.gitignore @@ -0,0 +1,10 @@ +*.iml +.gradle +/local.properties +/.idea +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/extras/android/RemoteHCI/app/.gitignore b/extras/android/RemoteHCI/app/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/extras/android/RemoteHCI/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/build.gradle.kts b/extras/android/RemoteHCI/app/build.gradle.kts new file mode 100644 index 00000000..2e2df389 --- /dev/null +++ b/extras/android/RemoteHCI/app/build.gradle.kts @@ -0,0 +1,73 @@ +@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed +plugins { + alias(libs.plugins.androidApplication) + alias(libs.plugins.kotlinAndroid) +} + +android { + namespace = "com.github.google.bumble.remotehci" + compileSdk = 33 + + defaultConfig { + applicationId = "com.github.google.bumble.remotehci" + minSdk = 26 + targetSdk = 33 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + compose = true + aidl = false + } + composeOptions { + kotlinCompilerExtensionVersion = "1.4.3" + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } +} + +dependencies { + implementation(kotlin("reflect")) + implementation(libs.core.ktx) + implementation(libs.lifecycle.runtime.ktx) + implementation(libs.activity.compose) + implementation(platform(libs.compose.bom)) + implementation(libs.ui) + implementation(libs.ui.graphics) + implementation(libs.ui.tooling.preview) + implementation(libs.material3) + compileOnly(project(":lib")) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.ext.junit) + androidTestImplementation(libs.espresso.core) + androidTestImplementation(platform(libs.compose.bom)) + androidTestImplementation(libs.ui.test.junit4) + debugImplementation(libs.ui.tooling) + debugImplementation(libs.ui.test.manifest) + //compileOnly(files("${project.rootDir.absolutePath}/sdk/framework.jar")) +} \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/proguard-rules.pro b/extras/android/RemoteHCI/app/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/extras/android/RemoteHCI/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/AndroidManifest.xml b/extras/android/RemoteHCI/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..2cca4ada --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/IBluetoothHci.aidl b/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/IBluetoothHci.aidl new file mode 100644 index 00000000..92feaa5e --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/IBluetoothHci.aidl @@ -0,0 +1,43 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.bluetooth; +@VintfStability +interface IBluetoothHci { + void close(); + void initialize(in android.hardware.bluetooth.IBluetoothHciCallbacks callback); + void sendAclData(in byte[] data); + void sendHciCommand(in byte[] command); + void sendIsoData(in byte[] data); + void sendScoData(in byte[] data); +} \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl b/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl new file mode 100644 index 00000000..f0d8c29a --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl @@ -0,0 +1,42 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.bluetooth; +@VintfStability +interface IBluetoothHciCallbacks { + void aclDataReceived(in byte[] data); + void hciEventReceived(in byte[] event); + void initializationComplete(in android.hardware.bluetooth.Status status); + void isoDataReceived(in byte[] data); + void scoDataReceived(in byte[] data); +} \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/Status.aidl b/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/Status.aidl new file mode 100644 index 00000000..f3ba7921 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/aidl/android/hardware/bluetooth/Status.aidl @@ -0,0 +1,43 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.bluetooth; +@Backing(type="int") +@VintfStability +enum Status { + SUCCESS = 0, + ALREADY_INITIALIZED = 1, + UNABLE_TO_OPEN_INTERFACE = 2, + HARDWARE_INITIALIZATION_ERROR = 3, + UNKNOWN = 4, +} \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/hidl/bluetooth/1.1/IBluetoothHci.hal b/extras/android/RemoteHCI/app/src/main/hidl/bluetooth/1.1/IBluetoothHci.hal new file mode 100644 index 00000000..b7845d5a --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/hidl/bluetooth/1.1/IBluetoothHci.hal @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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. + */ + +package android.hardware.bluetooth@1.1; + +import @1.0::HciPacket; +import @1.0::IBluetoothHci; +import IBluetoothHciCallbacks; + +/** + * The Host Controller Interface (HCI) is the layer defined by the Bluetooth + * specification between the software that runs on the host and the Bluetooth + * controller chip. This boundary is the natural choice for a Hardware + * Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies + * the stack and abstracts away power management, initialization, and other + * implementation-specific details related to the hardware. + */ +interface IBluetoothHci extends @1.0::IBluetoothHci { + /** + * Same as @1.0, but uses 1.1 Callbacks version + */ + initialize_1_1(@1.1::IBluetoothHciCallbacks callback); + + /** + * Send an ISO data packet (as specified in the Bluetooth Core + * Specification v5.2) to the Bluetooth controller. + * Packets must be processed in order. + * @param data HCI data packet to be sent + */ + sendIsoData(HciPacket data); +}; \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/hidl/bluetooth/1.1/IBluetoothHciCallbacks.hal b/extras/android/RemoteHCI/app/src/main/hidl/bluetooth/1.1/IBluetoothHciCallbacks.hal new file mode 100644 index 00000000..b8d0b8a6 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/hidl/bluetooth/1.1/IBluetoothHciCallbacks.hal @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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. + */ + +package android.hardware.bluetooth@1.1; + +import @1.0::HciPacket; +import @1.0::IBluetoothHciCallbacks; + +/** + * The interface from the Bluetooth Controller to the stack. + */ +interface IBluetoothHciCallbacks extends @1.0::IBluetoothHciCallbacks { + /** + * Send a ISO data packet form the controller to the host. + * @param data the ISO HCI packet to be passed to the host stack + */ + isoDataReceived(HciPacket data); +}; \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/ic_launcher-playstore.png b/extras/android/RemoteHCI/app/src/main/ic_launcher-playstore.png new file mode 100644 index 00000000..b0a2f40f Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/ic_launcher-playstore.png differ diff --git a/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/IBluetoothHci.java b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/IBluetoothHci.java new file mode 100644 index 00000000..c2351372 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/IBluetoothHci.java @@ -0,0 +1,259 @@ +/* + * This file is auto-generated. DO NOT MODIFY. + */ +package android.hardware.bluetooth; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public interface IBluetoothHci extends android.os.IInterface +{ + /** Default implementation for IBluetoothHci. */ + public static class Default implements android.hardware.bluetooth.IBluetoothHci + { + @Override public void close() throws android.os.RemoteException + { + } + @Override public void initialize(android.hardware.bluetooth.IBluetoothHciCallbacks callback) throws android.os.RemoteException + { + } + @Override public void sendAclData(byte[] data) throws android.os.RemoteException + { + } + @Override public void sendHciCommand(byte[] command) throws android.os.RemoteException + { + } + @Override public void sendIsoData(byte[] data) throws android.os.RemoteException + { + } + @Override public void sendScoData(byte[] data) throws android.os.RemoteException + { + } + @Override + public android.os.IBinder asBinder() { + return null; + } + } + /** Local-side IPC implementation stub class. */ + public static abstract class Stub extends android.os.Binder implements android.hardware.bluetooth.IBluetoothHci + { + /** Construct the stub at attach it to the interface. */ + public Stub() + { + //this.markVintfStability(); + try { + Method method = this.getClass().getMethod("markVintfStability", (Class[])null); + method.invoke(this); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + this.attachInterface(this, DESCRIPTOR); + } + /** + * Cast an IBinder object into an android.hardware.bluetooth.IBluetoothHci interface, + * generating a proxy if needed. + */ + public static android.hardware.bluetooth.IBluetoothHci asInterface(android.os.IBinder obj) + { + if ((obj==null)) { + return null; + } + android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (((iin!=null)&&(iin instanceof android.hardware.bluetooth.IBluetoothHci))) { + return ((android.hardware.bluetooth.IBluetoothHci)iin); + } + return new android.hardware.bluetooth.IBluetoothHci.Stub.Proxy(obj); + } + @Override public android.os.IBinder asBinder() + { + return this; + } + @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException + { + java.lang.String descriptor = DESCRIPTOR; + if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) { + data.enforceInterface(descriptor); + } + switch (code) + { + case INTERFACE_TRANSACTION: + { + reply.writeString(descriptor); + return true; + } + } + switch (code) + { + case TRANSACTION_close: + { + this.close(); + reply.writeNoException(); + break; + } + case TRANSACTION_initialize: + { + android.hardware.bluetooth.IBluetoothHciCallbacks _arg0; + _arg0 = android.hardware.bluetooth.IBluetoothHciCallbacks.Stub.asInterface(data.readStrongBinder()); + this.initialize(_arg0); + reply.writeNoException(); + break; + } + case TRANSACTION_sendAclData: + { + byte[] _arg0; + _arg0 = data.createByteArray(); + this.sendAclData(_arg0); + reply.writeNoException(); + break; + } + case TRANSACTION_sendHciCommand: + { + byte[] _arg0; + _arg0 = data.createByteArray(); + this.sendHciCommand(_arg0); + reply.writeNoException(); + break; + } + case TRANSACTION_sendIsoData: + { + byte[] _arg0; + _arg0 = data.createByteArray(); + this.sendIsoData(_arg0); + reply.writeNoException(); + break; + } + case TRANSACTION_sendScoData: + { + byte[] _arg0; + _arg0 = data.createByteArray(); + this.sendScoData(_arg0); + reply.writeNoException(); + break; + } + default: + { + return super.onTransact(code, data, reply, flags); + } + } + return true; + } + private static class Proxy implements android.hardware.bluetooth.IBluetoothHci + { + private android.os.IBinder mRemote; + Proxy(android.os.IBinder remote) + { + mRemote = remote; + } + @Override public android.os.IBinder asBinder() + { + return mRemote; + } + public java.lang.String getInterfaceDescriptor() + { + return DESCRIPTOR; + } + @Override public void close() throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + boolean _status = mRemote.transact(Stub.TRANSACTION_close, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void initialize(android.hardware.bluetooth.IBluetoothHciCallbacks callback) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeStrongInterface(callback); + boolean _status = mRemote.transact(Stub.TRANSACTION_initialize, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void sendAclData(byte[] data) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeByteArray(data); + boolean _status = mRemote.transact(Stub.TRANSACTION_sendAclData, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void sendHciCommand(byte[] command) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeByteArray(command); + boolean _status = mRemote.transact(Stub.TRANSACTION_sendHciCommand, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void sendIsoData(byte[] data) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeByteArray(data); + boolean _status = mRemote.transact(Stub.TRANSACTION_sendIsoData, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void sendScoData(byte[] data) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeByteArray(data); + boolean _status = mRemote.transact(Stub.TRANSACTION_sendScoData, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + } + static final int TRANSACTION_close = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); + static final int TRANSACTION_initialize = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); + static final int TRANSACTION_sendAclData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); + static final int TRANSACTION_sendHciCommand = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); + static final int TRANSACTION_sendIsoData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); + static final int TRANSACTION_sendScoData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); + } + public static final java.lang.String DESCRIPTOR = "android$hardware$bluetooth$IBluetoothHci".replace('$', '.'); + public void close() throws android.os.RemoteException; + public void initialize(android.hardware.bluetooth.IBluetoothHciCallbacks callback) throws android.os.RemoteException; + public void sendAclData(byte[] data) throws android.os.RemoteException; + public void sendHciCommand(byte[] command) throws android.os.RemoteException; + public void sendIsoData(byte[] data) throws android.os.RemoteException; + public void sendScoData(byte[] data) throws android.os.RemoteException; +} diff --git a/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/IBluetoothHciCallbacks.java b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/IBluetoothHciCallbacks.java new file mode 100644 index 00000000..61a70ad6 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/IBluetoothHciCallbacks.java @@ -0,0 +1,234 @@ +/* + * This file is auto-generated. DO NOT MODIFY. + */ +package android.hardware.bluetooth; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public interface IBluetoothHciCallbacks extends android.os.IInterface +{ + /** Default implementation for IBluetoothHciCallbacks. */ + public static class Default implements android.hardware.bluetooth.IBluetoothHciCallbacks + { + @Override public void aclDataReceived(byte[] data) throws android.os.RemoteException + { + } + @Override public void hciEventReceived(byte[] event) throws android.os.RemoteException + { + } + @Override public void initializationComplete(int status) throws android.os.RemoteException + { + } + @Override public void isoDataReceived(byte[] data) throws android.os.RemoteException + { + } + @Override public void scoDataReceived(byte[] data) throws android.os.RemoteException + { + } + @Override + public android.os.IBinder asBinder() { + return null; + } + } + /** Local-side IPC implementation stub class. */ + public static abstract class Stub extends android.os.Binder implements android.hardware.bluetooth.IBluetoothHciCallbacks + { + /** Construct the stub at attach it to the interface. */ + public Stub() + { + //this.markVintfStability(); + try { + Method method = this.getClass().getMethod("markVintfStability", (Class[])null); + method.invoke(this); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + throw new RuntimeException(e); + } + this.attachInterface(this, DESCRIPTOR); + } + /** + * Cast an IBinder object into an android.hardware.bluetooth.IBluetoothHciCallbacks interface, + * generating a proxy if needed. + */ + public static android.hardware.bluetooth.IBluetoothHciCallbacks asInterface(android.os.IBinder obj) + { + if ((obj==null)) { + return null; + } + android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (((iin!=null)&&(iin instanceof android.hardware.bluetooth.IBluetoothHciCallbacks))) { + return ((android.hardware.bluetooth.IBluetoothHciCallbacks)iin); + } + return new android.hardware.bluetooth.IBluetoothHciCallbacks.Stub.Proxy(obj); + } + @Override public android.os.IBinder asBinder() + { + return this; + } + @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException + { + java.lang.String descriptor = DESCRIPTOR; + if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) { + data.enforceInterface(descriptor); + } + switch (code) + { + case INTERFACE_TRANSACTION: + { + reply.writeString(descriptor); + return true; + } + } + switch (code) + { + case TRANSACTION_aclDataReceived: + { + byte[] _arg0; + _arg0 = data.createByteArray(); + this.aclDataReceived(_arg0); + reply.writeNoException(); + break; + } + case TRANSACTION_hciEventReceived: + { + byte[] _arg0; + _arg0 = data.createByteArray(); + this.hciEventReceived(_arg0); + reply.writeNoException(); + break; + } + case TRANSACTION_initializationComplete: + { + int _arg0; + _arg0 = data.readInt(); + this.initializationComplete(_arg0); + reply.writeNoException(); + break; + } + case TRANSACTION_isoDataReceived: + { + byte[] _arg0; + _arg0 = data.createByteArray(); + this.isoDataReceived(_arg0); + reply.writeNoException(); + break; + } + case TRANSACTION_scoDataReceived: + { + byte[] _arg0; + _arg0 = data.createByteArray(); + this.scoDataReceived(_arg0); + reply.writeNoException(); + break; + } + default: + { + return super.onTransact(code, data, reply, flags); + } + } + return true; + } + private static class Proxy implements android.hardware.bluetooth.IBluetoothHciCallbacks + { + private android.os.IBinder mRemote; + Proxy(android.os.IBinder remote) + { + mRemote = remote; + } + @Override public android.os.IBinder asBinder() + { + return mRemote; + } + public java.lang.String getInterfaceDescriptor() + { + return DESCRIPTOR; + } + @Override public void aclDataReceived(byte[] data) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeByteArray(data); + boolean _status = mRemote.transact(Stub.TRANSACTION_aclDataReceived, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void hciEventReceived(byte[] event) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeByteArray(event); + boolean _status = mRemote.transact(Stub.TRANSACTION_hciEventReceived, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void initializationComplete(int status) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeInt(status); + boolean _status = mRemote.transact(Stub.TRANSACTION_initializationComplete, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void isoDataReceived(byte[] data) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeByteArray(data); + boolean _status = mRemote.transact(Stub.TRANSACTION_isoDataReceived, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public void scoDataReceived(byte[] data) throws android.os.RemoteException + { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeByteArray(data); + boolean _status = mRemote.transact(Stub.TRANSACTION_scoDataReceived, _data, _reply, 0); + _reply.readException(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + } + } + static final int TRANSACTION_aclDataReceived = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); + static final int TRANSACTION_hciEventReceived = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); + static final int TRANSACTION_initializationComplete = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); + static final int TRANSACTION_isoDataReceived = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); + static final int TRANSACTION_scoDataReceived = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); + } + public static final java.lang.String DESCRIPTOR = "android$hardware$bluetooth$IBluetoothHciCallbacks".replace('$', '.'); + public void aclDataReceived(byte[] data) throws android.os.RemoteException; + public void hciEventReceived(byte[] event) throws android.os.RemoteException; + public void initializationComplete(int status) throws android.os.RemoteException; + public void isoDataReceived(byte[] data) throws android.os.RemoteException; + public void scoDataReceived(byte[] data) throws android.os.RemoteException; +} diff --git a/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/Status.java b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/Status.java new file mode 100644 index 00000000..710d6c98 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/Status.java @@ -0,0 +1,11 @@ +/* + * This file is auto-generated. DO NOT MODIFY. + */ +package android.hardware.bluetooth; +public @interface Status { + public static final int SUCCESS = 0; + public static final int ALREADY_INITIALIZED = 1; + public static final int UNABLE_TO_OPEN_INTERFACE = 2; + public static final int HARDWARE_INITIALIZATION_ERROR = 3; + public static final int UNKNOWN = 4; +} diff --git a/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/IBluetoothHci.java b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/IBluetoothHci.java new file mode 100644 index 00000000..e7cd5771 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/IBluetoothHci.java @@ -0,0 +1,816 @@ +package android.hardware.bluetooth.V1_0; + +import android.os.HidlSupport; +import android.os.HwBinder; +import android.os.IHwBinder; +import android.os.HwBlob; +import android.os.HwParcel; +import android.os.IHwInterface; +import android.os.NativeHandle; + +/** + * The Host Controller Interface (HCI) is the layer defined by the Bluetooth + * specification between the software that runs on the host and the Bluetooth + * controller chip. This boundary is the natural choice for a Hardware + * Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies + * the stack and abstracts away power management, initialization, and other + * implementation-specific details related to the hardware. + */ +public interface IBluetoothHci extends android.internal.hidl.base.V1_0.IBase { + /** + * Fully-qualified interface name for this interface. + */ + public static final String kInterfaceName = "android.hardware.bluetooth@1.0::IBluetoothHci"; + + /** + * Does a checked conversion from a binder to this class. + */ + /* package private */ static IBluetoothHci asInterface(IHwBinder binder) { + if (binder == null) { + return null; + } + + IHwInterface iface = + binder.queryLocalInterface(kInterfaceName); + + if ((iface != null) && (iface instanceof IBluetoothHci)) { + return (IBluetoothHci)iface; + } + + IBluetoothHci proxy = new IBluetoothHci.Proxy(binder); + + try { + for (String descriptor : proxy.interfaceChain()) { + if (descriptor.equals(kInterfaceName)) { + return proxy; + } + } + } catch (android.os.RemoteException e) { + } + + return null; + } + + /** + * Does a checked conversion from any interface to this class. + */ + public static IBluetoothHci castFrom(IHwInterface iface) { + return (iface == null) ? null : IBluetoothHci.asInterface(iface.asBinder()); + } + + @Override + public IHwBinder asBinder(); + + /** + * This will invoke the equivalent of the C++ getService(std::string) if retry is + * true or tryGetService(std::string) if retry is false. If the service is + * available on the device and retry is true, this will wait for the service to + * start. + * + */ + public static IBluetoothHci getService(String serviceName, boolean retry) throws android.os.RemoteException { + return IBluetoothHci.asInterface(HwBinder.getService("android.hardware.bluetooth@1.0::IBluetoothHci", serviceName, retry)); + } + + /** + * Calls getService("default",retry). + */ + public static IBluetoothHci getService(boolean retry) throws android.os.RemoteException { + return getService("default", retry); + } + + /** + * @deprecated this will not wait for the interface to come up if it hasn't yet + * started. See getService(String,boolean) instead. + */ + @Deprecated + public static IBluetoothHci getService(String serviceName) throws android.os.RemoteException { + return IBluetoothHci.asInterface(HwBinder.getService("android.hardware.bluetooth@1.0::IBluetoothHci", serviceName)); + } + + /** + * @deprecated this will not wait for the interface to come up if it hasn't yet + * started. See getService(boolean) instead. + */ + @Deprecated + public static IBluetoothHci getService() throws android.os.RemoteException { + return getService("default"); + } + + /** + * Initialize the underlying HCI interface. + * + * This method should be used to initialize any hardware interfaces + * required to communicate with the Bluetooth hardware in the + * device. + * + * The |oninitializationComplete| callback must be invoked in response + * to this function to indicate success before any other function + * (sendHciCommand, sendAclData, * sendScoData) is invoked on this + * interface. + * + * @param callback implements IBluetoothHciCallbacks which will + * receive callbacks when incoming HCI packets are received + * from the controller to be sent to the host. + */ + void initialize(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks callback) + throws android.os.RemoteException; + /** + * Send an HCI command (as specified in the Bluetooth Specification + * V4.2, Vol 2, Part 5, Section 5.4.1) to the Bluetooth controller. + * Commands must be executed in order. + * + * @param command is the HCI command to be sent + */ + void sendHciCommand(java.util.ArrayList command) + throws android.os.RemoteException; + /** + * Send an HCI ACL data packet (as specified in the Bluetooth Specification + * V4.2, Vol 2, Part 5, Section 5.4.2) to the Bluetooth controller. + * Packets must be processed in order. + * @param data HCI data packet to be sent + */ + void sendAclData(java.util.ArrayList data) + throws android.os.RemoteException; + /** + * Send an SCO data packet (as specified in the Bluetooth Specification + * V4.2, Vol 2, Part 5, Section 5.4.3) to the Bluetooth controller. + * Packets must be processed in order. + * @param data HCI data packet to be sent + */ + void sendScoData(java.util.ArrayList data) + throws android.os.RemoteException; + /** + * Close the HCI interface + */ + void close() + throws android.os.RemoteException; + /* + * Provides run-time type information for this object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceChain on an IChild object must yield the following: + * ["android.hardware.foo@1.0::IChild", + * "android.hardware.foo@1.0::IParent" + * "android.internal.hidl.base@1.0::IBase"] + * + * @return descriptors a vector of descriptors of the run-time type of the + * object. + */ + java.util.ArrayList interfaceChain() + throws android.os.RemoteException; + /* + * Emit diagnostic information to the given file. + * + * Optionally overriden. + * + * @param fd File descriptor to dump data to. + * Must only be used for the duration of this call. + * @param options Arguments for debugging. + * Must support empty for default debug information. + */ + void debug(NativeHandle fd, java.util.ArrayList options) + throws android.os.RemoteException; + /* + * Provides run-time type information for this object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceDescriptor on an IChild object must yield + * "android.hardware.foo@1.0::IChild" + * + * @return descriptor a descriptor of the run-time type of the + * object (the first element of the vector returned by + * interfaceChain()) + */ + String interfaceDescriptor() + throws android.os.RemoteException; + /* + * Returns hashes of the source HAL files that define the interfaces of the + * runtime type information on the object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceChain on an IChild object must yield the following: + * [(hash of IChild.hal), + * (hash of IParent.hal) + * (hash of IBase.hal)]. + * + * SHA-256 is used as the hashing algorithm. Each hash has 32 bytes + * according to SHA-256 standard. + * + * @return hashchain a vector of SHA-1 digests + */ + java.util.ArrayList getHashChain() + throws android.os.RemoteException; + /* + * This method trigger the interface to enable/disable instrumentation based + * on system property hal.instrumentation.enable. + */ + void setHALInstrumentation() + throws android.os.RemoteException; + /* + * Registers a death recipient, to be called when the process hosting this + * interface dies. + * + * @param recipient a hidl_death_recipient callback object + * @param cookie a cookie that must be returned with the callback + * @return success whether the death recipient was registered successfully. + */ + boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) + throws android.os.RemoteException; + /* + * Provides way to determine if interface is running without requesting + * any functionality. + */ + void ping() + throws android.os.RemoteException; + /* + * Get debug information on references on this interface. + * @return info debugging information. See comments of DebugInfo. + */ + android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() + throws android.os.RemoteException; + /* + * This method notifies the interface that one or more system properties + * have changed. The default implementation calls + * (C++) report_sysprop_change() in libcutils or + * (Java) android.os.SystemProperties.reportSyspropChanged, + * which in turn calls a set of registered callbacks (eg to update trace + * tags). + */ + void notifySyspropsChanged() + throws android.os.RemoteException; + /* + * Unregisters the registered death recipient. If this service was registered + * multiple times with the same exact death recipient, this unlinks the most + * recently registered one. + * + * @param recipient a previously registered hidl_death_recipient callback + * @return success whether the death recipient was unregistered successfully. + */ + boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) + throws android.os.RemoteException; + + public static final class Proxy implements IBluetoothHci { + private IHwBinder mRemote; + + public Proxy(IHwBinder remote) { + mRemote = java.util.Objects.requireNonNull(remote); + } + + @Override + public IHwBinder asBinder() { + return mRemote; + } + + @Override + public String toString() { + try { + return this.interfaceDescriptor() + "@Proxy"; + } catch (android.os.RemoteException ex) { + /* ignored; handled below. */ + } + return "[class or subclass of " + IBluetoothHci.kInterfaceName + "]@Proxy"; + } + + @Override + public final boolean equals(java.lang.Object other) { + return HidlSupport.interfacesEqual(this, other); + } + + @Override + public final int hashCode() { + return this.asBinder().hashCode(); + } + + // Methods from ::android::hardware::bluetooth::V1_0::IBluetoothHci follow. + @Override + public void initialize(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks callback) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + _hidl_request.writeStrongBinder(callback == null ? null : callback.asBinder()); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(1 /* initialize */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void sendHciCommand(java.util.ArrayList command) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + _hidl_request.writeInt8Vector(command); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(2 /* sendHciCommand */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void sendAclData(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(3 /* sendAclData */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void sendScoData(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(4 /* sendScoData */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void close() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(5 /* close */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + // Methods from ::android::hidl::base::V1_0::IBase follow. + @Override + public java.util.ArrayList interfaceChain() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256067662 /* interfaceChain */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + java.util.ArrayList _hidl_out_descriptors = _hidl_reply.readStringVector(); + return _hidl_out_descriptors; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void debug(NativeHandle fd, java.util.ArrayList options) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + _hidl_request.writeNativeHandle(fd); + _hidl_request.writeStringVector(options); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256131655 /* debug */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public String interfaceDescriptor() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256136003 /* interfaceDescriptor */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + String _hidl_out_descriptor = _hidl_reply.readString(); + return _hidl_out_descriptor; + } finally { + _hidl_reply.release(); + } + } + + @Override + public java.util.ArrayList getHashChain() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256398152 /* getHashChain */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + java.util.ArrayList _hidl_out_hashchain = new java.util.ArrayList(); + { + HwBlob _hidl_blob = _hidl_reply.readBuffer(16 /* size */); + { + int _hidl_vec_size = _hidl_blob.getInt32(0 /* offset */ + 8 /* offsetof(hidl_vec, mSize) */); + HwBlob childBlob = _hidl_reply.readEmbeddedBuffer( + _hidl_vec_size * 32,_hidl_blob.handle(), + 0 /* offset */ + 0 /* offsetof(hidl_vec, mBuffer) */,true /* nullable */); + + ((java.util.ArrayList) _hidl_out_hashchain).clear(); + for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) { + byte[/* 32 */] _hidl_vec_element = new byte[32]; + { + long _hidl_array_offset_1 = _hidl_index_0 * 32; + childBlob.copyToInt8Array(_hidl_array_offset_1, (byte[/* 32 */]) _hidl_vec_element, 32 /* size */); + _hidl_array_offset_1 += 32 * 1; + } + ((java.util.ArrayList) _hidl_out_hashchain).add(_hidl_vec_element); + } + } + } + return _hidl_out_hashchain; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void setHALInstrumentation() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256462420 /* setHALInstrumentation */, _hidl_request, _hidl_reply, 1 /* oneway */); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) + throws android.os.RemoteException { + return mRemote.linkToDeath(recipient, cookie); + } + @Override + public void ping() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256921159 /* ping */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(257049926 /* getDebugInfo */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + android.internal.hidl.base.V1_0.DebugInfo _hidl_out_info = new android.internal.hidl.base.V1_0.DebugInfo(); + ((android.internal.hidl.base.V1_0.DebugInfo) _hidl_out_info).readFromParcel(_hidl_reply); + return _hidl_out_info; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void notifySyspropsChanged() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(257120595 /* notifySyspropsChanged */, _hidl_request, _hidl_reply, 1 /* oneway */); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) + throws android.os.RemoteException { + return mRemote.unlinkToDeath(recipient); + } + } + + public static abstract class Stub extends HwBinder implements IBluetoothHci { + @Override + public IHwBinder asBinder() { + return this; + } + + @Override + public final java.util.ArrayList interfaceChain() { + return new java.util.ArrayList(java.util.Arrays.asList( + android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName, + android.internal.hidl.base.V1_0.IBase.kInterfaceName)); + + } + + @Override + public void debug(NativeHandle fd, java.util.ArrayList options) { + return; + + } + + @Override + public final String interfaceDescriptor() { + return android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName; + + } + + @Override + public final java.util.ArrayList getHashChain() { + return new java.util.ArrayList(java.util.Arrays.asList( + new byte[/* 32 */]{52,124,-25,70,-127,86,7,86,127,95,59,83,-28,-128,9,-104,-54,90,-71,53,81,65,-16,-120,15,-64,-49,12,31,-59,-61,85} /* 347ce746815607567f5f3b53e4800998ca5ab9355141f0880fc0cf0c1fc5c355 */, + new byte[/* 32 */]{-20,127,-41,-98,-48,45,-6,-123,-68,73,-108,38,-83,-82,62,-66,35,-17,5,36,-13,-51,105,87,19,-109,36,-72,59,24,-54,76} /* ec7fd79ed02dfa85bc499426adae3ebe23ef0524f3cd6957139324b83b18ca4c */)); + + } + + @Override + public final void setHALInstrumentation() { + + } + + @Override + public final boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) { + return true; + + } + + @Override + public final void ping() { + return; + + } + + @Override + public final android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() { + android.internal.hidl.base.V1_0.DebugInfo info = new android.internal.hidl.base.V1_0.DebugInfo(); + info.pid = HidlSupport.getPidIfSharable(); + info.ptr = 0; + info.arch = android.internal.hidl.base.V1_0.DebugInfo.Architecture.UNKNOWN; + return info; + + } + + @Override + public final void notifySyspropsChanged() { + HwBinder.enableInstrumentation(); + + } + + @Override + public final boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) { + return true; + + } + + @Override + public IHwInterface queryLocalInterface(String descriptor) { + if (kInterfaceName.equals(descriptor)) { + return this; + } + return null; + } + + public void registerAsService(String serviceName) throws android.os.RemoteException { + registerService(serviceName); + } + + @Override + public String toString() { + return this.interfaceDescriptor() + "@Stub"; + } + + //@Override + public void onTransact(int _hidl_code, HwParcel _hidl_request, final HwParcel _hidl_reply, int _hidl_flags) + throws android.os.RemoteException { + switch (_hidl_code) { + case 1 /* initialize */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks callback = android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.asInterface(_hidl_request.readStrongBinder()); + initialize(callback); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 2 /* sendHciCommand */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + java.util.ArrayList command = _hidl_request.readInt8Vector(); + sendHciCommand(command); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 3 /* sendAclData */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + sendAclData(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 4 /* sendScoData */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + sendScoData(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 5 /* close */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + close(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 256067662 /* interfaceChain */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + java.util.ArrayList _hidl_out_descriptors = interfaceChain(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.writeStringVector(_hidl_out_descriptors); + _hidl_reply.send(); + break; + } + + case 256131655 /* debug */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + NativeHandle fd = _hidl_request.readNativeHandle(); + java.util.ArrayList options = _hidl_request.readStringVector(); + debug(fd, options); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 256136003 /* interfaceDescriptor */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + String _hidl_out_descriptor = interfaceDescriptor(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.writeString(_hidl_out_descriptor); + _hidl_reply.send(); + break; + } + + case 256398152 /* getHashChain */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + java.util.ArrayList _hidl_out_hashchain = getHashChain(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + { + HwBlob _hidl_blob = new HwBlob(16 /* size */); + { + int _hidl_vec_size = _hidl_out_hashchain.size(); + _hidl_blob.putInt32(0 /* offset */ + 8 /* offsetof(hidl_vec, mSize) */, _hidl_vec_size); + _hidl_blob.putBool(0 /* offset */ + 12 /* offsetof(hidl_vec, mOwnsBuffer) */, false); + HwBlob childBlob = new HwBlob((int)(_hidl_vec_size * 32)); + for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) { + { + long _hidl_array_offset_1 = _hidl_index_0 * 32; + byte[] _hidl_array_item_1 = (byte[/* 32 */]) _hidl_out_hashchain.get(_hidl_index_0); + + if (_hidl_array_item_1 == null || _hidl_array_item_1.length != 32) { + throw new IllegalArgumentException("Array element is not of the expected length"); + } + + childBlob.putInt8Array(_hidl_array_offset_1, _hidl_array_item_1); + _hidl_array_offset_1 += 32 * 1; + } + } + _hidl_blob.putBlob(0 /* offset */ + 0 /* offsetof(hidl_vec, mBuffer) */, childBlob); + } + _hidl_reply.writeBuffer(_hidl_blob); + } + _hidl_reply.send(); + break; + } + + case 256462420 /* setHALInstrumentation */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + setHALInstrumentation(); + break; + } + + case 256660548 /* linkToDeath */: + { + break; + } + + case 256921159 /* ping */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + ping(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 257049926 /* getDebugInfo */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + android.internal.hidl.base.V1_0.DebugInfo _hidl_out_info = getDebugInfo(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + ((android.internal.hidl.base.V1_0.DebugInfo) _hidl_out_info).writeToParcel(_hidl_reply); + _hidl_reply.send(); + break; + } + + case 257120595 /* notifySyspropsChanged */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + notifySyspropsChanged(); + break; + } + + case 257250372 /* unlinkToDeath */: + { + break; + } + + } + } + } +} diff --git a/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/IBluetoothHciCallbacks.java b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/IBluetoothHciCallbacks.java new file mode 100644 index 00000000..694fb723 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/IBluetoothHciCallbacks.java @@ -0,0 +1,762 @@ +package android.hardware.bluetooth.V1_0; + +import android.os.HidlSupport; +import android.os.HwBinder; +import android.os.IHwBinder; +import android.os.HwBlob; +import android.os.HwParcel; +import android.os.IHwInterface; +import android.os.NativeHandle; + +/** + * The interface from the Bluetooth Controller to the stack. + */ +public interface IBluetoothHciCallbacks extends android.internal.hidl.base.V1_0.IBase { + /** + * Fully-qualified interface name for this interface. + */ + public static final String kInterfaceName = "android.hardware.bluetooth@1.0::IBluetoothHciCallbacks"; + + /** + * Does a checked conversion from a binder to this class. + */ + /* package private */ static IBluetoothHciCallbacks asInterface(IHwBinder binder) { + if (binder == null) { + return null; + } + + IHwInterface iface = + binder.queryLocalInterface(kInterfaceName); + + if ((iface != null) && (iface instanceof IBluetoothHciCallbacks)) { + return (IBluetoothHciCallbacks)iface; + } + + IBluetoothHciCallbacks proxy = new IBluetoothHciCallbacks.Proxy(binder); + + try { + for (String descriptor : proxy.interfaceChain()) { + if (descriptor.equals(kInterfaceName)) { + return proxy; + } + } + } catch (android.os.RemoteException e) { + } + + return null; + } + + /** + * Does a checked conversion from any interface to this class. + */ + public static IBluetoothHciCallbacks castFrom(IHwInterface iface) { + return (iface == null) ? null : IBluetoothHciCallbacks.asInterface(iface.asBinder()); + } + + @Override + public IHwBinder asBinder(); + + /** + * This will invoke the equivalent of the C++ getService(std::string) if retry is + * true or tryGetService(std::string) if retry is false. If the service is + * available on the device and retry is true, this will wait for the service to + * start. + * + */ + public static IBluetoothHciCallbacks getService(String serviceName, boolean retry) throws android.os.RemoteException { + return IBluetoothHciCallbacks.asInterface(HwBinder.getService("android.hardware.bluetooth@1.0::IBluetoothHciCallbacks", serviceName, retry)); + } + + /** + * Calls getService("default",retry). + */ + public static IBluetoothHciCallbacks getService(boolean retry) throws android.os.RemoteException { + return getService("default", retry); + } + + /** + * @deprecated this will not wait for the interface to come up if it hasn't yet + * started. See getService(String,boolean) instead. + */ + @Deprecated + public static IBluetoothHciCallbacks getService(String serviceName) throws android.os.RemoteException { + return IBluetoothHciCallbacks.asInterface(HwBinder.getService("android.hardware.bluetooth@1.0::IBluetoothHciCallbacks", serviceName)); + } + + /** + * @deprecated this will not wait for the interface to come up if it hasn't yet + * started. See getService(boolean) instead. + */ + @Deprecated + public static IBluetoothHciCallbacks getService() throws android.os.RemoteException { + return getService("default"); + } + + /** + * Invoked when the Bluetooth controller initialization has been + * completed. + */ + void initializationComplete(int status) + throws android.os.RemoteException; + /** + * This function is invoked when an HCI event is received from the + * Bluetooth controller to be forwarded to the Bluetooth stack. + * @param event is the HCI event to be sent to the Bluetooth stack. + */ + void hciEventReceived(java.util.ArrayList event) + throws android.os.RemoteException; + /** + * Send an ACL data packet form the controller to the host. + * @param data the ACL HCI packet to be passed to the host stack + */ + void aclDataReceived(java.util.ArrayList data) + throws android.os.RemoteException; + /** + * Send a SCO data packet form the controller to the host. + * @param data the SCO HCI packet to be passed to the host stack + */ + void scoDataReceived(java.util.ArrayList data) + throws android.os.RemoteException; + /* + * Provides run-time type information for this object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceChain on an IChild object must yield the following: + * ["android.hardware.foo@1.0::IChild", + * "android.hardware.foo@1.0::IParent" + * "android.internal.hidl.base@1.0::IBase"] + * + * @return descriptors a vector of descriptors of the run-time type of the + * object. + */ + java.util.ArrayList interfaceChain() + throws android.os.RemoteException; + /* + * Emit diagnostic information to the given file. + * + * Optionally overriden. + * + * @param fd File descriptor to dump data to. + * Must only be used for the duration of this call. + * @param options Arguments for debugging. + * Must support empty for default debug information. + */ + void debug(NativeHandle fd, java.util.ArrayList options) + throws android.os.RemoteException; + /* + * Provides run-time type information for this object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceDescriptor on an IChild object must yield + * "android.hardware.foo@1.0::IChild" + * + * @return descriptor a descriptor of the run-time type of the + * object (the first element of the vector returned by + * interfaceChain()) + */ + String interfaceDescriptor() + throws android.os.RemoteException; + /* + * Returns hashes of the source HAL files that define the interfaces of the + * runtime type information on the object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceChain on an IChild object must yield the following: + * [(hash of IChild.hal), + * (hash of IParent.hal) + * (hash of IBase.hal)]. + * + * SHA-256 is used as the hashing algorithm. Each hash has 32 bytes + * according to SHA-256 standard. + * + * @return hashchain a vector of SHA-1 digests + */ + java.util.ArrayList getHashChain() + throws android.os.RemoteException; + /* + * This method trigger the interface to enable/disable instrumentation based + * on system property hal.instrumentation.enable. + */ + void setHALInstrumentation() + throws android.os.RemoteException; + /* + * Registers a death recipient, to be called when the process hosting this + * interface dies. + * + * @param recipient a hidl_death_recipient callback object + * @param cookie a cookie that must be returned with the callback + * @return success whether the death recipient was registered successfully. + */ + boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) + throws android.os.RemoteException; + /* + * Provides way to determine if interface is running without requesting + * any functionality. + */ + void ping() + throws android.os.RemoteException; + /* + * Get debug information on references on this interface. + * @return info debugging information. See comments of DebugInfo. + */ + android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() + throws android.os.RemoteException; + /* + * This method notifies the interface that one or more system properties + * have changed. The default implementation calls + * (C++) report_sysprop_change() in libcutils or + * (Java) android.os.SystemProperties.reportSyspropChanged, + * which in turn calls a set of registered callbacks (eg to update trace + * tags). + */ + void notifySyspropsChanged() + throws android.os.RemoteException; + /* + * Unregisters the registered death recipient. If this service was registered + * multiple times with the same exact death recipient, this unlinks the most + * recently registered one. + * + * @param recipient a previously registered hidl_death_recipient callback + * @return success whether the death recipient was unregistered successfully. + */ + boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) + throws android.os.RemoteException; + + public static final class Proxy implements IBluetoothHciCallbacks { + private IHwBinder mRemote; + + public Proxy(IHwBinder remote) { + mRemote = java.util.Objects.requireNonNull(remote); + } + + @Override + public IHwBinder asBinder() { + return mRemote; + } + + @Override + public String toString() { + try { + return this.interfaceDescriptor() + "@Proxy"; + } catch (android.os.RemoteException ex) { + /* ignored; handled below. */ + } + return "[class or subclass of " + IBluetoothHciCallbacks.kInterfaceName + "]@Proxy"; + } + + @Override + public final boolean equals(java.lang.Object other) { + return HidlSupport.interfacesEqual(this, other); + } + + @Override + public final int hashCode() { + return this.asBinder().hashCode(); + } + + // Methods from ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks follow. + @Override + public void initializationComplete(int status) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt32(status); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(1 /* initializationComplete */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void hciEventReceived(java.util.ArrayList event) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt8Vector(event); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(2 /* hciEventReceived */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void aclDataReceived(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(3 /* aclDataReceived */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void scoDataReceived(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(4 /* scoDataReceived */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + // Methods from ::android::hidl::base::V1_0::IBase follow. + @Override + public java.util.ArrayList interfaceChain() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256067662 /* interfaceChain */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + java.util.ArrayList _hidl_out_descriptors = _hidl_reply.readStringVector(); + return _hidl_out_descriptors; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void debug(NativeHandle fd, java.util.ArrayList options) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + _hidl_request.writeNativeHandle(fd); + _hidl_request.writeStringVector(options); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256131655 /* debug */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public String interfaceDescriptor() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256136003 /* interfaceDescriptor */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + String _hidl_out_descriptor = _hidl_reply.readString(); + return _hidl_out_descriptor; + } finally { + _hidl_reply.release(); + } + } + + @Override + public java.util.ArrayList getHashChain() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256398152 /* getHashChain */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + java.util.ArrayList _hidl_out_hashchain = new java.util.ArrayList(); + { + HwBlob _hidl_blob = _hidl_reply.readBuffer(16 /* size */); + { + int _hidl_vec_size = _hidl_blob.getInt32(0 /* offset */ + 8 /* offsetof(hidl_vec, mSize) */); + HwBlob childBlob = _hidl_reply.readEmbeddedBuffer( + _hidl_vec_size * 32,_hidl_blob.handle(), + 0 /* offset */ + 0 /* offsetof(hidl_vec, mBuffer) */,true /* nullable */); + + ((java.util.ArrayList) _hidl_out_hashchain).clear(); + for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) { + byte[/* 32 */] _hidl_vec_element = new byte[32]; + { + long _hidl_array_offset_1 = _hidl_index_0 * 32; + childBlob.copyToInt8Array(_hidl_array_offset_1, (byte[/* 32 */]) _hidl_vec_element, 32 /* size */); + _hidl_array_offset_1 += 32 * 1; + } + ((java.util.ArrayList) _hidl_out_hashchain).add(_hidl_vec_element); + } + } + } + return _hidl_out_hashchain; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void setHALInstrumentation() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256462420 /* setHALInstrumentation */, _hidl_request, _hidl_reply, 1 /* oneway */); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) + throws android.os.RemoteException { + return mRemote.linkToDeath(recipient, cookie); + } + @Override + public void ping() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256921159 /* ping */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(257049926 /* getDebugInfo */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + android.internal.hidl.base.V1_0.DebugInfo _hidl_out_info = new android.internal.hidl.base.V1_0.DebugInfo(); + ((android.internal.hidl.base.V1_0.DebugInfo) _hidl_out_info).readFromParcel(_hidl_reply); + return _hidl_out_info; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void notifySyspropsChanged() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(257120595 /* notifySyspropsChanged */, _hidl_request, _hidl_reply, 1 /* oneway */); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) + throws android.os.RemoteException { + return mRemote.unlinkToDeath(recipient); + } + } + + public static abstract class Stub extends HwBinder implements IBluetoothHciCallbacks { + @Override + public IHwBinder asBinder() { + return this; + } + + @Override + public final java.util.ArrayList interfaceChain() { + return new java.util.ArrayList(java.util.Arrays.asList( + android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName, + android.internal.hidl.base.V1_0.IBase.kInterfaceName)); + + } + + @Override + public void debug(NativeHandle fd, java.util.ArrayList options) { + return; + + } + + @Override + public final String interfaceDescriptor() { + return android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName; + + } + + @Override + public final java.util.ArrayList getHashChain() { + return new java.util.ArrayList(java.util.Arrays.asList( + new byte[/* 32 */]{-125,95,65,-66,34,-127,-65,-78,47,62,51,-58,-6,-121,11,-34,123,-62,30,55,-27,-49,-70,-7,-93,111,-1,23,6,50,-9,84} /* 835f41be2281bfb22f3e33c6fa870bde7bc21e37e5cfbaf9a36fff170632f754 */, + new byte[/* 32 */]{-20,127,-41,-98,-48,45,-6,-123,-68,73,-108,38,-83,-82,62,-66,35,-17,5,36,-13,-51,105,87,19,-109,36,-72,59,24,-54,76} /* ec7fd79ed02dfa85bc499426adae3ebe23ef0524f3cd6957139324b83b18ca4c */)); + + } + + @Override + public final void setHALInstrumentation() { + + } + + @Override + public final boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) { + return true; + + } + + @Override + public final void ping() { + return; + + } + + @Override + public final android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() { + android.internal.hidl.base.V1_0.DebugInfo info = new android.internal.hidl.base.V1_0.DebugInfo(); + info.pid = HidlSupport.getPidIfSharable(); + info.ptr = 0; + info.arch = android.internal.hidl.base.V1_0.DebugInfo.Architecture.UNKNOWN; + return info; + + } + + @Override + public final void notifySyspropsChanged() { + HwBinder.enableInstrumentation(); + + } + + @Override + public final boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) { + return true; + + } + + @Override + public IHwInterface queryLocalInterface(String descriptor) { + if (kInterfaceName.equals(descriptor)) { + return this; + } + return null; + } + + public void registerAsService(String serviceName) throws android.os.RemoteException { + registerService(serviceName); + } + + @Override + public String toString() { + return this.interfaceDescriptor() + "@Stub"; + } + + //@Override + public void onTransact(int _hidl_code, HwParcel _hidl_request, final HwParcel _hidl_reply, int _hidl_flags) + throws android.os.RemoteException { + switch (_hidl_code) { + case 1 /* initializationComplete */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + + int status = _hidl_request.readInt32(); + initializationComplete(status); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 2 /* hciEventReceived */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + + java.util.ArrayList event = _hidl_request.readInt8Vector(); + hciEventReceived(event); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 3 /* aclDataReceived */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + aclDataReceived(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 4 /* scoDataReceived */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + scoDataReceived(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 256067662 /* interfaceChain */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + java.util.ArrayList _hidl_out_descriptors = interfaceChain(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.writeStringVector(_hidl_out_descriptors); + _hidl_reply.send(); + break; + } + + case 256131655 /* debug */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + NativeHandle fd = _hidl_request.readNativeHandle(); + java.util.ArrayList options = _hidl_request.readStringVector(); + debug(fd, options); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 256136003 /* interfaceDescriptor */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + String _hidl_out_descriptor = interfaceDescriptor(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.writeString(_hidl_out_descriptor); + _hidl_reply.send(); + break; + } + + case 256398152 /* getHashChain */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + java.util.ArrayList _hidl_out_hashchain = getHashChain(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + { + HwBlob _hidl_blob = new HwBlob(16 /* size */); + { + int _hidl_vec_size = _hidl_out_hashchain.size(); + _hidl_blob.putInt32(0 /* offset */ + 8 /* offsetof(hidl_vec, mSize) */, _hidl_vec_size); + _hidl_blob.putBool(0 /* offset */ + 12 /* offsetof(hidl_vec, mOwnsBuffer) */, false); + HwBlob childBlob = new HwBlob((int)(_hidl_vec_size * 32)); + for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) { + { + long _hidl_array_offset_1 = _hidl_index_0 * 32; + byte[] _hidl_array_item_1 = (byte[/* 32 */]) _hidl_out_hashchain.get(_hidl_index_0); + + if (_hidl_array_item_1 == null || _hidl_array_item_1.length != 32) { + throw new IllegalArgumentException("Array element is not of the expected length"); + } + + childBlob.putInt8Array(_hidl_array_offset_1, _hidl_array_item_1); + _hidl_array_offset_1 += 32 * 1; + } + } + _hidl_blob.putBlob(0 /* offset */ + 0 /* offsetof(hidl_vec, mBuffer) */, childBlob); + } + _hidl_reply.writeBuffer(_hidl_blob); + } + _hidl_reply.send(); + break; + } + + case 256462420 /* setHALInstrumentation */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + setHALInstrumentation(); + break; + } + + case 256660548 /* linkToDeath */: + { + break; + } + + case 256921159 /* ping */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + ping(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 257049926 /* getDebugInfo */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + android.internal.hidl.base.V1_0.DebugInfo _hidl_out_info = getDebugInfo(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + ((android.internal.hidl.base.V1_0.DebugInfo) _hidl_out_info).writeToParcel(_hidl_reply); + _hidl_reply.send(); + break; + } + + case 257120595 /* notifySyspropsChanged */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + notifySyspropsChanged(); + break; + } + + case 257250372 /* unlinkToDeath */: + { + break; + } + + } + } + } +} diff --git a/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/Status.java b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/Status.java new file mode 100644 index 00000000..92350056 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_0/Status.java @@ -0,0 +1,48 @@ +package android.hardware.bluetooth.V1_0; + + +public final class Status { + public static final int SUCCESS = 0; + public static final int TRANSPORT_ERROR = 1 /* ::android::hardware::bluetooth::V1_0::Status.SUCCESS implicitly + 1 */; + public static final int INITIALIZATION_ERROR = 2 /* ::android::hardware::bluetooth::V1_0::Status.TRANSPORT_ERROR implicitly + 1 */; + public static final int UNKNOWN = 3 /* ::android::hardware::bluetooth::V1_0::Status.INITIALIZATION_ERROR implicitly + 1 */; + public static final String toString(int o) { + if (o == SUCCESS) { + return "SUCCESS"; + } + if (o == TRANSPORT_ERROR) { + return "TRANSPORT_ERROR"; + } + if (o == INITIALIZATION_ERROR) { + return "INITIALIZATION_ERROR"; + } + if (o == UNKNOWN) { + return "UNKNOWN"; + } + return "0x" + Integer.toHexString(o); + } + + public static final String dumpBitfield(int o) { + java.util.ArrayList list = new java.util.ArrayList<>(); + int flipped = 0; + list.add("SUCCESS"); // SUCCESS == 0 + if ((o & TRANSPORT_ERROR) == TRANSPORT_ERROR) { + list.add("TRANSPORT_ERROR"); + flipped |= TRANSPORT_ERROR; + } + if ((o & INITIALIZATION_ERROR) == INITIALIZATION_ERROR) { + list.add("INITIALIZATION_ERROR"); + flipped |= INITIALIZATION_ERROR; + } + if ((o & UNKNOWN) == UNKNOWN) { + list.add("UNKNOWN"); + flipped |= UNKNOWN; + } + if (o != flipped) { + list.add("0x" + Integer.toHexString(o & (~flipped))); + } + return String.join(" | ", list); + } + +}; + diff --git a/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_1/IBluetoothHci.java b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_1/IBluetoothHci.java new file mode 100644 index 00000000..44394516 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_1/IBluetoothHci.java @@ -0,0 +1,840 @@ +package android.hardware.bluetooth.V1_1; + +import android.os.HidlSupport; +import android.os.HwBinder; +import android.os.IHwBinder; +import android.os.HwBlob; +import android.os.HwParcel; +import android.os.IHwInterface; +import android.os.NativeHandle; + +/** + * The Host Controller Interface (HCI) is the layer defined by the Bluetooth + * specification between the software that runs on the host and the Bluetooth + * controller chip. This boundary is the natural choice for a Hardware + * Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies + * the stack and abstracts away power management, initialization, and other + * implementation-specific details related to the hardware. + */ +public interface IBluetoothHci extends android.hardware.bluetooth.V1_0.IBluetoothHci { + /** + * Fully-qualified interface name for this interface. + */ + public static final String kInterfaceName = "android.hardware.bluetooth@1.1::IBluetoothHci"; + + /** + * Does a checked conversion from a binder to this class. + */ + /* package private */ static IBluetoothHci asInterface(IHwBinder binder) { + if (binder == null) { + return null; + } + + IHwInterface iface = + binder.queryLocalInterface(kInterfaceName); + + if ((iface != null) && (iface instanceof IBluetoothHci)) { + return (IBluetoothHci)iface; + } + + IBluetoothHci proxy = new IBluetoothHci.Proxy(binder); + + try { + for (String descriptor : proxy.interfaceChain()) { + if (descriptor.equals(kInterfaceName)) { + return proxy; + } + } + } catch (android.os.RemoteException e) { + } + + return null; + } + + /** + * Does a checked conversion from any interface to this class. + */ + public static IBluetoothHci castFrom(IHwInterface iface) { + return (iface == null) ? null : IBluetoothHci.asInterface(iface.asBinder()); + } + + @Override + public IHwBinder asBinder(); + + /** + * This will invoke the equivalent of the C++ getService(std::string) if retry is + * true or tryGetService(std::string) if retry is false. If the service is + * available on the device and retry is true, this will wait for the service to + * start. + * + */ + public static IBluetoothHci getService(String serviceName, boolean retry) throws android.os.RemoteException { + return IBluetoothHci.asInterface(HwBinder.getService("android.hardware.bluetooth@1.1::IBluetoothHci", serviceName, retry)); + } + + /** + * Calls getService("default",retry). + */ + public static IBluetoothHci getService(boolean retry) throws android.os.RemoteException { + return getService("default", retry); + } + + /** + * @deprecated this will not wait for the interface to come up if it hasn't yet + * started. See getService(String,boolean) instead. + */ + @Deprecated + public static IBluetoothHci getService(String serviceName) throws android.os.RemoteException { + return IBluetoothHci.asInterface(HwBinder.getService("android.hardware.bluetooth@1.1::IBluetoothHci", serviceName)); + } + + /** + * @deprecated this will not wait for the interface to come up if it hasn't yet + * started. See getService(boolean) instead. + */ + @Deprecated + public static IBluetoothHci getService() throws android.os.RemoteException { + return getService("default"); + } + + /** + * Same as @1.0, but uses 1.1 Callbacks version + */ + void initialize_1_1(android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks callback) + throws android.os.RemoteException; + /** + * Send an ISO data packet (as specified in the Bluetooth Core + * Specification v5.2) to the Bluetooth controller. + * Packets must be processed in order. + * @param data HCI data packet to be sent + */ + void sendIsoData(java.util.ArrayList data) + throws android.os.RemoteException; + /* + * Provides run-time type information for this object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceChain on an IChild object must yield the following: + * ["android.hardware.foo@1.0::IChild", + * "android.hardware.foo@1.0::IParent" + * "android.internal.hidl.base@1.0::IBase"] + * + * @return descriptors a vector of descriptors of the run-time type of the + * object. + */ + java.util.ArrayList interfaceChain() + throws android.os.RemoteException; + /* + * Emit diagnostic information to the given file. + * + * Optionally overriden. + * + * @param fd File descriptor to dump data to. + * Must only be used for the duration of this call. + * @param options Arguments for debugging. + * Must support empty for default debug information. + */ + void debug(NativeHandle fd, java.util.ArrayList options) + throws android.os.RemoteException; + /* + * Provides run-time type information for this object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceDescriptor on an IChild object must yield + * "android.hardware.foo@1.0::IChild" + * + * @return descriptor a descriptor of the run-time type of the + * object (the first element of the vector returned by + * interfaceChain()) + */ + String interfaceDescriptor() + throws android.os.RemoteException; + /* + * Returns hashes of the source HAL files that define the interfaces of the + * runtime type information on the object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceChain on an IChild object must yield the following: + * [(hash of IChild.hal), + * (hash of IParent.hal) + * (hash of IBase.hal)]. + * + * SHA-256 is used as the hashing algorithm. Each hash has 32 bytes + * according to SHA-256 standard. + * + * @return hashchain a vector of SHA-1 digests + */ + java.util.ArrayList getHashChain() + throws android.os.RemoteException; + /* + * This method trigger the interface to enable/disable instrumentation based + * on system property hal.instrumentation.enable. + */ + void setHALInstrumentation() + throws android.os.RemoteException; + /* + * Registers a death recipient, to be called when the process hosting this + * interface dies. + * + * @param recipient a hidl_death_recipient callback object + * @param cookie a cookie that must be returned with the callback + * @return success whether the death recipient was registered successfully. + */ + boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) + throws android.os.RemoteException; + /* + * Provides way to determine if interface is running without requesting + * any functionality. + */ + void ping() + throws android.os.RemoteException; + /* + * Get debug information on references on this interface. + * @return info debugging information. See comments of DebugInfo. + */ + android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() + throws android.os.RemoteException; + /* + * This method notifies the interface that one or more system properties + * have changed. The default implementation calls + * (C++) report_sysprop_change() in libcutils or + * (Java) android.os.SystemProperties.reportSyspropChanged, + * which in turn calls a set of registered callbacks (eg to update trace + * tags). + */ + void notifySyspropsChanged() + throws android.os.RemoteException; + /* + * Unregisters the registered death recipient. If this service was registered + * multiple times with the same exact death recipient, this unlinks the most + * recently registered one. + * + * @param recipient a previously registered hidl_death_recipient callback + * @return success whether the death recipient was unregistered successfully. + */ + boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) + throws android.os.RemoteException; + + public static final class Proxy implements IBluetoothHci { + private IHwBinder mRemote; + + public Proxy(IHwBinder remote) { + mRemote = java.util.Objects.requireNonNull(remote); + } + + @Override + public IHwBinder asBinder() { + return mRemote; + } + + @Override + public String toString() { + try { + return this.interfaceDescriptor() + "@Proxy"; + } catch (android.os.RemoteException ex) { + /* ignored; handled below. */ + } + return "[class or subclass of " + IBluetoothHci.kInterfaceName + "]@Proxy"; + } + + @Override + public final boolean equals(java.lang.Object other) { + return HidlSupport.interfacesEqual(this, other); + } + + @Override + public final int hashCode() { + return this.asBinder().hashCode(); + } + + // Methods from ::android::hardware::bluetooth::V1_0::IBluetoothHci follow. + @Override + public void initialize(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks callback) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + _hidl_request.writeStrongBinder(callback == null ? null : callback.asBinder()); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(1 /* initialize */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void sendHciCommand(java.util.ArrayList command) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + _hidl_request.writeInt8Vector(command); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(2 /* sendHciCommand */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void sendAclData(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(3 /* sendAclData */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void sendScoData(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(4 /* sendScoData */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void close() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(5 /* close */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + // Methods from ::android::hardware::bluetooth::V1_1::IBluetoothHci follow. + @Override + public void initialize_1_1(android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks callback) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_1.IBluetoothHci.kInterfaceName); + _hidl_request.writeStrongBinder(callback == null ? null : callback.asBinder()); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(6 /* initialize_1_1 */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void sendIsoData(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_1.IBluetoothHci.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(7 /* sendIsoData */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + // Methods from ::android::hidl::base::V1_0::IBase follow. + @Override + public java.util.ArrayList interfaceChain() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256067662 /* interfaceChain */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + java.util.ArrayList _hidl_out_descriptors = _hidl_reply.readStringVector(); + return _hidl_out_descriptors; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void debug(NativeHandle fd, java.util.ArrayList options) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + _hidl_request.writeNativeHandle(fd); + _hidl_request.writeStringVector(options); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256131655 /* debug */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public String interfaceDescriptor() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256136003 /* interfaceDescriptor */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + String _hidl_out_descriptor = _hidl_reply.readString(); + return _hidl_out_descriptor; + } finally { + _hidl_reply.release(); + } + } + + @Override + public java.util.ArrayList getHashChain() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256398152 /* getHashChain */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + java.util.ArrayList _hidl_out_hashchain = new java.util.ArrayList(); + { + HwBlob _hidl_blob = _hidl_reply.readBuffer(16 /* size */); + { + int _hidl_vec_size = _hidl_blob.getInt32(0 /* offset */ + 8 /* offsetof(hidl_vec, mSize) */); + HwBlob childBlob = _hidl_reply.readEmbeddedBuffer( + _hidl_vec_size * 32,_hidl_blob.handle(), + 0 /* offset */ + 0 /* offsetof(hidl_vec, mBuffer) */,true /* nullable */); + + ((java.util.ArrayList) _hidl_out_hashchain).clear(); + for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) { + byte[/* 32 */] _hidl_vec_element = new byte[32]; + { + long _hidl_array_offset_1 = _hidl_index_0 * 32; + childBlob.copyToInt8Array(_hidl_array_offset_1, (byte[/* 32 */]) _hidl_vec_element, 32 /* size */); + _hidl_array_offset_1 += 32 * 1; + } + ((java.util.ArrayList) _hidl_out_hashchain).add(_hidl_vec_element); + } + } + } + return _hidl_out_hashchain; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void setHALInstrumentation() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256462420 /* setHALInstrumentation */, _hidl_request, _hidl_reply, 1 /* oneway */); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) + throws android.os.RemoteException { + return mRemote.linkToDeath(recipient, cookie); + } + @Override + public void ping() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256921159 /* ping */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(257049926 /* getDebugInfo */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + android.internal.hidl.base.V1_0.DebugInfo _hidl_out_info = new android.internal.hidl.base.V1_0.DebugInfo(); + ((android.internal.hidl.base.V1_0.DebugInfo) _hidl_out_info).readFromParcel(_hidl_reply); + return _hidl_out_info; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void notifySyspropsChanged() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(257120595 /* notifySyspropsChanged */, _hidl_request, _hidl_reply, 1 /* oneway */); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) + throws android.os.RemoteException { + return mRemote.unlinkToDeath(recipient); + } + } + + public static abstract class Stub extends HwBinder implements IBluetoothHci { + @Override + public IHwBinder asBinder() { + return this; + } + + @Override + public final java.util.ArrayList interfaceChain() { + return new java.util.ArrayList(java.util.Arrays.asList( + android.hardware.bluetooth.V1_1.IBluetoothHci.kInterfaceName, + android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName, + android.internal.hidl.base.V1_0.IBase.kInterfaceName)); + + } + + @Override + public void debug(NativeHandle fd, java.util.ArrayList options) { + return; + + } + + @Override + public final String interfaceDescriptor() { + return android.hardware.bluetooth.V1_1.IBluetoothHci.kInterfaceName; + + } + + @Override + public final java.util.ArrayList getHashChain() { + return new java.util.ArrayList(java.util.Arrays.asList( + new byte[/* 32 */]{54,47,-47,-62,22,65,-62,34,79,59,-128,-61,13,-105,-105,-71,-120,-6,63,52,66,67,-43,49,-70,115,-59,83,119,-102,87,99} /* 362fd1c21641c2224f3b80c30d9797b988fa3f344243d531ba73c553779a5763 */, + new byte[/* 32 */]{52,124,-25,70,-127,86,7,86,127,95,59,83,-28,-128,9,-104,-54,90,-71,53,81,65,-16,-120,15,-64,-49,12,31,-59,-61,85} /* 347ce746815607567f5f3b53e4800998ca5ab9355141f0880fc0cf0c1fc5c355 */, + new byte[/* 32 */]{-20,127,-41,-98,-48,45,-6,-123,-68,73,-108,38,-83,-82,62,-66,35,-17,5,36,-13,-51,105,87,19,-109,36,-72,59,24,-54,76} /* ec7fd79ed02dfa85bc499426adae3ebe23ef0524f3cd6957139324b83b18ca4c */)); + + } + + @Override + public final void setHALInstrumentation() { + + } + + @Override + public final boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) { + return true; + + } + + @Override + public final void ping() { + return; + + } + + @Override + public final android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() { + android.internal.hidl.base.V1_0.DebugInfo info = new android.internal.hidl.base.V1_0.DebugInfo(); + info.pid = HidlSupport.getPidIfSharable(); + info.ptr = 0; + info.arch = android.internal.hidl.base.V1_0.DebugInfo.Architecture.UNKNOWN; + return info; + + } + + @Override + public final void notifySyspropsChanged() { + HwBinder.enableInstrumentation(); + + } + + @Override + public final boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) { + return true; + + } + + @Override + public IHwInterface queryLocalInterface(String descriptor) { + if (kInterfaceName.equals(descriptor)) { + return this; + } + return null; + } + + public void registerAsService(String serviceName) throws android.os.RemoteException { + registerService(serviceName); + } + + @Override + public String toString() { + return this.interfaceDescriptor() + "@Stub"; + } + + //@Override + public void onTransact(int _hidl_code, HwParcel _hidl_request, final HwParcel _hidl_reply, int _hidl_flags) + throws android.os.RemoteException { + switch (_hidl_code) { + case 1 /* initialize */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks callback = android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.asInterface(_hidl_request.readStrongBinder()); + initialize(callback); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 2 /* sendHciCommand */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + java.util.ArrayList command = _hidl_request.readInt8Vector(); + sendHciCommand(command); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 3 /* sendAclData */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + sendAclData(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 4 /* sendScoData */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + sendScoData(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 5 /* close */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName); + + close(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 6 /* initialize_1_1 */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_1.IBluetoothHci.kInterfaceName); + + android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks callback = android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks.asInterface(_hidl_request.readStrongBinder()); + initialize_1_1(callback); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 7 /* sendIsoData */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_1.IBluetoothHci.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + sendIsoData(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 256067662 /* interfaceChain */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + java.util.ArrayList _hidl_out_descriptors = interfaceChain(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.writeStringVector(_hidl_out_descriptors); + _hidl_reply.send(); + break; + } + + case 256131655 /* debug */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + NativeHandle fd = _hidl_request.readNativeHandle(); + java.util.ArrayList options = _hidl_request.readStringVector(); + debug(fd, options); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 256136003 /* interfaceDescriptor */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + String _hidl_out_descriptor = interfaceDescriptor(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.writeString(_hidl_out_descriptor); + _hidl_reply.send(); + break; + } + + case 256398152 /* getHashChain */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + java.util.ArrayList _hidl_out_hashchain = getHashChain(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + { + HwBlob _hidl_blob = new HwBlob(16 /* size */); + { + int _hidl_vec_size = _hidl_out_hashchain.size(); + _hidl_blob.putInt32(0 /* offset */ + 8 /* offsetof(hidl_vec, mSize) */, _hidl_vec_size); + _hidl_blob.putBool(0 /* offset */ + 12 /* offsetof(hidl_vec, mOwnsBuffer) */, false); + HwBlob childBlob = new HwBlob((int)(_hidl_vec_size * 32)); + for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) { + { + long _hidl_array_offset_1 = _hidl_index_0 * 32; + byte[] _hidl_array_item_1 = (byte[/* 32 */]) _hidl_out_hashchain.get(_hidl_index_0); + + if (_hidl_array_item_1 == null || _hidl_array_item_1.length != 32) { + throw new IllegalArgumentException("Array element is not of the expected length"); + } + + childBlob.putInt8Array(_hidl_array_offset_1, _hidl_array_item_1); + _hidl_array_offset_1 += 32 * 1; + } + } + _hidl_blob.putBlob(0 /* offset */ + 0 /* offsetof(hidl_vec, mBuffer) */, childBlob); + } + _hidl_reply.writeBuffer(_hidl_blob); + } + _hidl_reply.send(); + break; + } + + case 256462420 /* setHALInstrumentation */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + setHALInstrumentation(); + break; + } + + case 256660548 /* linkToDeath */: + { + break; + } + + case 256921159 /* ping */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + ping(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 257049926 /* getDebugInfo */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + android.internal.hidl.base.V1_0.DebugInfo _hidl_out_info = getDebugInfo(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + ((android.internal.hidl.base.V1_0.DebugInfo) _hidl_out_info).writeToParcel(_hidl_reply); + _hidl_reply.send(); + break; + } + + case 257120595 /* notifySyspropsChanged */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + notifySyspropsChanged(); + break; + } + + case 257250372 /* unlinkToDeath */: + { + break; + } + + } + } + } +} diff --git a/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_1/IBluetoothHciCallbacks.java b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_1/IBluetoothHciCallbacks.java new file mode 100644 index 00000000..905e3a05 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/android/hardware/bluetooth/V1_1/IBluetoothHciCallbacks.java @@ -0,0 +1,774 @@ +package android.hardware.bluetooth.V1_1; + +import android.os.HidlSupport; +import android.os.HwBinder; +import android.os.IHwBinder; +import android.os.HwBlob; +import android.os.HwParcel; +import android.os.IHwInterface; +import android.os.NativeHandle; + +/** + * The interface from the Bluetooth Controller to the stack. + */ +public interface IBluetoothHciCallbacks extends android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks { + /** + * Fully-qualified interface name for this interface. + */ + public static final String kInterfaceName = "android.hardware.bluetooth@1.1::IBluetoothHciCallbacks"; + + /** + * Does a checked conversion from a binder to this class. + */ + /* package private */ static IBluetoothHciCallbacks asInterface(IHwBinder binder) { + if (binder == null) { + return null; + } + + IHwInterface iface = + binder.queryLocalInterface(kInterfaceName); + + if ((iface != null) && (iface instanceof IBluetoothHciCallbacks)) { + return (IBluetoothHciCallbacks)iface; + } + + IBluetoothHciCallbacks proxy = new IBluetoothHciCallbacks.Proxy(binder); + + try { + for (String descriptor : proxy.interfaceChain()) { + if (descriptor.equals(kInterfaceName)) { + return proxy; + } + } + } catch (android.os.RemoteException e) { + } + + return null; + } + + /** + * Does a checked conversion from any interface to this class. + */ + public static IBluetoothHciCallbacks castFrom(IHwInterface iface) { + return (iface == null) ? null : IBluetoothHciCallbacks.asInterface(iface.asBinder()); + } + + @Override + public IHwBinder asBinder(); + + /** + * This will invoke the equivalent of the C++ getService(std::string) if retry is + * true or tryGetService(std::string) if retry is false. If the service is + * available on the device and retry is true, this will wait for the service to + * start. + * + */ + public static IBluetoothHciCallbacks getService(String serviceName, boolean retry) throws android.os.RemoteException { + return IBluetoothHciCallbacks.asInterface(HwBinder.getService("android.hardware.bluetooth@1.1::IBluetoothHciCallbacks", serviceName, retry)); + } + + /** + * Calls getService("default",retry). + */ + public static IBluetoothHciCallbacks getService(boolean retry) throws android.os.RemoteException { + return getService("default", retry); + } + + /** + * @deprecated this will not wait for the interface to come up if it hasn't yet + * started. See getService(String,boolean) instead. + */ + @Deprecated + public static IBluetoothHciCallbacks getService(String serviceName) throws android.os.RemoteException { + return IBluetoothHciCallbacks.asInterface(HwBinder.getService("android.hardware.bluetooth@1.1::IBluetoothHciCallbacks", serviceName)); + } + + /** + * @deprecated this will not wait for the interface to come up if it hasn't yet + * started. See getService(boolean) instead. + */ + @Deprecated + public static IBluetoothHciCallbacks getService() throws android.os.RemoteException { + return getService("default"); + } + + /** + * Send a ISO data packet form the controller to the host. + * @param data the ISO HCI packet to be passed to the host stack + */ + void isoDataReceived(java.util.ArrayList data) + throws android.os.RemoteException; + /* + * Provides run-time type information for this object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceChain on an IChild object must yield the following: + * ["android.hardware.foo@1.0::IChild", + * "android.hardware.foo@1.0::IParent" + * "android.internal.hidl.base@1.0::IBase"] + * + * @return descriptors a vector of descriptors of the run-time type of the + * object. + */ + java.util.ArrayList interfaceChain() + throws android.os.RemoteException; + /* + * Emit diagnostic information to the given file. + * + * Optionally overriden. + * + * @param fd File descriptor to dump data to. + * Must only be used for the duration of this call. + * @param options Arguments for debugging. + * Must support empty for default debug information. + */ + void debug(NativeHandle fd, java.util.ArrayList options) + throws android.os.RemoteException; + /* + * Provides run-time type information for this object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceDescriptor on an IChild object must yield + * "android.hardware.foo@1.0::IChild" + * + * @return descriptor a descriptor of the run-time type of the + * object (the first element of the vector returned by + * interfaceChain()) + */ + String interfaceDescriptor() + throws android.os.RemoteException; + /* + * Returns hashes of the source HAL files that define the interfaces of the + * runtime type information on the object. + * For example, for the following interface definition: + * package android.hardware.foo@1.0; + * interface IParent {}; + * interface IChild extends IParent {}; + * Calling interfaceChain on an IChild object must yield the following: + * [(hash of IChild.hal), + * (hash of IParent.hal) + * (hash of IBase.hal)]. + * + * SHA-256 is used as the hashing algorithm. Each hash has 32 bytes + * according to SHA-256 standard. + * + * @return hashchain a vector of SHA-1 digests + */ + java.util.ArrayList getHashChain() + throws android.os.RemoteException; + /* + * This method trigger the interface to enable/disable instrumentation based + * on system property hal.instrumentation.enable. + */ + void setHALInstrumentation() + throws android.os.RemoteException; + /* + * Registers a death recipient, to be called when the process hosting this + * interface dies. + * + * @param recipient a hidl_death_recipient callback object + * @param cookie a cookie that must be returned with the callback + * @return success whether the death recipient was registered successfully. + */ + boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) + throws android.os.RemoteException; + /* + * Provides way to determine if interface is running without requesting + * any functionality. + */ + void ping() + throws android.os.RemoteException; + /* + * Get debug information on references on this interface. + * @return info debugging information. See comments of DebugInfo. + */ + android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() + throws android.os.RemoteException; + /* + * This method notifies the interface that one or more system properties + * have changed. The default implementation calls + * (C++) report_sysprop_change() in libcutils or + * (Java) android.os.SystemProperties.reportSyspropChanged, + * which in turn calls a set of registered callbacks (eg to update trace + * tags). + */ + void notifySyspropsChanged() + throws android.os.RemoteException; + /* + * Unregisters the registered death recipient. If this service was registered + * multiple times with the same exact death recipient, this unlinks the most + * recently registered one. + * + * @param recipient a previously registered hidl_death_recipient callback + * @return success whether the death recipient was unregistered successfully. + */ + boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) + throws android.os.RemoteException; + + public static final class Proxy implements IBluetoothHciCallbacks { + private IHwBinder mRemote; + + public Proxy(IHwBinder remote) { + mRemote = java.util.Objects.requireNonNull(remote); + } + + @Override + public IHwBinder asBinder() { + return mRemote; + } + + @Override + public String toString() { + try { + return this.interfaceDescriptor() + "@Proxy"; + } catch (android.os.RemoteException ex) { + /* ignored; handled below. */ + } + return "[class or subclass of " + IBluetoothHciCallbacks.kInterfaceName + "]@Proxy"; + } + + @Override + public final boolean equals(java.lang.Object other) { + return HidlSupport.interfacesEqual(this, other); + } + + @Override + public final int hashCode() { + return this.asBinder().hashCode(); + } + + // Methods from ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks follow. + @Override + public void initializationComplete(int status) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt32(status); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(1 /* initializationComplete */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void hciEventReceived(java.util.ArrayList event) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt8Vector(event); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(2 /* hciEventReceived */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void aclDataReceived(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(3 /* aclDataReceived */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public void scoDataReceived(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(4 /* scoDataReceived */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + // Methods from ::android::hardware::bluetooth::V1_1::IBluetoothHciCallbacks follow. + @Override + public void isoDataReceived(java.util.ArrayList data) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks.kInterfaceName); + _hidl_request.writeInt8Vector(data); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(5 /* isoDataReceived */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + // Methods from ::android::hidl::base::V1_0::IBase follow. + @Override + public java.util.ArrayList interfaceChain() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256067662 /* interfaceChain */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + java.util.ArrayList _hidl_out_descriptors = _hidl_reply.readStringVector(); + return _hidl_out_descriptors; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void debug(NativeHandle fd, java.util.ArrayList options) + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + _hidl_request.writeNativeHandle(fd); + _hidl_request.writeStringVector(options); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256131655 /* debug */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public String interfaceDescriptor() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256136003 /* interfaceDescriptor */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + String _hidl_out_descriptor = _hidl_reply.readString(); + return _hidl_out_descriptor; + } finally { + _hidl_reply.release(); + } + } + + @Override + public java.util.ArrayList getHashChain() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256398152 /* getHashChain */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + java.util.ArrayList _hidl_out_hashchain = new java.util.ArrayList(); + { + HwBlob _hidl_blob = _hidl_reply.readBuffer(16 /* size */); + { + int _hidl_vec_size = _hidl_blob.getInt32(0 /* offset */ + 8 /* offsetof(hidl_vec, mSize) */); + HwBlob childBlob = _hidl_reply.readEmbeddedBuffer( + _hidl_vec_size * 32,_hidl_blob.handle(), + 0 /* offset */ + 0 /* offsetof(hidl_vec, mBuffer) */,true /* nullable */); + + ((java.util.ArrayList) _hidl_out_hashchain).clear(); + for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) { + byte[/* 32 */] _hidl_vec_element = new byte[32]; + { + long _hidl_array_offset_1 = _hidl_index_0 * 32; + childBlob.copyToInt8Array(_hidl_array_offset_1, (byte[/* 32 */]) _hidl_vec_element, 32 /* size */); + _hidl_array_offset_1 += 32 * 1; + } + ((java.util.ArrayList) _hidl_out_hashchain).add(_hidl_vec_element); + } + } + } + return _hidl_out_hashchain; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void setHALInstrumentation() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256462420 /* setHALInstrumentation */, _hidl_request, _hidl_reply, 1 /* oneway */); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) + throws android.os.RemoteException { + return mRemote.linkToDeath(recipient, cookie); + } + @Override + public void ping() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(256921159 /* ping */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(257049926 /* getDebugInfo */, _hidl_request, _hidl_reply, 0 /* flags */); + _hidl_reply.verifySuccess(); + _hidl_request.releaseTemporaryStorage(); + + android.internal.hidl.base.V1_0.DebugInfo _hidl_out_info = new android.internal.hidl.base.V1_0.DebugInfo(); + ((android.internal.hidl.base.V1_0.DebugInfo) _hidl_out_info).readFromParcel(_hidl_reply); + return _hidl_out_info; + } finally { + _hidl_reply.release(); + } + } + + @Override + public void notifySyspropsChanged() + throws android.os.RemoteException { + HwParcel _hidl_request = new HwParcel(); + _hidl_request.writeInterfaceToken(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + HwParcel _hidl_reply = new HwParcel(); + try { + mRemote.transact(257120595 /* notifySyspropsChanged */, _hidl_request, _hidl_reply, 1 /* oneway */); + _hidl_request.releaseTemporaryStorage(); + } finally { + _hidl_reply.release(); + } + } + + @Override + public boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) + throws android.os.RemoteException { + return mRemote.unlinkToDeath(recipient); + } + } + + public static abstract class Stub extends HwBinder implements IBluetoothHciCallbacks { + @Override + public IHwBinder asBinder() { + return this; + } + + @Override + public final java.util.ArrayList interfaceChain() { + return new java.util.ArrayList(java.util.Arrays.asList( + android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks.kInterfaceName, + android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName, + android.internal.hidl.base.V1_0.IBase.kInterfaceName)); + + } + + @Override + public void debug(NativeHandle fd, java.util.ArrayList options) { + return; + + } + + @Override + public final String interfaceDescriptor() { + return android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks.kInterfaceName; + + } + + @Override + public final java.util.ArrayList getHashChain() { + return new java.util.ArrayList(java.util.Arrays.asList( + new byte[/* 32 */]{64,-85,44,104,102,-63,-115,50,-70,-10,-28,-98,48,83,-108,-98,121,96,31,86,-106,58,121,30,-109,-26,-117,-98,-31,-113,113,-115} /* 40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d */, + new byte[/* 32 */]{-125,95,65,-66,34,-127,-65,-78,47,62,51,-58,-6,-121,11,-34,123,-62,30,55,-27,-49,-70,-7,-93,111,-1,23,6,50,-9,84} /* 835f41be2281bfb22f3e33c6fa870bde7bc21e37e5cfbaf9a36fff170632f754 */, + new byte[/* 32 */]{-20,127,-41,-98,-48,45,-6,-123,-68,73,-108,38,-83,-82,62,-66,35,-17,5,36,-13,-51,105,87,19,-109,36,-72,59,24,-54,76} /* ec7fd79ed02dfa85bc499426adae3ebe23ef0524f3cd6957139324b83b18ca4c */)); + + } + + @Override + public final void setHALInstrumentation() { + + } + + @Override + public final boolean linkToDeath(IHwBinder.DeathRecipient recipient, long cookie) { + return true; + + } + + @Override + public final void ping() { + return; + + } + + @Override + public final android.internal.hidl.base.V1_0.DebugInfo getDebugInfo() { + android.internal.hidl.base.V1_0.DebugInfo info = new android.internal.hidl.base.V1_0.DebugInfo(); + info.pid = HidlSupport.getPidIfSharable(); + info.ptr = 0; + info.arch = android.internal.hidl.base.V1_0.DebugInfo.Architecture.UNKNOWN; + return info; + + } + + @Override + public final void notifySyspropsChanged() { + HwBinder.enableInstrumentation(); + + } + + @Override + public final boolean unlinkToDeath(IHwBinder.DeathRecipient recipient) { + return true; + + } + + @Override + public IHwInterface queryLocalInterface(String descriptor) { + if (kInterfaceName.equals(descriptor)) { + return this; + } + return null; + } + + public void registerAsService(String serviceName) throws android.os.RemoteException { + registerService(serviceName); + } + + @Override + public String toString() { + return this.interfaceDescriptor() + "@Stub"; + } + + //@Override + public void onTransact(int _hidl_code, HwParcel _hidl_request, final HwParcel _hidl_reply, int _hidl_flags) + throws android.os.RemoteException { + switch (_hidl_code) { + case 1 /* initializationComplete */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + + int status = _hidl_request.readInt32(); + initializationComplete(status); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 2 /* hciEventReceived */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + + java.util.ArrayList event = _hidl_request.readInt8Vector(); + hciEventReceived(event); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 3 /* aclDataReceived */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + aclDataReceived(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 4 /* scoDataReceived */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + scoDataReceived(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 5 /* isoDataReceived */: + { + _hidl_request.enforceInterface(android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks.kInterfaceName); + + java.util.ArrayList data = _hidl_request.readInt8Vector(); + isoDataReceived(data); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 256067662 /* interfaceChain */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + java.util.ArrayList _hidl_out_descriptors = interfaceChain(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.writeStringVector(_hidl_out_descriptors); + _hidl_reply.send(); + break; + } + + case 256131655 /* debug */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + NativeHandle fd = _hidl_request.readNativeHandle(); + java.util.ArrayList options = _hidl_request.readStringVector(); + debug(fd, options); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 256136003 /* interfaceDescriptor */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + String _hidl_out_descriptor = interfaceDescriptor(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.writeString(_hidl_out_descriptor); + _hidl_reply.send(); + break; + } + + case 256398152 /* getHashChain */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + java.util.ArrayList _hidl_out_hashchain = getHashChain(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + { + HwBlob _hidl_blob = new HwBlob(16 /* size */); + { + int _hidl_vec_size = _hidl_out_hashchain.size(); + _hidl_blob.putInt32(0 /* offset */ + 8 /* offsetof(hidl_vec, mSize) */, _hidl_vec_size); + _hidl_blob.putBool(0 /* offset */ + 12 /* offsetof(hidl_vec, mOwnsBuffer) */, false); + HwBlob childBlob = new HwBlob((int)(_hidl_vec_size * 32)); + for (int _hidl_index_0 = 0; _hidl_index_0 < _hidl_vec_size; ++_hidl_index_0) { + { + long _hidl_array_offset_1 = _hidl_index_0 * 32; + byte[] _hidl_array_item_1 = (byte[/* 32 */]) _hidl_out_hashchain.get(_hidl_index_0); + + if (_hidl_array_item_1 == null || _hidl_array_item_1.length != 32) { + throw new IllegalArgumentException("Array element is not of the expected length"); + } + + childBlob.putInt8Array(_hidl_array_offset_1, _hidl_array_item_1); + _hidl_array_offset_1 += 32 * 1; + } + } + _hidl_blob.putBlob(0 /* offset */ + 0 /* offsetof(hidl_vec, mBuffer) */, childBlob); + } + _hidl_reply.writeBuffer(_hidl_blob); + } + _hidl_reply.send(); + break; + } + + case 256462420 /* setHALInstrumentation */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + setHALInstrumentation(); + break; + } + + case 256660548 /* linkToDeath */: + { + break; + } + + case 256921159 /* ping */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + ping(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + _hidl_reply.send(); + break; + } + + case 257049926 /* getDebugInfo */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + android.internal.hidl.base.V1_0.DebugInfo _hidl_out_info = getDebugInfo(); + _hidl_reply.writeStatus(HwParcel.STATUS_SUCCESS); + ((android.internal.hidl.base.V1_0.DebugInfo) _hidl_out_info).writeToParcel(_hidl_reply); + _hidl_reply.send(); + break; + } + + case 257120595 /* notifySyspropsChanged */: + { + _hidl_request.enforceInterface(android.internal.hidl.base.V1_0.IBase.kInterfaceName); + + notifySyspropsChanged(); + break; + } + + case 257250372 /* unlinkToDeath */: + { + break; + } + + } + } + } +} diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciHal.java b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciHal.java new file mode 100644 index 00000000..fd819218 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciHal.java @@ -0,0 +1,260 @@ +package com.github.google.bumble.remotehci; + +import android.hardware.bluetooth.V1_0.Status; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import java.util.ArrayList; +import java.util.NoSuchElementException; + +public interface HciHal { + public enum Status { + SUCCESS("SUCCESS"), + ALREADY_INITIALIZED("ALREADY_INITIALIZED"), + UNABLE_TO_OPEN_INTERFACE("UNABLE_TO_OPEN_INTERFACE"), + INITIALIZATION_ERROR("INITIALIZATION_ERROR"), + TRANSPORT_ERROR("TRANSPORT_ERROR"), + UNKNOWN("UNKNOWN"); + + public final String label; + + private Status(String label) { + this.label = label; + } + } + static final String TAG = "HciHal"; + public static HciHal create(HciHalCallback hciCallbacks) { + // First try HIDL + HciHal hciHal = HciHidlHal.create(hciCallbacks); + if (hciHal != null) { + Log.d(TAG, "Found HIDL HAL"); + return hciHal; + } + + // Then try AIDL + hciHal = HciAidlHal.create(hciCallbacks); + if (hciHal != null) { + Log.d(TAG, "Found AIDL HAL"); + return hciHal; + } + + Log.d(TAG, "No HAL found"); + return null; + } + + public Status initialize() throws RemoteException, InterruptedException; + public void sendPacket(HciPacket.Type type, byte[] packet); +} + +class HciHidlHal extends android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.Stub implements HciHal { + private static final String TAG = "HciHidlHal"; + private final android.hardware.bluetooth.V1_0.IBluetoothHci mHciService; + private final HciHalCallback mHciCallbacks; + private int mInitializationStatus = -1; + + + public static HciHidlHal create(HciHalCallback hciCallbacks) { + // Get the HAL service. + android.hardware.bluetooth.V1_0.IBluetoothHci hciService; + try { + hciService = android.hardware.bluetooth.V1_0.IBluetoothHci.getService(true); + } catch (NoSuchElementException e) { + Log.d(TAG, "HIDL HAL V1.0 not found"); + return null; + } catch (android.os.RemoteException e) { + Log.w(TAG, "Exception from getService: " + e); + return null; + } + Log.d(TAG, "Found HIDL HAL V1.0"); + return new HciHidlHal(hciService, hciCallbacks); + } + + private HciHidlHal(android.hardware.bluetooth.V1_0.IBluetoothHci hciService, HciHalCallback hciCallbacks) { + mHciService = hciService; + mHciCallbacks = hciCallbacks; + } + + public Status initialize() throws RemoteException, InterruptedException { + // Trigger the initialization. + mHciService.initialize(this); + + // Wait for the initialization to complete. + Log.d(TAG, "Waiting for initialization status..."); + synchronized (this) { + while (mInitializationStatus == -1) { + wait(); + } + } + + // Map the status code. + switch (mInitializationStatus) { + case android.hardware.bluetooth.V1_0.Status.SUCCESS: + return Status.SUCCESS; + + case android.hardware.bluetooth.V1_0.Status.TRANSPORT_ERROR: + return Status.TRANSPORT_ERROR; + + case android.hardware.bluetooth.V1_0.Status.INITIALIZATION_ERROR: + return Status.INITIALIZATION_ERROR; + + default: + return Status.UNKNOWN; + } + } + + @Override + public void sendPacket(HciPacket.Type type, byte[] packet) { + ArrayList data = HciPacket.byteArrayToList(packet); + + try { + switch (type) { + case COMMAND: + mHciService.sendHciCommand(data); + break; + + case ACL_DATA: + mHciService.sendAclData(data); + break; + + case SCO_DATA: + mHciService.sendScoData(data); + break; + } + } catch (RemoteException error) { + Log.w(TAG, "failed to forward packet: " + error); + } + } + + @Override + public synchronized void initializationComplete(int status) throws RemoteException { + mInitializationStatus = status; + notifyAll(); + } + + @Override + public void hciEventReceived(ArrayList event) throws RemoteException { + byte[] packet = HciPacket.listToByteArray(event); + mHciCallbacks.onPacket(HciPacket.Type.EVENT, packet); + } + + @Override + public void aclDataReceived(ArrayList data) throws RemoteException { + byte[] packet = HciPacket.listToByteArray(data); + mHciCallbacks.onPacket(HciPacket.Type.ACL_DATA, packet); + } + + @Override + public void scoDataReceived(ArrayList data) throws RemoteException { + byte[] packet = HciPacket.listToByteArray(data); + mHciCallbacks.onPacket(HciPacket.Type.SCO_DATA, packet); + } +} + +class HciAidlHal extends android.hardware.bluetooth.IBluetoothHciCallbacks.Stub implements HciHal { + private static final String TAG = "HciAidlHal"; + private final android.hardware.bluetooth.IBluetoothHci mHciService; + private final HciHalCallback mHciCallbacks; + private int mInitializationStatus = android.hardware.bluetooth.Status.SUCCESS; + + public static HciAidlHal create(HciHalCallback hciCallbacks) { + IBinder binder = ServiceManager.getService("android.hardware.bluetooth.IBluetoothHci/default"); + if (binder == null) { + Log.d(TAG, "AIDL HAL not found"); + return null; + } + android.hardware.bluetooth.IBluetoothHci hciService = android.hardware.bluetooth.IBluetoothHci.Stub.asInterface(binder); + return new HciAidlHal(hciService, hciCallbacks); + } + + private HciAidlHal(android.hardware.bluetooth.IBluetoothHci hciService, HciHalCallback hciCallbacks) { + super(); + mHciService = hciService; + mHciCallbacks = hciCallbacks; + } + + public Status initialize() throws RemoteException, InterruptedException { + // Trigger the initialization. + mHciService.initialize(this); + + // Wait for the initialization to complete. + Log.d(TAG, "Waiting for initialization status..."); + synchronized (this) { + while (mInitializationStatus == -1) { + wait(); + } + } + + // Map the status code. + switch (mInitializationStatus) { + case android.hardware.bluetooth.Status.SUCCESS: + return Status.SUCCESS; + + case android.hardware.bluetooth.Status.ALREADY_INITIALIZED: + return Status.ALREADY_INITIALIZED; + + case android.hardware.bluetooth.Status.UNABLE_TO_OPEN_INTERFACE: + return Status.UNABLE_TO_OPEN_INTERFACE; + + case android.hardware.bluetooth.Status.HARDWARE_INITIALIZATION_ERROR: + return Status.INITIALIZATION_ERROR; + + default: + return Status.UNKNOWN; + } + } + + // HciHal methods. + @Override + public void sendPacket(HciPacket.Type type, byte[] packet) { + try { + switch (type) { + case COMMAND: + mHciService.sendHciCommand(packet); + break; + + case ACL_DATA: + mHciService.sendAclData(packet); + break; + + case SCO_DATA: + mHciService.sendScoData(packet); + break; + + case ISO_DATA: + mHciService.sendIsoData(packet); + break; + } + } catch (RemoteException error) { + Log.w(TAG, "failed to forward packet: " + error); + } + } + + // IBluetoothHciCallbacks methods. + @Override + public synchronized void initializationComplete(int status) throws RemoteException { + mInitializationStatus = status; + notifyAll(); + } + + @Override + public void hciEventReceived(byte[] event) throws RemoteException { + mHciCallbacks.onPacket(HciPacket.Type.EVENT, event); + } + + @Override + public void aclDataReceived(byte[] data) throws RemoteException { + mHciCallbacks.onPacket(HciPacket.Type.ACL_DATA, data); + } + + @Override + public void scoDataReceived(byte[] data) throws RemoteException { + mHciCallbacks.onPacket(HciPacket.Type.SCO_DATA, data); + } + + @Override + public void isoDataReceived(byte[] data) throws RemoteException { + mHciCallbacks.onPacket(HciPacket.Type.ISO_DATA, data); + } +} \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciHalCallback.java b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciHalCallback.java new file mode 100644 index 00000000..5878fc16 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciHalCallback.java @@ -0,0 +1,5 @@ +package com.github.google.bumble.remotehci; + +public interface HciHalCallback { + public void onPacket(HciPacket.Type type, byte[] packet); +} diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciPacket.java b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciPacket.java new file mode 100644 index 00000000..2f3162b3 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciPacket.java @@ -0,0 +1,69 @@ +package com.github.google.bumble.remotehci; + +import java.util.ArrayList; + +public class HciPacket { + public enum Type { + COMMAND((byte) 1), + ACL_DATA((byte) 2), + SCO_DATA((byte) 3), + EVENT((byte) 4), + ISO_DATA((byte)5); + + final byte value; + final int lengthSize; + final int lengthOffset; + + Type(byte value) throws IllegalArgumentException { + switch (value) { + case 1: + case 3: + lengthSize = 1; + lengthOffset = 2; + break; + + case 2: + case 5: + lengthSize = 2; + lengthOffset = 2; + break; + + case 4: + lengthSize = 1; + lengthOffset = 1; + break; + + default: + throw new IllegalArgumentException(); + + } + this.value = value; + } + + static Type fromValue(byte value) { + for (Type type : values()) { + if (type.value == value) { + return type; + } + } + return null; + } + } + + public static ArrayList byteArrayToList(byte[] byteArray) { + ArrayList list = new ArrayList<>(); + list.ensureCapacity(byteArray.length); + for (byte x : byteArray) { + list.add(x); + } + return list; + } + + public static byte[] listToByteArray(ArrayList byteList) { + byte[] byteArray = new byte[byteList.size()]; + for (int i = 0; i < byteList.size(); i++) { + byteArray[i] = byteList.get(i); + } + return byteArray; + } +} diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciParser.java b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciParser.java new file mode 100644 index 00000000..8647468c --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciParser.java @@ -0,0 +1,83 @@ +package com.github.google.bumble.remotehci; + +import static java.lang.Integer.min; + +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + + +class HciParser { + Sink sink; + State state; + int bytesNeeded; + ByteArrayOutputStream packet = new ByteArrayOutputStream(); + HciPacket.Type packetType; + + HciParser(Sink sink) { + this.sink = sink; + reset(); + } + + void feedData(byte[] data, int dataSize) { + int dataOffset = 0; + int dataLeft = dataSize; + + while (dataLeft > 0 && bytesNeeded > 0) { + int consumed = min(dataLeft, bytesNeeded); + if (state != State.NEED_TYPE) { + packet.write(data, dataOffset, consumed); + } + bytesNeeded -= consumed; + + if (bytesNeeded == 0) { + if (state == State.NEED_TYPE) { + packetType = HciPacket.Type.fromValue(data[dataOffset]); + if (packetType == null) { + throw new InvalidFormatException(); + } + bytesNeeded = packetType.lengthOffset + packetType.lengthSize; + state = State.NEED_LENGTH; + } else if (state == State.NEED_LENGTH) { + ByteBuffer lengthBuffer = + ByteBuffer.wrap(packet.toByteArray()) + .order(ByteOrder.LITTLE_ENDIAN); + bytesNeeded = packetType.lengthSize == 1 ? + lengthBuffer.get(packetType.lengthOffset) & 0xFF : + lengthBuffer.getShort(packetType.lengthOffset) & 0xFFFF; + state = State.NEED_BODY; + } + + // Emit a packet if one is complete. + if (state == State.NEED_BODY && bytesNeeded == 0) { + if (sink != null) { + sink.onPacket(packetType, packet.toByteArray()); + } + + reset(); + } + } + + dataOffset += consumed; + dataLeft -= consumed; + } + } + + void reset() { + state = State.NEED_TYPE; + bytesNeeded = 1; + packet.reset(); + packetType = null; + } + + enum State { + NEED_TYPE, NEED_LENGTH, NEED_BODY + } + + interface Sink { + void onPacket(HciPacket.Type type, byte[] packet); + } + + static class InvalidFormatException extends RuntimeException { + } +} \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciProxy.java b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciProxy.java new file mode 100644 index 00000000..1949a636 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciProxy.java @@ -0,0 +1,143 @@ +package com.github.google.bumble.remotehci; + +import android.os.RemoteException; +import android.util.Log; + +import java.io.IOException; + +public class HciProxy { + private static final String TAG = "HciProxy"; + private final HciServer mServer; + private final Listener mListener; + private int mCommandPacketsReceived; + private int mAclPacketsReceived; + private int mScoPacketsReceived; + private int mEventPacketsSent; + private int mAclPacketsSent; + private int mScoPacketsSent; + + HciProxy(int port, Listener listener) throws HalException { + this.mListener = listener; + + // Instantiate a HAL to communicate with the hardware. + HciHal hciHal = HciHal.create(new HciHalCallback() { + @Override + public void onPacket(HciPacket.Type type, byte[] packet) { + mServer.sendPacket(type, packet); + + switch (type) { + case EVENT: + mEventPacketsSent += 1; + break; + + case ACL_DATA: + mAclPacketsSent += 1; + break; + + case SCO_DATA: + mScoPacketsSent += 1; + break; + } + updateHciPacketCount(); + } + }); + if (hciHal == null) { + String message = "Could not instantiate a HAL instance"; + Log.w(TAG, message); + throw new HalException(message); + } + + // Initialize the HAL. + HciHal.Status status = null; + try { + status = hciHal.initialize(); + } catch (RemoteException | InterruptedException e) { + throw new HalException("Exception while initializing"); + } + if (status != HciHal.Status.SUCCESS) { + String message = "HAL initialization failed: " + status.label; + Log.w(TAG, message); + throw new HalException(message); + } + + // Create a server to accept clients. + mServer = new HciServer(port, new HciServer.Listener() { + @Override + public void onHostConnectionState(boolean connected) { + mListener.onHostConnectionState(connected); + if (connected) { + mCommandPacketsReceived = 0; + mAclPacketsReceived = 0; + mScoPacketsReceived = 0; + mEventPacketsSent = 0; + mAclPacketsSent = 0; + mScoPacketsSent = 0; + updateHciPacketCount(); + } + } + + @Override + public void onMessage(String message) { + listener.onMessage(message); + } + + @Override + public void onPacket(HciPacket.Type type, byte[] packet) { + Log.d(TAG, String.format("onPacket: type=%s, size=%d", type, packet.length)); + hciHal.sendPacket(type, packet); + + switch (type) { + case COMMAND: + mCommandPacketsReceived += 1; + break; + + case ACL_DATA: + mAclPacketsReceived += 1; + break; + + case SCO_DATA: + mScoPacketsReceived += 1; + break; + } + updateHciPacketCount(); + } + }); + } + + public void run() throws IOException { + mServer.run(); + } + + private void updateHciPacketCount() { + mListener.onHciPacketCountChange( + mCommandPacketsReceived, + mAclPacketsReceived, + mScoPacketsReceived, + mEventPacketsSent, + mAclPacketsSent, + mScoPacketsSent + ); + } + + public interface Listener { + void onHostConnectionState(boolean connected); + + void onHciPacketCountChange( + int commandPacketsReceived, + int aclPacketsReceived, + int scoPacketsReceived, + int eventPacketsSent, + int aclPacketsSent, + int scoPacketsSent + ); + + void onMessage(String message); + } + + public static class HalException extends RuntimeException { + public final String message; + public HalException(String message) { + this.message = message; + } + } +} diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciServer.java b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciServer.java new file mode 100644 index 00000000..a78a86a0 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/HciServer.java @@ -0,0 +1,92 @@ +package com.github.google.bumble.remotehci; + +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; + + +public class HciServer { + private static final String TAG = "HciServer"; + private static final int BUFFER_SIZE = 1024; + private final int mPort; + private final Listener mListener; + private OutputStream mOutputStream; + + public interface Listener extends HciParser.Sink { + void onHostConnectionState(boolean connected); + void onMessage(String message); + } + + HciServer(int port, Listener listener) { + this.mPort = port; + this.mListener = listener; + } + + public void run() throws IOException { + for (;;) { + try { + loop(); + } catch (IOException error) { + mListener.onMessage("Cannot listen on port " + mPort); + return; + } + } + } + + private void loop() throws IOException { + mListener.onHostConnectionState(false); + try (ServerSocket serverSocket = new ServerSocket(mPort)) { + mListener.onMessage("Waiting for connection on port " + serverSocket.getLocalPort()); + try (Socket clientSocket = serverSocket.accept()) { + mListener.onHostConnectionState(true); + mListener.onMessage("Connected"); + HciParser parser = new HciParser(mListener); + InputStream inputStream = clientSocket.getInputStream(); + synchronized (this) { + mOutputStream = clientSocket.getOutputStream(); + } + byte[] buffer = new byte[BUFFER_SIZE]; + + try { + for (; ; ) { + int bytesRead = inputStream.read(buffer); + if (bytesRead < 0) { + Log.d(TAG, "end of stream"); + break; + } + parser.feedData(buffer, bytesRead); + } + } catch (IOException error) { + Log.d(TAG, "exception in read loop: " + error); + } + } + } finally { + synchronized (this) { + mOutputStream = null; + } + } + } + + public void sendPacket(HciPacket.Type type, byte[] packet) { + // Create a combined data buffer so we can write it out in a single call. + byte[] data = new byte[packet.length + 1]; + data[0] = type.value; + System.arraycopy(packet, 0, data, 1, packet.length); + + synchronized (this) { + if (mOutputStream != null) { + try { + mOutputStream.write(data); + } catch (IOException error) { + Log.w(TAG, "failed to write packet: " + error); + } + } else { + Log.d(TAG, "no client, dropping packet"); + } + } + } +} diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/MainActivity.kt b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/MainActivity.kt new file mode 100644 index 00000000..3a2630af --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/MainActivity.kt @@ -0,0 +1,229 @@ +package com.github.google.bumble.remotehci + +import android.content.Context +import android.content.SharedPreferences +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Button +import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.ViewModel +import com.github.google.bumble.remotehci.HciProxy.HalException +import com.github.google.bumble.remotehci.ui.theme.RemoteHCITheme +import java.io.IOException +import java.util.logging.Logger +import kotlin.concurrent.thread + +const val DEFAULT_TCP_PORT = 9993 +const val TCP_PORT_PREF_KEY = "tcp_port" + +class AppViewModel : ViewModel(), HciProxy.Listener { + private var preferences: SharedPreferences? = null + var tcpPort by mutableStateOf(DEFAULT_TCP_PORT) + var canStart by mutableStateOf(true) + var message by mutableStateOf("") + var hostConnected by mutableStateOf(false) + var hciCommandPacketsReceived by mutableStateOf(0) + var hciAclPacketsReceived by mutableStateOf(0) + var hciScoPacketsReceived by mutableStateOf(0) + var hciEventPacketsSent by mutableStateOf(0) + var hciAclPacketsSent by mutableStateOf(0) + var hciScoPacketsSent by mutableStateOf(0) + + fun loadPreferences(preferences: SharedPreferences) { + this.preferences = preferences + val savedTcpPortString = preferences.getString(TCP_PORT_PREF_KEY, null) + if (savedTcpPortString != null) { + val savedTcpPortInt = savedTcpPortString.toIntOrNull() + if (savedTcpPortInt != null) { + tcpPort = savedTcpPortInt + } + } + } + + fun updateTcpPort(tcpPort: Int) { + this.tcpPort = tcpPort + + // Save the port to the preferences + with (preferences!!.edit()) { + putString(TCP_PORT_PREF_KEY, tcpPort.toString()) + apply() + } + } + + override fun onHostConnectionState(connected: Boolean) { + hostConnected = connected + } + + override fun onHciPacketCountChange( + commandPacketsReceived: Int, + aclPacketsReceived: Int, + scoPacketsReceived: Int, + eventPacketsSent: Int, + aclPacketsSent: Int, + scoPacketsSent: Int + ) { + hciCommandPacketsReceived = commandPacketsReceived + hciAclPacketsReceived = aclPacketsReceived + hciScoPacketsReceived = scoPacketsReceived + hciEventPacketsSent = eventPacketsSent + hciAclPacketsSent = aclPacketsSent + hciScoPacketsSent = scoPacketsSent + + } + + override fun onMessage(message: String) { + this.message = message + } +} + +class MainActivity : ComponentActivity() { + private val log = Logger.getLogger(MainActivity::class.java.name) + private val appViewModel = AppViewModel() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + appViewModel.loadPreferences(getPreferences(Context.MODE_PRIVATE)) + + val tcpPort = intent.getIntExtra("port", -1) + if (tcpPort >= 0) { + appViewModel.tcpPort = tcpPport + } + + setContent { + MainView(appViewModel, ::startProxy) + } + + if (intent.getBooleanExtra("autostart", false)) { + startProxy() + } + } + + private fun startProxy() { + // Run the proxy in a thread. + appViewModel.message = "" + thread { + log.info("HCI Proxy thread starting") + appViewModel.canStart = false + try { + val hciProxy = HciProxy(appViewModel.tcpPort, appViewModel) + hciProxy.run() + } catch (error: IOException) { + log.warning("Exception while running HCI Server: $error") + } catch (error: HalException) { + log.warning("HAL exception: ${error.message}") + appViewModel.message = "Cannot bind to HAL (${error.message}). You may need to use the command 'setenforce 0' in a root adb shell." + } + log.info("HCI Proxy thread ended") + appViewModel.canStart = true + } + } +} + +@Composable +fun ActionButton(text: String, onClick: () -> Unit, enabled: Boolean) { + Button(onClick = onClick, enabled = enabled) { + Text(text = text) + } +} + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) +@Composable +fun MainView(appViewModel: AppViewModel, startProxy: () -> Unit) { + RemoteHCITheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background + ) { + Column(modifier = Modifier.padding(horizontal = 16.dp)) { + Text( + text = "Bumble Remote HCI", + fontSize = 24.sp, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) + Divider() + Text( + text = appViewModel.message + ) + Divider() + val keyboardController = LocalSoftwareKeyboardController.current + TextField( + label = { + Text(text = "TCP Port") + }, + value = appViewModel.tcpPort.toString(), + modifier = Modifier.fillMaxWidth(), + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), + onValueChange = { + if (it.isNotEmpty()) { + val tcpPort = it.toIntOrNull() + if (tcpPort != null) { + appViewModel.updateTcpPort(tcpPort) + } + } + }, + keyboardActions = KeyboardActions( + onDone = {keyboardController?.hide()} + ) + ) + Divider() + val connectState = if (appViewModel.hostConnected) "CONNECTED" else "DISCONNECTED" + Text( + text = "HOST: $connectState", + modifier = Modifier.background(color = if (appViewModel.hostConnected) Color.Green else Color.Red), + color = Color.Black + ) + Divider() + Text( + text = "Command Packets Received: ${appViewModel.hciCommandPacketsReceived}" + ) + Text( + text = "ACL Packets Received: ${appViewModel.hciAclPacketsReceived}" + ) + Text( + text = "SCO Packets Received: ${appViewModel.hciScoPacketsReceived}" + ) + Text( + text = "Event Packets Sent: ${appViewModel.hciEventPacketsSent}" + ) + Text( + text = "ACL Packets Sent: ${appViewModel.hciAclPacketsSent}" + ) + Text( + text = "SCO Packets Sent: ${appViewModel.hciScoPacketsSent}" + ) + Divider() + ActionButton( + text = "Start", onClick = startProxy, enabled = appViewModel.canStart + ) + } + } + } +} \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Color.kt b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Color.kt new file mode 100644 index 00000000..420958d5 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.github.google.bumble.remotehci.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Theme.kt b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Theme.kt new file mode 100644 index 00000000..8d707c98 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Theme.kt @@ -0,0 +1,70 @@ +package com.github.google.bumble.remotehci.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun RemoteHCITheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Type.kt b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Type.kt new file mode 100644 index 00000000..5017af23 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/java/com/github/google/bumble/remotehci/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.github.google.bumble.remotehci.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/extras/android/RemoteHCI/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/extras/android/RemoteHCI/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..036d09bc --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 00000000..f01f61e6 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..bb2143e0 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 00000000..1d9c6ae1 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 00000000..2a80e302 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..9764352d Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 00000000..45f205bb Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 00000000..c607bc0a Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..bb2d0f80 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..54c5d2f3 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 00000000..9afe5656 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..a5f95712 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..142c967c Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 00000000..c9792ade Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 00000000..434da3f5 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..b48797d8 Binary files /dev/null and b/extras/android/RemoteHCI/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/extras/android/RemoteHCI/app/src/main/res/values/colors.xml b/extras/android/RemoteHCI/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..f8c6127d --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/res/values/ic_launcher_background.xml b/extras/android/RemoteHCI/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 00000000..c5d5899f --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/res/values/strings.xml b/extras/android/RemoteHCI/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..af779413 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Remote HCI + \ No newline at end of file diff --git a/extras/android/RemoteHCI/app/src/main/res/values/themes.xml b/extras/android/RemoteHCI/app/src/main/res/values/themes.xml new file mode 100644 index 00000000..cd813bf3 --- /dev/null +++ b/extras/android/RemoteHCI/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +