Compare commits

...

13 Commits

Author SHA1 Message Date
Gilles Boccon-Gibod
dc6b466a42 add intent parameters 2023-10-11 16:52:15 -07:00
Gilles Boccon-Gibod
5e5c9c2580 fix byte order and packet accounting 2023-10-10 21:17:20 -07:00
Gilles Boccon-Gibod
246b11925c add remote hci android app 2023-10-06 14:10:51 -07:00
Gilles Boccon-Gibod
dfa9131192 Merge pull request #311 from zxzxwu/rust
Fix Rust lints
2023-10-06 13:37:47 -07:00
Josh Wu
88c801b4c2 Replace or_insert_with with or_default 2023-10-06 18:02:46 +08:00
Gilles Boccon-Gibod
a1b55b94e0 Merge pull request #301 from whitevegagabriel/simplify-event-loop-copy
Remove unncecesary steps for injecting Python event loop
2023-10-02 12:12:41 -07:00
Gilles Boccon-Gibod
80db9e2e2f Merge pull request #303 from whitevegagabriel/hci-command-rs
Ability to send HCI commands from Rust
2023-10-02 12:12:05 -07:00
Gabriel White-Vega
ce74690420 Update pdl to 0.2.0
- Allows removing impl PartialEq for pdl Error
2023-10-02 11:20:44 -04:00
Gilles Boccon-Gibod
50de4dfb5d Merge pull request #307 from google/gbg/hotfix-001
don't delete advertising prefs on disconnection
2023-09-30 17:46:53 -07:00
Gilles Boccon-Gibod
9bcdf860f4 don't delete advertising prefs on disconnection 2023-09-30 17:41:18 -07:00
Gabriel White-Vega
511ab4b630 Add python async wrapper, move hci non-wrapper to internal, add hci::internal tests 2023-09-29 10:23:19 -04:00
Gabriel White-Vega
7e331c2944 Ability to send HCI commands from Rust
* Autogenerate packet code in Rust from PDL (packet file copied from rootcanal)
* Implement parsing of packets that have a type header
* Expose Python APIs for sending HCI commands
* Expose Python APIs for instantiating a local controller
2023-09-27 11:17:47 -04:00
Gabriel White-Vega
50fd2218fa Remove unncecesary steps for injecting Python event loop
* Context vars can be injected directly into Rust future and spawned with tokio
2023-09-22 15:23:01 -04:00
103 changed files with 13181 additions and 135 deletions

View File

@@ -1425,10 +1425,10 @@ class Device(CompositeEventEmitter):
check_result=True,
)
self.advertising_own_address_type = own_address_type
self.auto_restart_advertising = auto_restart
self.advertising_type = advertising_type
self.advertising_own_address_type = own_address_type
self.advertising = True
self.auto_restart_advertising = auto_restart
async def stop_advertising(self) -> None:
# Disable advertising
@@ -1438,9 +1438,9 @@ class Device(CompositeEventEmitter):
check_result=True,
)
self.advertising_type = None
self.advertising_own_address_type = None
self.advertising = False
self.advertising_type = None
self.auto_restart_advertising = False
@property
@@ -2630,7 +2630,6 @@ class Device(CompositeEventEmitter):
own_address_type = self.advertising_own_address_type
# We are no longer advertising
self.advertising_own_address_type = None
self.advertising = False
if own_address_type in (
@@ -2687,7 +2686,6 @@ class Device(CompositeEventEmitter):
and self.advertising
and self.advertising_type.is_directed
):
self.advertising_own_address_type = None
self.advertising = False
# Notify listeners

View File

@@ -33,7 +33,7 @@ from typing import (
Union,
overload,
)
from functools import wraps
from functools import wraps, partial
from pyee import EventEmitter
from .colors import color
@@ -410,3 +410,20 @@ class FlowControlAsyncPipe:
self.resume_source()
self.check_pump()
async def async_call(function, *args, **kwargs):
"""
Immediately calls the function with provided args and kwargs, wrapping it in an async function.
Rust's `pyo3_asyncio` library needs functions to be marked async to properly inject a running loop.
result = await async_call(some_function, ...)
"""
return function(*args, **kwargs)
def wrap_async(function):
"""
Wraps the provided function in an async function.
"""
return partial(async_call, function)

View File

@@ -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

View File

@@ -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:<outside-port> tcp:<inside-port>
```
Where ``<outside-port>`` is the port number for a listening socket on your laptop or
desktop machine, and <inside-port> 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:<host>:<port>`` 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
```

View File

@@ -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.

View File

@@ -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.

10
extras/android/RemoteHCI/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
*.iml
.gradle
/local.properties
/.idea
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

View File

@@ -0,0 +1 @@
/build

View File

@@ -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"))
}

View File

@@ -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

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.RemoteHCI"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.RemoteHCI">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -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 <name>-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);
}

View File

@@ -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 <name>-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);
}

View File

@@ -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 <name>-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,
}

View File

@@ -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);
};

View File

@@ -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);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<Byte> 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<Byte> 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<Byte> 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<String> 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<String> 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<byte[/* 32 */]> 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<Byte> 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<Byte> 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<Byte> 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<String> 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<String> _hidl_out_descriptors = _hidl_reply.readStringVector();
return _hidl_out_descriptors;
} finally {
_hidl_reply.release();
}
}
@Override
public void debug(NativeHandle fd, java.util.ArrayList<String> 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<byte[/* 32 */]> 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<byte[/* 32 */]> _hidl_out_hashchain = new java.util.ArrayList<byte[/* 32 */]>();
{
HwBlob _hidl_blob = _hidl_reply.readBuffer(16 /* size */);
{
int _hidl_vec_size = _hidl_blob.getInt32(0 /* offset */ + 8 /* offsetof(hidl_vec<T>, mSize) */);
HwBlob childBlob = _hidl_reply.readEmbeddedBuffer(
_hidl_vec_size * 32,_hidl_blob.handle(),
0 /* offset */ + 0 /* offsetof(hidl_vec<T>, mBuffer) */,true /* nullable */);
((java.util.ArrayList<byte[/* 32 */]>) _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<byte[/* 32 */]>) _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<String> interfaceChain() {
return new java.util.ArrayList<String>(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<String> options) {
return;
}
@Override
public final String interfaceDescriptor() {
return android.hardware.bluetooth.V1_0.IBluetoothHci.kInterfaceName;
}
@Override
public final java.util.ArrayList<byte[/* 32 */]> getHashChain() {
return new java.util.ArrayList<byte[/* 32 */]>(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<Byte> 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<Byte> 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<Byte> 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<String> _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<String> 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<byte[/* 32 */]> _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<T>, mSize) */, _hidl_vec_size);
_hidl_blob.putBool(0 /* offset */ + 12 /* offsetof(hidl_vec<T>, 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<T>, 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;
}
}
}
}
}

View File

@@ -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<Byte> 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<Byte> 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<Byte> 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<String> 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<String> 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<byte[/* 32 */]> 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<Byte> 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<Byte> 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<Byte> 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<String> 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<String> _hidl_out_descriptors = _hidl_reply.readStringVector();
return _hidl_out_descriptors;
} finally {
_hidl_reply.release();
}
}
@Override
public void debug(NativeHandle fd, java.util.ArrayList<String> 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<byte[/* 32 */]> 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<byte[/* 32 */]> _hidl_out_hashchain = new java.util.ArrayList<byte[/* 32 */]>();
{
HwBlob _hidl_blob = _hidl_reply.readBuffer(16 /* size */);
{
int _hidl_vec_size = _hidl_blob.getInt32(0 /* offset */ + 8 /* offsetof(hidl_vec<T>, mSize) */);
HwBlob childBlob = _hidl_reply.readEmbeddedBuffer(
_hidl_vec_size * 32,_hidl_blob.handle(),
0 /* offset */ + 0 /* offsetof(hidl_vec<T>, mBuffer) */,true /* nullable */);
((java.util.ArrayList<byte[/* 32 */]>) _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<byte[/* 32 */]>) _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<String> interfaceChain() {
return new java.util.ArrayList<String>(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<String> options) {
return;
}
@Override
public final String interfaceDescriptor() {
return android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.kInterfaceName;
}
@Override
public final java.util.ArrayList<byte[/* 32 */]> getHashChain() {
return new java.util.ArrayList<byte[/* 32 */]>(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<Byte> 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<Byte> 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<Byte> 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<String> _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<String> 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<byte[/* 32 */]> _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<T>, mSize) */, _hidl_vec_size);
_hidl_blob.putBool(0 /* offset */ + 12 /* offsetof(hidl_vec<T>, 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<T>, 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;
}
}
}
}
}

View File

@@ -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<String> 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);
}
};

View File

@@ -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<Byte> 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<String> 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<String> 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<byte[/* 32 */]> 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<Byte> 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<Byte> 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<Byte> 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<Byte> 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<String> 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<String> _hidl_out_descriptors = _hidl_reply.readStringVector();
return _hidl_out_descriptors;
} finally {
_hidl_reply.release();
}
}
@Override
public void debug(NativeHandle fd, java.util.ArrayList<String> 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<byte[/* 32 */]> 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<byte[/* 32 */]> _hidl_out_hashchain = new java.util.ArrayList<byte[/* 32 */]>();
{
HwBlob _hidl_blob = _hidl_reply.readBuffer(16 /* size */);
{
int _hidl_vec_size = _hidl_blob.getInt32(0 /* offset */ + 8 /* offsetof(hidl_vec<T>, mSize) */);
HwBlob childBlob = _hidl_reply.readEmbeddedBuffer(
_hidl_vec_size * 32,_hidl_blob.handle(),
0 /* offset */ + 0 /* offsetof(hidl_vec<T>, mBuffer) */,true /* nullable */);
((java.util.ArrayList<byte[/* 32 */]>) _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<byte[/* 32 */]>) _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<String> interfaceChain() {
return new java.util.ArrayList<String>(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<String> options) {
return;
}
@Override
public final String interfaceDescriptor() {
return android.hardware.bluetooth.V1_1.IBluetoothHci.kInterfaceName;
}
@Override
public final java.util.ArrayList<byte[/* 32 */]> getHashChain() {
return new java.util.ArrayList<byte[/* 32 */]>(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<Byte> 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<Byte> 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<Byte> 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<Byte> 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<String> _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<String> 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<byte[/* 32 */]> _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<T>, mSize) */, _hidl_vec_size);
_hidl_blob.putBool(0 /* offset */ + 12 /* offsetof(hidl_vec<T>, 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<T>, 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;
}
}
}
}
}

View File

@@ -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<Byte> 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<String> 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<String> 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<byte[/* 32 */]> 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<Byte> 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<Byte> 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<Byte> 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<Byte> 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<String> 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<String> _hidl_out_descriptors = _hidl_reply.readStringVector();
return _hidl_out_descriptors;
} finally {
_hidl_reply.release();
}
}
@Override
public void debug(NativeHandle fd, java.util.ArrayList<String> 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<byte[/* 32 */]> 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<byte[/* 32 */]> _hidl_out_hashchain = new java.util.ArrayList<byte[/* 32 */]>();
{
HwBlob _hidl_blob = _hidl_reply.readBuffer(16 /* size */);
{
int _hidl_vec_size = _hidl_blob.getInt32(0 /* offset */ + 8 /* offsetof(hidl_vec<T>, mSize) */);
HwBlob childBlob = _hidl_reply.readEmbeddedBuffer(
_hidl_vec_size * 32,_hidl_blob.handle(),
0 /* offset */ + 0 /* offsetof(hidl_vec<T>, mBuffer) */,true /* nullable */);
((java.util.ArrayList<byte[/* 32 */]>) _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<byte[/* 32 */]>) _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<String> interfaceChain() {
return new java.util.ArrayList<String>(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<String> options) {
return;
}
@Override
public final String interfaceDescriptor() {
return android.hardware.bluetooth.V1_1.IBluetoothHciCallbacks.kInterfaceName;
}
@Override
public final java.util.ArrayList<byte[/* 32 */]> getHashChain() {
return new java.util.ArrayList<byte[/* 32 */]>(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<Byte> 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<Byte> 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<Byte> 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<Byte> 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<String> _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<String> 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<byte[/* 32 */]> _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<T>, mSize) */, _hidl_vec_size);
_hidl_blob.putBool(0 /* offset */ + 12 /* offsetof(hidl_vec<T>, 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<T>, 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;
}
}
}
}
}

View File

@@ -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<Byte> 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<Byte> event) throws RemoteException {
byte[] packet = HciPacket.listToByteArray(event);
mHciCallbacks.onPacket(HciPacket.Type.EVENT, packet);
}
@Override
public void aclDataReceived(ArrayList<Byte> data) throws RemoteException {
byte[] packet = HciPacket.listToByteArray(data);
mHciCallbacks.onPacket(HciPacket.Type.ACL_DATA, packet);
}
@Override
public void scoDataReceived(ArrayList<Byte> 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);
}
}

View File

@@ -0,0 +1,5 @@
package com.github.google.bumble.remotehci;
public interface HciHalCallback {
public void onPacket(HciPacket.Type type, byte[] packet);
}

View File

@@ -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<Byte> byteArrayToList(byte[] byteArray) {
ArrayList<Byte> list = new ArrayList<>();
list.ensureCapacity(byteArray.length);
for (byte x : byteArray) {
list.add(x);
}
return list;
}
public static byte[] listToByteArray(ArrayList<Byte> byteList) {
byte[] byteArray = new byte[byteList.size()];
for (int i = 0; i < byteList.size(); i++) {
byteArray[i] = byteList.get(i);
}
return byteArray;
}
}

View File

@@ -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 {
}
}

View File

@@ -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;
}
}
}

View File

@@ -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");
}
}
}
}

View File

@@ -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
)
}
}
}
}

View File

@@ -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)

View File

@@ -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
)
}

View File

@@ -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
)
*/
)

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">Remote HCI</string>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.RemoteHCI" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@@ -0,0 +1,8 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.kotlinAndroid) apply false
alias(libs.plugins.androidLibrary) apply false
}
true // Needed to make the Suppress annotation work for the plugins block

View File

@@ -0,0 +1,23 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

View File

@@ -0,0 +1,36 @@
[versions]
agp = "8.3.0-alpha05"
kotlin = "1.8.10"
core-ktx = "1.9.0"
junit = "4.13.2"
androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
lifecycle-runtime-ktx = "2.6.1"
activity-compose = "1.7.2"
compose-bom = "2023.03.00"
appcompat = "1.6.1"
material = "1.9.0"
[libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle-runtime-ktx" }
activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" }
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
ui = { group = "androidx.compose.ui", name = "ui" }
ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
material3 = { group = "androidx.compose.material3", name = "material3" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
androidLibrary = { id = "com.android.library", version.ref = "agp" }

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Sun Aug 06 12:53:26 PDT 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-rc-2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
extras/android/RemoteHCI/gradlew vendored Executable file
View File

@@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# 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
#
# https://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.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
extras/android/RemoteHCI/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,39 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.androidLibrary)
}
android {
namespace = "com.github.google.bumble"
compileSdk = 34
defaultConfig {
minSdk = 26
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
implementation(libs.appcompat)
implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
}

View File

@@ -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

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@@ -0,0 +1,17 @@
package android.internal.hidl.base.V1_0;
import android.os.HwParcel;
public class DebugInfo {
public static final class Architecture {
public static final int UNKNOWN = 0;
}
public int pid = 0;
public long ptr = 0L;
public int arch = 0;
public final void readFromParcel(HwParcel parcel) {
}
public final void writeToParcel(HwParcel parcel) {
}
}

View File

@@ -0,0 +1,20 @@
package android.internal.hidl.base.V1_0;
import android.os.IHwBinder;
import android.os.IHwInterface;
public interface IBase extends IHwInterface {
public static final String kInterfaceName = "android.hidl.base@1.0::IBase";
public static abstract class Stub extends android.os.HwBinder implements IBase {
public void onTransact(int _hidl_code, android.os.HwParcel _hidl_request, final android.os.HwParcel _hidl_reply, int _hidl_flags)
throws android.os.RemoteException {}
}
public static final class Proxy implements IBase {
@Override
public IHwBinder asBinder() {
return null;
}
}
}

View File

@@ -0,0 +1,8 @@
package android.os;
public class HidlSupport {
public static boolean interfacesEqual(IHwInterface lft, Object rgt) {
return false; // STUB
}
public static native int getPidIfSharable();
}

View File

@@ -0,0 +1,40 @@
package android.os;
public class HwBinder implements IHwBinder {
public native final void registerService(String serviceName);
public static final IHwBinder getService(
String iface,
String serviceName) {
return null; //STUB
}
public static final IHwBinder getService(
String iface,
String serviceName,
boolean retry) {
return null; // STUB
}
public static void enableInstrumentation() {
}
@Override
public IHwInterface queryLocalInterface(String descriptor) {
return null; // STUB
}
@Override
public void transact(int code, HwParcel request, HwParcel reply, int flags) {
}
@Override
public boolean linkToDeath(DeathRecipient recipient, long cookie) {
return false;
}
@Override
public boolean unlinkToDeath(DeathRecipient recipient) {
return false;
}
}

View File

@@ -0,0 +1,13 @@
package android.os;
public class HwBlob {
public HwBlob(int size) {}
public native final long handle();
public native final int getInt32(long offset);
public native final void putInt32(long offset, int x);
public native final void putBool(long offset, boolean x);
public native final void putInt8Array(long offset, byte[] x);
public native final void putBlob(long offset, HwBlob blob);
public native final void copyToInt8Array(long offset, byte[] array, int size);
}

View File

@@ -0,0 +1,107 @@
package android.os;
import java.util.ArrayList;
public class HwParcel {
public static final int STATUS_SUCCESS = 0;
public native final void writeInterfaceToken(String interfaceName);
public native final void writeBool(boolean val);
public native final void writeInt8(byte val);
public native final void writeInt16(short val);
public native final void writeInt32(int val);
public native final void writeInt64(long val);
public native final void writeFloat(float val);
public native final void writeDouble(double val);
public native final void writeString(String val);
public native final void writeNativeHandle(NativeHandle val);
private native final void writeBoolVector(boolean[] val);
private native final void writeInt8Vector(byte[] val);
private native final void writeInt16Vector(short[] val);
private native final void writeInt32Vector(int[] val);
private native final void writeInt64Vector(long[] val);
private native final void writeFloatVector(float[] val);
private native final void writeDoubleVector(double[] val);
private native final void writeStringVector(String[] val);
private native final void writeNativeHandleVector(NativeHandle[] val);
public final void writeBoolVector(ArrayList<Boolean> val) {
}
public final void writeInt8Vector(ArrayList<Byte> val) {
}
public final void writeInt16Vector(ArrayList<Short> val) {
}
public final void writeInt32Vector(ArrayList<Integer> val) {
}
public final void writeInt64Vector(ArrayList<Long> val) {
}
public final void writeFloatVector(ArrayList<Float> val) {
}
public final void writeDoubleVector(ArrayList<Double> val) {
}
public final void writeStringVector(ArrayList<String> val) {
}
public final void writeNativeHandleVector(ArrayList<NativeHandle> val) {
}
public native final void writeStrongBinder(IHwBinder binder);
//public native final void writeHidlMemory(HidlMemory memory);
public native final void enforceInterface(String interfaceName);
public native final boolean readBool();
public native final byte readInt8();
public native final short readInt16();
public native final int readInt32();
public native final long readInt64();
public native final float readFloat();
public native final double readDouble();
public native final String readString();
public native final NativeHandle readNativeHandle();
public native final NativeHandle readEmbeddedNativeHandle(
long parentHandle, long offset);
private native final boolean[] readBoolVectorAsArray();
private native final byte[] readInt8VectorAsArray();
private native final short[] readInt16VectorAsArray();
private native final int[] readInt32VectorAsArray();
private native final long[] readInt64VectorAsArray();
private native final float[] readFloatVectorAsArray();
private native final double[] readDoubleVectorAsArray();
private native final String[] readStringVectorAsArray();
private native final NativeHandle[] readNativeHandleAsArray();
public final ArrayList<Boolean> readBoolVector() {
return null;
}
public final ArrayList<Byte> readInt8Vector() {
return null;
}
public final ArrayList<Short> readInt16Vector() {
return null;
}
public final ArrayList<Integer> readInt32Vector() {
return null;
}
public final ArrayList<Long> readInt64Vector() {
return null;
}
public final ArrayList<Float> readFloatVector() {
return null;
}
public final ArrayList<Double> readDoubleVector() {
return null;
}
public final ArrayList<String> readStringVector() {
return null;
}
public final ArrayList<NativeHandle> readNativeHandleVector() {
return null;
}
public native final IHwBinder readStrongBinder();
// public native final HidlMemory readHidlMemory();
// public native final
// HidlMemory readEmbeddedHidlMemory(long fieldHandle, long parentHandle, long offset);
public native final HwBlob readBuffer(long expectedSize);
public native final HwBlob readEmbeddedBuffer(
long expectedSize, long parentHandle, long offset,
boolean nullable);
public native final void writeBuffer(HwBlob blob);
public native final void writeStatus(int status);
public native final void verifySuccess();
public native final void releaseTemporaryStorage();
public native final void release();
public native final void send();}

View File

@@ -0,0 +1,11 @@
package android.os;
public interface IHwBinder {
public interface DeathRecipient {
public void serviceDied(long cookie);
}
public IHwInterface queryLocalInterface(String descriptor);
public void transact(int code, HwParcel request, HwParcel reply, int flags);
public boolean linkToDeath(DeathRecipient recipient, long cookie);
public boolean unlinkToDeath(DeathRecipient recipient);
}

View File

@@ -0,0 +1,5 @@
package android.os;
public interface IHwInterface {
public IHwBinder asBinder();
}

View File

@@ -0,0 +1,4 @@
package android.os;
public class NativeHandle {
}

View File

@@ -0,0 +1,7 @@
package android.os;
public final class ServiceManager {
public static IBinder getService(String name) {
return null; // Stub
}
}

View File

@@ -0,0 +1,32 @@
# Run this script to generate the .java files from the .aidl files
# then replace `this.markVintfStability()` with:
# try {
# Method method = this.getClass().getMethod("markVintfStability", null);
# method.invoke(this);
# } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
# throw new RuntimeException(e);
# }
AIDL=$ANDROID_SDK_ROOT/build-tools/34.0.0/aidl
$AIDL \
-oapp/src/main/java \
-Iapp/src/main/aidl \
--stability=vintf \
--structured \
app/src/main/aidl/android/hardware/bluetooth/IBluetoothHci.aidl
$AIDL \
-oapp/src/main/java \
-Iapp/src/main/aidl \
--stability=vintf \
--structured \
app/src/main/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
$AIDL \
-oapp/src/main/java \
-Iapp/src/main/aidl \
--stability=vintf \
--structured \
app/src/main/aidl/android/hardware/bluetooth/Status.aidl

View File

@@ -0,0 +1,18 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "RemoteHCI"
include(":app")
include(":lib")

229
rust/Cargo.lock generated
View File

@@ -80,6 +80,37 @@ version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "argh"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7af5ba06967ff7214ce4c7419c7d185be7ecd6cc4965a8f6e1d8ce0398aad219"
dependencies = [
"argh_derive",
"argh_shared",
]
[[package]]
name = "argh_derive"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56df0aeedf6b7a2fc67d06db35b09684c3e8da0c95f8f27685cb17e08413d87a"
dependencies = [
"argh_shared",
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]]
name = "argh_shared"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5693f39141bda5760ecc4111ab08da40565d1771038c4a0250f03457ec707531"
dependencies = [
"serde",
]
[[package]]
name = "atty"
version = "0.2.14"
@@ -130,6 +161,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bstr"
version = "1.6.2"
@@ -145,6 +185,7 @@ name = "bumble"
version = "0.1.0"
dependencies = [
"anyhow",
"bytes",
"clap 4.4.1",
"directories",
"env_logger",
@@ -158,6 +199,8 @@ dependencies = [
"nix",
"nom",
"owo-colors",
"pdl-derive",
"pdl-runtime",
"pyo3",
"pyo3-asyncio",
"rand",
@@ -178,9 +221,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "bytes"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cc"
@@ -262,6 +305,16 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]]
name = "colorchoice"
version = "1.0.0"
@@ -284,6 +337,15 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
dependencies = [
"libc",
]
[[package]]
name = "crossbeam"
version = "0.8.2"
@@ -351,6 +413,26 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "directories"
version = "5.0.1"
@@ -559,6 +641,16 @@ dependencies = [
"slab",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.10"
@@ -1064,12 +1156,100 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "pdl-compiler"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee66995739fb9ddd9155767990a54aadd226ee32408a94f99f94883ff445ceba"
dependencies = [
"argh",
"codespan-reporting",
"heck",
"pest",
"pest_derive",
"prettyplease",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn 2.0.29",
]
[[package]]
name = "pdl-derive"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "113e4a1215c407466b36d2c2f6a6318819d6b22ccdd3acb7bb35e27a68806034"
dependencies = [
"codespan-reporting",
"pdl-compiler",
"proc-macro2",
"quote",
"syn 2.0.29",
"termcolor",
]
[[package]]
name = "pdl-runtime"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d36c2f9799613babe78eb5cd9a353d527daaba6c3d1f39a1175657a35790732"
dependencies = [
"bytes",
"thiserror",
]
[[package]]
name = "percent-encoding"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]]
name = "pest"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c022f1e7b65d6a24c0dbbd5fb344c66881bc01f3e5ae74a1c8100f2f985d98a4"
dependencies = [
"memchr",
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35513f630d46400a977c4cb58f78e1bfbe01434316e60c37d27b9ad6139c66d8"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc9fc1b9e7057baba189b5c626e2d6f40681ae5b6eb064dc7c7834101ec8123a"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.29",
]
[[package]]
name = "pest_meta"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df74e9e7ec4053ceb980e7c0c8bd3594e977fde1af91daba9c928e8e8c6708d"
dependencies = [
"once_cell",
"pest",
"sha2",
]
[[package]]
name = "pin-project-lite"
version = "0.2.13"
@@ -1094,6 +1274,16 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "prettyplease"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
dependencies = [
"proc-macro2",
"syn 2.0.29",
]
[[package]]
name = "proc-macro2"
version = "1.0.66"
@@ -1465,6 +1655,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
@@ -1711,6 +1912,18 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "ucd-trie"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
[[package]]
name = "unicode-bidi"
version = "0.3.13"
@@ -1738,6 +1951,12 @@ version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unindent"
version = "0.1.11"
@@ -1767,6 +1986,12 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.4.0"

View File

@@ -23,6 +23,9 @@ hex = "0.4.3"
itertools = "0.11.0"
lazy_static = "1.4.0"
thiserror = "1.0.41"
bytes = "1.5.0"
pdl-derive = "0.2.0"
pdl-runtime = "0.2.0"
# Dev tools
file-header = { version = "0.1.2", optional = true }

View File

@@ -20,7 +20,8 @@
use bumble::{
adv::CommonDataType,
wrapper::{
core::AdvertisementDataUnit, device::Device, hci::AddressType, transport::Transport,
core::AdvertisementDataUnit, device::Device, hci::packets::AddressType,
transport::Transport,
},
};
use clap::Parser as _;
@@ -69,9 +70,7 @@ async fn main() -> PyResult<()> {
let mut seen_adv_cache = seen_adv_clone.lock().unwrap();
let expiry_duration = time::Duration::from_secs(cli.dedup_expiry_secs);
let advs_from_addr = seen_adv_cache
.entry(addr_bytes)
.or_insert_with(collections::HashMap::new);
let advs_from_addr = seen_adv_cache.entry(addr_bytes).or_default();
// we expect cache hits to be the norm, so we do a separate lookup to avoid cloning
// on every lookup with entry()
let show = if let Some(prev) = advs_from_addr.get_mut(&data_units) {
@@ -102,7 +101,9 @@ async fn main() -> PyResult<()> {
};
let (type_style, qualifier) = match adv.address()?.address_type()? {
AddressType::PublicIdentity | AddressType::PublicDevice => (Style::new().cyan(), ""),
AddressType::PublicIdentityAddress | AddressType::PublicDeviceAddress => {
(Style::new().cyan(), "")
}
_ => {
if addr.is_static()? {
(Style::new().green(), "(static)")

View File

@@ -12,9 +12,26 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use bumble::wrapper::{drivers::rtk::DriverInfo, transport::Transport};
use bumble::wrapper::{
controller::Controller,
device::Device,
drivers::rtk::DriverInfo,
hci::{
packets::{
AddressType, ErrorCode, ReadLocalVersionInformationBuilder,
ReadLocalVersionInformationComplete,
},
Address, Error,
},
host::Host,
link::Link,
transport::Transport,
};
use nix::sys::stat::Mode;
use pyo3::PyResult;
use pyo3::{
exceptions::PyException,
{PyErr, PyResult},
};
#[pyo3_asyncio::tokio::test]
async fn fifo_transport_can_open() -> PyResult<()> {
@@ -35,3 +52,26 @@ async fn realtek_driver_info_all_drivers() -> PyResult<()> {
assert_eq!(12, DriverInfo::all_drivers()?.len());
Ok(())
}
#[pyo3_asyncio::tokio::test]
async fn hci_command_wrapper_has_correct_methods() -> PyResult<()> {
let address = Address::new("F0:F1:F2:F3:F4:F5", &AddressType::RandomDeviceAddress)?;
let link = Link::new_local_link()?;
let controller = Controller::new("C1", None, None, Some(link), Some(address.clone())).await?;
let host = Host::new(controller.clone().into(), controller.into()).await?;
let device = Device::new(None, Some(address), None, Some(host), None)?;
device.power_on().await?;
// Send some simple command. A successful response means [HciCommandWrapper] has the minimum
// required interface for the Python code to think its an [HCI_Command] object.
let command = ReadLocalVersionInformationBuilder {};
let event: ReadLocalVersionInformationComplete = device
.send_command(&command.into(), true)
.await?
.try_into()
.map_err(|e: Error| PyErr::new::<PyException, _>(e.to_string()))?;
assert_eq!(ErrorCode::Success, event.get_status());
Ok(())
}

View File

@@ -179,7 +179,7 @@ pub(crate) fn parse(firmware_path: &path::Path) -> PyResult<()> {
pub(crate) async fn info(transport: &str, force: bool) -> PyResult<()> {
let transport = Transport::open(transport).await?;
let mut host = Host::new(transport.source()?, transport.sink()?)?;
let mut host = Host::new(transport.source()?, transport.sink()?).await?;
host.reset(DriverFactory::None).await?;
if !force && !Driver::check(&host).await? {
@@ -203,7 +203,7 @@ pub(crate) async fn info(transport: &str, force: bool) -> PyResult<()> {
pub(crate) async fn load(transport: &str, force: bool) -> PyResult<()> {
let transport = Transport::open(transport).await?;
let mut host = Host::new(transport.source()?, transport.sink()?)?;
let mut host = Host::new(transport.source()?, transport.sink()?).await?;
host.reset(DriverFactory::None).await?;
match Driver::for_host(&host, force).await? {
@@ -219,7 +219,7 @@ pub(crate) async fn load(transport: &str, force: bool) -> PyResult<()> {
pub(crate) async fn drop(transport: &str) -> PyResult<()> {
let transport = Transport::open(transport).await?;
let mut host = Host::new(transport.source()?, transport.sink()?)?;
let mut host = Host::new(transport.source()?, transport.sink()?).await?;
host.reset(DriverFactory::None).await?;
Driver::drop_firmware(&mut host).await?;

View File

@@ -21,8 +21,7 @@
/// TCP client to connect.
/// When the L2CAP CoC channel is closed, the TCP connection is closed as well.
use crate::cli::l2cap::{
proxy_l2cap_rx_to_tcp_tx, proxy_tcp_rx_to_l2cap_tx, run_future_with_current_task_locals,
BridgeData,
inject_py_event_loop, proxy_l2cap_rx_to_tcp_tx, proxy_tcp_rx_to_l2cap_tx, BridgeData,
};
use bumble::wrapper::{
device::{Connection, Device},
@@ -85,11 +84,12 @@ pub async fn start(args: &Args, device: &mut Device) -> PyResult<()> {
let mtu = args.mtu;
let mps = args.mps;
let ble_connection = Arc::new(Mutex::new(ble_connection));
// Ensure Python event loop is available to l2cap `disconnect`
let _ = run_future_with_current_task_locals(async move {
// spawn thread to handle incoming tcp connections
tokio::spawn(inject_py_event_loop(async move {
while let Ok((tcp_stream, addr)) = listener.accept().await {
let ble_connection = ble_connection.clone();
let _ = run_future_with_current_task_locals(proxy_data_between_tcp_and_l2cap(
// spawn thread to handle this specific tcp connection
if let Ok(future) = inject_py_event_loop(proxy_data_between_tcp_and_l2cap(
ble_connection,
tcp_stream,
addr,
@@ -97,10 +97,11 @@ pub async fn start(args: &Args, device: &mut Device) -> PyResult<()> {
max_credits,
mtu,
mps,
));
)) {
tokio::spawn(future);
}
}
Ok(())
});
})?);
Ok(())
}

View File

@@ -18,7 +18,7 @@ use crate::L2cap;
use anyhow::anyhow;
use bumble::wrapper::{device::Device, l2cap::LeConnectionOrientedChannel, transport::Transport};
use owo_colors::{colors::css::Orange, OwoColorize};
use pyo3::{PyObject, PyResult, Python};
use pyo3::{PyResult, Python};
use std::{future::Future, path::PathBuf, sync::Arc};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
@@ -170,21 +170,12 @@ async fn proxy_tcp_rx_to_l2cap_tx(
}
}
/// Copies the current thread's TaskLocals into a Python "awaitable" and encapsulates it in a Rust
/// future, running it as a Python Task.
/// `TaskLocals` stores the current event loop, and allows the user to copy the current Python
/// context if necessary. In this case, the python event loop is used when calling `disconnect` on
/// an l2cap connection, or else the call will fail.
pub fn run_future_with_current_task_locals<F>(
fut: F,
) -> PyResult<impl Future<Output = PyResult<PyObject>> + Send>
/// Copies the current thread's Python even loop (contained in `TaskLocals`) into the given future.
/// Useful when sending work to another thread that calls Python code which calls `get_running_loop()`.
pub fn inject_py_event_loop<F, R>(fut: F) -> PyResult<impl Future<Output = R>>
where
F: Future<Output = PyResult<()>> + Send + 'static,
F: Future<Output = R> + Send + 'static,
{
Python::with_gil(|py| {
let locals = pyo3_asyncio::tokio::get_current_locals(py)?;
let future = pyo3_asyncio::tokio::scope(locals.clone(), fut);
pyo3_asyncio::tokio::future_into_py_with_locals(py, locals, future)
.and_then(pyo3_asyncio::tokio::into_future)
})
let locals = Python::with_gil(pyo3_asyncio::tokio::get_current_locals)?;
Ok(pyo3_asyncio::tokio::scope(locals, fut))
}

View File

@@ -19,10 +19,7 @@
/// When the L2CAP CoC channel is closed, the bridge disconnects the TCP socket
/// and waits for a new L2CAP CoC channel to be connected.
/// When the TCP connection is closed by the TCP server, the L2CAP connection is closed as well.
use crate::cli::l2cap::{
proxy_l2cap_rx_to_tcp_tx, proxy_tcp_rx_to_l2cap_tx, run_future_with_current_task_locals,
BridgeData,
};
use crate::cli::l2cap::{proxy_l2cap_rx_to_tcp_tx, proxy_tcp_rx_to_l2cap_tx, BridgeData};
use bumble::wrapper::{device::Device, hci::HciConstant, l2cap::LeConnectionOrientedChannel};
use futures::executor::block_on;
use owo_colors::OwoColorize;
@@ -49,19 +46,19 @@ pub async fn start(args: &Args, device: &mut Device) -> PyResult<()> {
let port = args.tcp_port;
device.register_l2cap_channel_server(
args.psm,
move |_py, l2cap_channel| {
move |py, l2cap_channel| {
let channel_info = l2cap_channel
.debug_string()
.unwrap_or_else(|e| format!("failed to get l2cap channel info ({e})"));
println!("{} {channel_info}", "*** L2CAP channel:".cyan());
let host = host.clone();
// Ensure Python event loop is available to l2cap `disconnect`
let _ = run_future_with_current_task_locals(proxy_data_between_l2cap_and_tcp(
l2cap_channel,
host,
port,
));
// Handles setting up a tokio runtime that runs this future to completion while also
// containing the necessary context vars.
pyo3_asyncio::tokio::future_into_py(
py,
proxy_data_between_l2cap_and_tcp(l2cap_channel, host, port),
)?;
Ok(())
},
args.max_credits,

View File

@@ -143,10 +143,7 @@ pub(crate) fn probe(verbose: bool) -> anyhow::Result<()> {
);
if let Some(s) = serial {
println!("{:26}{}", " Serial:".green(), s);
device_serials_by_id
.entry(device_id)
.or_insert(HashSet::new())
.insert(s);
device_serials_by_id.entry(device_id).or_default().insert(s);
}
if let Some(m) = mfg {
println!("{:26}{}", " Manufacturer:".green(), m);
@@ -314,7 +311,7 @@ impl ClassInfo {
self.protocol,
self.protocol_name()
.map(|s| format!(" [{}]", s))
.unwrap_or_else(String::new)
.unwrap_or_default()
)
}
}

View File

@@ -0,0 +1,161 @@
// Copyright 2023 Google LLC
//
// 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.
pub use pdl_runtime::{Error, Packet};
use crate::internal::hci::packets::{Acl, Command, Event, Sco};
use pdl_derive::pdl;
#[allow(missing_docs, warnings, clippy::all)]
#[pdl("src/internal/hci/packets.pdl")]
pub mod packets {}
#[cfg(test)]
mod tests;
/// HCI Packet type, prepended to the packet.
/// Rootcanal's PDL declaration excludes this from ser/deser and instead is implemented in code.
/// To maintain the ability to easily use future versions of their packet PDL, packet type is
/// implemented here.
#[derive(Debug, PartialEq)]
pub(crate) enum PacketType {
Command = 0x01,
Acl = 0x02,
Sco = 0x03,
Event = 0x04,
}
impl TryFrom<u8> for PacketType {
type Error = PacketTypeParseError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x01 => Ok(PacketType::Command),
0x02 => Ok(PacketType::Acl),
0x03 => Ok(PacketType::Sco),
0x04 => Ok(PacketType::Event),
_ => Err(PacketTypeParseError::InvalidPacketType { value }),
}
}
}
impl From<PacketType> for u8 {
fn from(packet_type: PacketType) -> Self {
match packet_type {
PacketType::Command => 0x01,
PacketType::Acl => 0x02,
PacketType::Sco => 0x03,
PacketType::Event => 0x04,
}
}
}
/// Allows for smoother interoperability between a [Packet] and a bytes representation of it that
/// includes its type as a header
pub(crate) trait WithPacketType<T: Packet> {
/// Converts the [Packet] into bytes, prefixed with its type
fn to_vec_with_packet_type(self) -> Vec<u8>;
/// Parses a [Packet] out of bytes that are prefixed with the packet's type
fn parse_with_packet_type(bytes: &[u8]) -> Result<T, PacketTypeParseError>;
}
/// Errors that may arise when parsing a packet that is prefixed with its type
#[derive(Debug, PartialEq, thiserror::Error)]
pub(crate) enum PacketTypeParseError {
#[error("The slice being parsed was empty")]
EmptySlice,
#[error("Packet type ({value:#X}) is invalid")]
InvalidPacketType { value: u8 },
#[error("Expected packet type: {expected:?}, but got: {actual:?}")]
PacketTypeMismatch {
expected: PacketType,
actual: PacketType,
},
#[error("Failed to parse packet after header: {error}")]
PacketParse { error: Error },
}
impl From<Error> for PacketTypeParseError {
fn from(error: Error) -> Self {
Self::PacketParse { error }
}
}
impl WithPacketType<Self> for Command {
fn to_vec_with_packet_type(self) -> Vec<u8> {
prepend_packet_type(PacketType::Command, self.to_vec())
}
fn parse_with_packet_type(bytes: &[u8]) -> Result<Self, PacketTypeParseError> {
parse_with_expected_packet_type(Command::parse, PacketType::Command, bytes)
}
}
impl WithPacketType<Self> for Acl {
fn to_vec_with_packet_type(self) -> Vec<u8> {
prepend_packet_type(PacketType::Acl, self.to_vec())
}
fn parse_with_packet_type(bytes: &[u8]) -> Result<Self, PacketTypeParseError> {
parse_with_expected_packet_type(Acl::parse, PacketType::Acl, bytes)
}
}
impl WithPacketType<Self> for Sco {
fn to_vec_with_packet_type(self) -> Vec<u8> {
prepend_packet_type(PacketType::Sco, self.to_vec())
}
fn parse_with_packet_type(bytes: &[u8]) -> Result<Self, PacketTypeParseError> {
parse_with_expected_packet_type(Sco::parse, PacketType::Sco, bytes)
}
}
impl WithPacketType<Self> for Event {
fn to_vec_with_packet_type(self) -> Vec<u8> {
prepend_packet_type(PacketType::Event, self.to_vec())
}
fn parse_with_packet_type(bytes: &[u8]) -> Result<Self, PacketTypeParseError> {
parse_with_expected_packet_type(Event::parse, PacketType::Event, bytes)
}
}
fn prepend_packet_type(packet_type: PacketType, mut packet_bytes: Vec<u8>) -> Vec<u8> {
packet_bytes.insert(0, packet_type.into());
packet_bytes
}
fn parse_with_expected_packet_type<T: Packet, F, E>(
parser: F,
expected_packet_type: PacketType,
bytes: &[u8],
) -> Result<T, PacketTypeParseError>
where
F: Fn(&[u8]) -> Result<T, E>,
PacketTypeParseError: From<E>,
{
let (first_byte, packet_bytes) = bytes
.split_first()
.ok_or(PacketTypeParseError::EmptySlice)?;
let actual_packet_type = PacketType::try_from(*first_byte)?;
if actual_packet_type == expected_packet_type {
Ok(parser(packet_bytes)?)
} else {
Err(PacketTypeParseError::PacketTypeMismatch {
expected: expected_packet_type,
actual: actual_packet_type,
})
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
// Copyright 2023 Google LLC
//
// 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.
use crate::internal::hci::{
packets::{Event, EventBuilder, EventCode, Sco},
parse_with_expected_packet_type, prepend_packet_type, Error, Packet, PacketType,
PacketTypeParseError, WithPacketType,
};
use bytes::Bytes;
#[test]
fn prepends_packet_type() {
let packet_type = PacketType::Event;
let packet_bytes = vec![0x00, 0x00, 0x00, 0x00];
let actual = prepend_packet_type(packet_type, packet_bytes);
assert_eq!(vec![0x04, 0x00, 0x00, 0x00, 0x00], actual);
}
#[test]
fn parse_empty_slice_should_error() {
let actual = parse_with_expected_packet_type(FakePacket::parse, PacketType::Event, &[]);
assert_eq!(Err(PacketTypeParseError::EmptySlice), actual);
}
#[test]
fn parse_invalid_packet_type_should_error() {
let actual = parse_with_expected_packet_type(FakePacket::parse, PacketType::Event, &[0xFF]);
assert_eq!(
Err(PacketTypeParseError::InvalidPacketType { value: 0xFF }),
actual
);
}
#[test]
fn parse_mismatched_packet_type_should_error() {
let actual = parse_with_expected_packet_type(FakePacket::parse, PacketType::Acl, &[0x01]);
assert_eq!(
Err(PacketTypeParseError::PacketTypeMismatch {
expected: PacketType::Acl,
actual: PacketType::Command
}),
actual
);
}
#[test]
fn parse_invalid_packet_should_error() {
let actual = parse_with_expected_packet_type(Sco::parse, PacketType::Sco, &[0x03]);
assert!(actual.is_err());
}
#[test]
fn test_packet_roundtrip_with_type() {
let event_packet = EventBuilder {
event_code: EventCode::InquiryComplete,
payload: None,
}
.build();
let event_packet_bytes = event_packet.clone().to_vec_with_packet_type();
let actual =
parse_with_expected_packet_type(Event::parse, PacketType::Event, &event_packet_bytes)
.unwrap();
assert_eq!(event_packet, actual);
}
#[derive(Debug, PartialEq)]
struct FakePacket;
impl FakePacket {
fn parse(_bytes: &[u8]) -> Result<Self, Error> {
Ok(Self)
}
}
impl Packet for FakePacket {
fn to_bytes(self) -> Bytes {
Bytes::new()
}
fn to_vec(self) -> Vec<u8> {
Vec::new()
}
}

View File

@@ -18,3 +18,4 @@
//! to discover.
pub(crate) mod drivers;
pub(crate) mod hci;

View File

@@ -0,0 +1,34 @@
// Copyright 2023 Google LLC
//
// 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.
//! Shared resources found under bumble's common.py
use pyo3::{PyObject, Python, ToPyObject};
/// Represents the sink for some transport mechanism
pub struct TransportSink(pub(crate) PyObject);
impl ToPyObject for TransportSink {
fn to_object(&self, _py: Python<'_>) -> PyObject {
self.0.clone()
}
}
/// Represents the source for some transport mechanism
pub struct TransportSource(pub(crate) PyObject);
impl ToPyObject for TransportSource {
fn to_object(&self, _py: Python<'_>) -> PyObject {
self.0.clone()
}
}

View File

@@ -0,0 +1,66 @@
// Copyright 2023 Google LLC
//
// 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.
//! Controller components
use crate::wrapper::{
common::{TransportSink, TransportSource},
hci::Address,
link::Link,
wrap_python_async, PyDictExt,
};
use pyo3::{
intern,
types::{PyDict, PyModule},
PyObject, PyResult, Python,
};
use pyo3_asyncio::tokio::into_future;
/// A controller that can send and receive HCI frames via some link
#[derive(Clone)]
pub struct Controller(pub(crate) PyObject);
impl Controller {
/// Creates a new [Controller] object. When optional arguments are not specified, the Python
/// module specifies the defaults. Must be called from a thread with a Python event loop, which
/// should be true on `tokio::main` and `async_std::main`.
///
/// For more info, see https://awestlake87.github.io/pyo3-asyncio/master/doc/pyo3_asyncio/#event-loop-references-and-contextvars.
pub async fn new(
name: &str,
host_source: Option<TransportSource>,
host_sink: Option<TransportSink>,
link: Option<Link>,
public_address: Option<Address>,
) -> PyResult<Self> {
Python::with_gil(|py| {
let controller_ctr = PyModule::import(py, intern!(py, "bumble.controller"))?
.getattr(intern!(py, "Controller"))?;
let kwargs = PyDict::new(py);
kwargs.set_item("name", name)?;
kwargs.set_opt_item("host_source", host_source)?;
kwargs.set_opt_item("host_sink", host_sink)?;
kwargs.set_opt_item("link", link)?;
kwargs.set_opt_item("public_address", public_address)?;
// Controller constructor (`__init__`) is not (and can't be) marked async, but calls
// `get_running_loop`, and thus needs wrapped in an async function.
wrap_python_async(py, controller_ctr)?
.call((), Some(kwargs))
.and_then(into_future)
})?
.await
.map(Self)
}
}

View File

@@ -14,12 +14,16 @@
//! Devices and connections to them
use crate::internal::hci::WithPacketType;
use crate::{
adv::AdvertisementDataBuilder,
wrapper::{
core::AdvertisingData,
gatt_client::{ProfileServiceProxy, ServiceProxy},
hci::{Address, HciErrorCode},
hci::{
packets::{Command, ErrorCode, Event},
Address, HciCommandWrapper,
},
host::Host,
l2cap::LeConnectionOrientedChannel,
transport::{Sink, Source},
@@ -27,18 +31,73 @@ use crate::{
},
};
use pyo3::{
exceptions::PyException,
intern,
types::{PyDict, PyModule},
IntoPy, PyObject, PyResult, Python, ToPyObject,
IntoPy, PyErr, PyObject, PyResult, Python, ToPyObject,
};
use pyo3_asyncio::tokio::into_future;
use std::path;
/// Represents the various properties of some device
pub struct DeviceConfiguration(PyObject);
impl DeviceConfiguration {
/// Creates a new configuration, letting the internal Python object set all the defaults
pub fn new() -> PyResult<DeviceConfiguration> {
Python::with_gil(|py| {
PyModule::import(py, intern!(py, "bumble.device"))?
.getattr(intern!(py, "DeviceConfiguration"))?
.call0()
.map(|any| Self(any.into()))
})
}
/// Creates a new configuration from the specified file
pub fn load_from_file(&mut self, device_config: &path::Path) -> PyResult<()> {
Python::with_gil(|py| {
self.0
.call_method1(py, intern!(py, "load_from_file"), (device_config,))
})
.map(|_| ())
}
}
impl ToPyObject for DeviceConfiguration {
fn to_object(&self, _py: Python<'_>) -> PyObject {
self.0.clone()
}
}
/// A device that can send/receive HCI frames.
#[derive(Clone)]
pub struct Device(PyObject);
impl Device {
/// Creates a Device. When optional arguments are not specified, the Python object specifies the
/// defaults.
pub fn new(
name: Option<&str>,
address: Option<Address>,
config: Option<DeviceConfiguration>,
host: Option<Host>,
generic_access_service: Option<bool>,
) -> PyResult<Self> {
Python::with_gil(|py| {
let kwargs = PyDict::new(py);
kwargs.set_opt_item("name", name)?;
kwargs.set_opt_item("address", address)?;
kwargs.set_opt_item("config", config)?;
kwargs.set_opt_item("host", host)?;
kwargs.set_opt_item("generic_access_service", generic_access_service)?;
PyModule::import(py, intern!(py, "bumble.device"))?
.getattr(intern!(py, "Device"))?
.call((), Some(kwargs))
.map(|any| Self(any.into()))
})
}
/// Create a Device per the provided file configured to communicate with a controller through an HCI source/sink
pub fn from_config_file_with_hci(
device_config: &path::Path,
@@ -66,6 +125,29 @@ impl Device {
})
}
/// Sends an HCI command on this Device, returning the command's event result.
pub async fn send_command(&self, command: &Command, check_result: bool) -> PyResult<Event> {
Python::with_gil(|py| {
self.0
.call_method1(
py,
intern!(py, "send_command"),
(HciCommandWrapper(command.clone()), check_result),
)
.and_then(|coroutine| into_future(coroutine.as_ref(py)))
})?
.await
.and_then(|event| {
Python::with_gil(|py| {
let py_bytes = event.call_method0(py, intern!(py, "__bytes__"))?;
let bytes: &[u8] = py_bytes.extract(py)?;
let event = Event::parse_with_packet_type(bytes)
.map_err(|e| PyErr::new::<PyException, _>(e.to_string()))?;
Ok(event)
})
})
}
/// Turn the device on
pub async fn power_on(&self) -> PyResult<()> {
Python::with_gil(|py| {
@@ -236,7 +318,7 @@ impl Connection {
kwargs.set_opt_item("mps", mps)?;
self.0
.call_method(py, intern!(py, "open_l2cap_channel"), (), Some(kwargs))
.and_then(|coroutine| pyo3_asyncio::tokio::into_future(coroutine.as_ref(py)))
.and_then(|coroutine| into_future(coroutine.as_ref(py)))
})?
.await
.map(LeConnectionOrientedChannel::from)
@@ -244,13 +326,13 @@ impl Connection {
/// Disconnect from device with provided reason. When optional arguments are not specified, the
/// Python module specifies the defaults.
pub async fn disconnect(&mut self, reason: Option<HciErrorCode>) -> PyResult<()> {
pub async fn disconnect(&mut self, reason: Option<ErrorCode>) -> PyResult<()> {
Python::with_gil(|py| {
let kwargs = PyDict::new(py);
kwargs.set_opt_item("reason", reason)?;
self.0
.call_method(py, intern!(py, "disconnect"), (), Some(kwargs))
.and_then(|coroutine| pyo3_asyncio::tokio::into_future(coroutine.as_ref(py)))
.and_then(|coroutine| into_future(coroutine.as_ref(py)))
})?
.await
.map(|_| ())
@@ -259,7 +341,7 @@ impl Connection {
/// Register a callback to be called on disconnection.
pub fn on_disconnection(
&mut self,
callback: impl Fn(Python, HciErrorCode) -> PyResult<()> + Send + 'static,
callback: impl Fn(Python, ErrorCode) -> PyResult<()> + Send + 'static,
) -> PyResult<()> {
let boxed = ClosureCallback::new(move |py, args, _kwargs| {
callback(py, args.get_item(0)?.extract()?)

View File

@@ -14,84 +14,62 @@
//! HCI
pub use crate::internal::hci::{packets, Error, Packet};
use crate::{
internal::hci::WithPacketType,
wrapper::hci::packets::{AddressType, Command, ErrorCode},
};
use itertools::Itertools as _;
use pyo3::{
exceptions::PyException, intern, types::PyModule, FromPyObject, PyAny, PyErr, PyObject,
PyResult, Python, ToPyObject,
exceptions::PyException,
intern, pyclass, pymethods,
types::{PyBytes, PyModule},
FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject,
};
/// HCI error code.
pub struct HciErrorCode(u8);
impl<'source> FromPyObject<'source> for HciErrorCode {
fn extract(ob: &'source PyAny) -> PyResult<Self> {
Ok(HciErrorCode(ob.extract()?))
}
}
impl ToPyObject for HciErrorCode {
fn to_object(&self, py: Python<'_>) -> PyObject {
self.0.to_object(py)
}
}
/// Provides helpers for interacting with HCI
pub struct HciConstant;
impl HciConstant {
/// Human-readable error name
pub fn error_name(status: HciErrorCode) -> PyResult<String> {
pub fn error_name(status: ErrorCode) -> PyResult<String> {
Python::with_gil(|py| {
PyModule::import(py, intern!(py, "bumble.hci"))?
.getattr(intern!(py, "HCI_Constant"))?
.call_method1(intern!(py, "error_name"), (status.0,))?
.call_method1(intern!(py, "error_name"), (status.to_object(py),))?
.extract()
})
}
}
/// A Bluetooth address
#[derive(Clone)]
pub struct Address(pub(crate) PyObject);
impl Address {
/// Creates a new [Address] object
pub fn new(address: &str, address_type: &AddressType) -> PyResult<Self> {
Python::with_gil(|py| {
PyModule::import(py, intern!(py, "bumble.device"))?
.getattr(intern!(py, "Address"))?
.call1((address, address_type.to_object(py)))
.map(|any| Self(any.into()))
})
}
/// The type of address
pub fn address_type(&self) -> PyResult<AddressType> {
Python::with_gil(|py| {
let addr_type = self
.0
self.0
.getattr(py, intern!(py, "address_type"))?
.extract::<u32>(py)?;
let module = PyModule::import(py, intern!(py, "bumble.hci"))?;
let klass = module.getattr(intern!(py, "Address"))?;
if addr_type
== klass
.getattr(intern!(py, "PUBLIC_DEVICE_ADDRESS"))?
.extract::<u32>()?
{
Ok(AddressType::PublicDevice)
} else if addr_type
== klass
.getattr(intern!(py, "RANDOM_DEVICE_ADDRESS"))?
.extract::<u32>()?
{
Ok(AddressType::RandomDevice)
} else if addr_type
== klass
.getattr(intern!(py, "PUBLIC_IDENTITY_ADDRESS"))?
.extract::<u32>()?
{
Ok(AddressType::PublicIdentity)
} else if addr_type
== klass
.getattr(intern!(py, "RANDOM_IDENTITY_ADDRESS"))?
.extract::<u32>()?
{
Ok(AddressType::RandomIdentity)
} else {
Err(PyErr::new::<PyException, _>("Invalid address type"))
}
.extract::<u8>(py)?
.try_into()
.map_err(|addr_type| {
PyErr::new::<PyException, _>(format!(
"Failed to convert {addr_type} to AddressType"
))
})
})
}
@@ -134,12 +112,45 @@ impl Address {
}
}
/// BT address types
#[allow(missing_docs)]
#[derive(PartialEq, Eq, Debug)]
pub enum AddressType {
PublicDevice,
RandomDevice,
PublicIdentity,
RandomIdentity,
impl ToPyObject for Address {
fn to_object(&self, _py: Python<'_>) -> PyObject {
self.0.clone()
}
}
/// Implements minimum necessary interface to be treated as bumble's [HCI_Command].
/// While pyo3's macros do not support generics, this could probably be refactored to allow multiple
/// implementations of the HCI_Command methods in the future, if needed.
#[pyclass]
pub(crate) struct HciCommandWrapper(pub(crate) Command);
#[pymethods]
impl HciCommandWrapper {
fn __bytes__(&self, py: Python) -> PyResult<PyObject> {
let bytes = PyBytes::new(py, &self.0.clone().to_vec_with_packet_type());
Ok(bytes.into_py(py))
}
#[getter]
fn op_code(&self) -> u16 {
self.0.get_op_code().into()
}
}
impl ToPyObject for AddressType {
fn to_object(&self, py: Python<'_>) -> PyObject {
u8::from(self).to_object(py)
}
}
impl<'source> FromPyObject<'source> for ErrorCode {
fn extract(ob: &'source PyAny) -> PyResult<Self> {
ob.extract()
}
}
impl ToPyObject for ErrorCode {
fn to_object(&self, py: Python<'_>) -> PyObject {
u8::from(self).to_object(py)
}
}

View File

@@ -14,8 +14,12 @@
//! Host-side types
use crate::wrapper::transport::{Sink, Source};
use pyo3::{intern, prelude::PyModule, types::PyDict, PyObject, PyResult, Python};
use crate::wrapper::{
transport::{Sink, Source},
wrap_python_async,
};
use pyo3::{intern, prelude::PyModule, types::PyDict, PyObject, PyResult, Python, ToPyObject};
use pyo3_asyncio::tokio::into_future;
/// Host HCI commands
pub struct Host {
@@ -29,13 +33,23 @@ impl Host {
}
/// Create a new Host
pub fn new(source: Source, sink: Sink) -> PyResult<Self> {
pub async fn new(source: Source, sink: Sink) -> PyResult<Self> {
Python::with_gil(|py| {
PyModule::import(py, intern!(py, "bumble.host"))?
.getattr(intern!(py, "Host"))?
.call((source.0, sink.0), None)
.map(|any| Self { obj: any.into() })
})
let host_ctr =
PyModule::import(py, intern!(py, "bumble.host"))?.getattr(intern!(py, "Host"))?;
let kwargs = PyDict::new(py);
kwargs.set_item("controller_source", source.0)?;
kwargs.set_item("controller_sink", sink.0)?;
// Needed for Python 3.8-3.9, in which the Semaphore object, when constructed, calls
// `get_event_loop`.
wrap_python_async(py, host_ctr)?
.call((), Some(kwargs))
.and_then(into_future)
})?
.await
.map(|any| Self { obj: any })
}
/// Send a reset command and perform other reset tasks.
@@ -61,6 +75,12 @@ impl Host {
}
}
impl ToPyObject for Host {
fn to_object(&self, _py: Python<'_>) -> PyObject {
self.obj.clone()
}
}
/// Driver factory to use when initializing a host
#[derive(Debug, Clone)]
pub enum DriverFactory {

Some files were not shown because too many files have changed in this diff Show More