floss: Add set-alias to btclient and API.
Adds support for changing the remote device alias. This also fixes the
BluetoothProperty conversions which were being done incorrectly
(off-by-one).
Bug: 196887190
Tag: #floss
Test: Built floss, verified alias can be updated in btclient.
Change-Id: I2c21feb9bb6763c4147997f349b06904c4bff20d
diff --git a/system/gd/rust/linux/client/src/command_handler.rs b/system/gd/rust/linux/client/src/command_handler.rs
index f2221cc..266dd5f 100644
--- a/system/gd/rust/linux/client/src/command_handler.rs
+++ b/system/gd/rust/linux/client/src/command_handler.rs
@@ -437,7 +437,7 @@
return;
}
- enforce_arg_len(args, 2, "device <connect|disconnect|info> <address>", || {
+ enforce_arg_len(args, 2, "device <connect|disconnect|info|set-alias> <address>", || {
match &args[0][0..] {
"connect" => {
let device = BluetoothDevice {
@@ -519,6 +519,31 @@
)
);
}
+ "set-alias" => {
+ if args.len() < 3 {
+ println!("usage: device set-alias <address> <new-alias>");
+ return;
+ }
+ let new_alias = &args[2];
+ let device =
+ BluetoothDevice { address: String::from(&args[1]), name: String::from("") };
+ let old_alias = self
+ .context
+ .lock()
+ .unwrap()
+ .adapter_dbus
+ .as_ref()
+ .unwrap()
+ .get_remote_alias(device.clone());
+ println!("Updating alias for {}: {} -> {}", &args[1], old_alias, new_alias);
+ self.context
+ .lock()
+ .unwrap()
+ .adapter_dbus
+ .as_mut()
+ .unwrap()
+ .set_remote_alias(device.clone(), new_alias.clone());
+ }
_ => {
println!("Invalid argument '{}'", args[0]);
}
diff --git a/system/gd/rust/linux/client/src/dbus_iface.rs b/system/gd/rust/linux/client/src/dbus_iface.rs
index 300316f..a18729e 100644
--- a/system/gd/rust/linux/client/src/dbus_iface.rs
+++ b/system/gd/rust/linux/client/src/dbus_iface.rs
@@ -400,6 +400,11 @@
dbus_generated!()
}
+ #[dbus_method("SetRemoteAlias")]
+ fn set_remote_alias(&mut self, device: BluetoothDevice, new_alias: String) {
+ dbus_generated!()
+ }
+
#[dbus_method("GetRemoteClass")]
fn get_remote_class(&self, device: BluetoothDevice) -> u32 {
dbus_generated!()
diff --git a/system/gd/rust/linux/service/src/iface_bluetooth.rs b/system/gd/rust/linux/service/src/iface_bluetooth.rs
index 37769b6..10229b2 100644
--- a/system/gd/rust/linux/service/src/iface_bluetooth.rs
+++ b/system/gd/rust/linux/service/src/iface_bluetooth.rs
@@ -248,6 +248,11 @@
dbus_generated!()
}
+ #[dbus_method("SetRemoteAlias")]
+ fn set_remote_alias(&mut self, _device: BluetoothDevice, new_alias: String) {
+ dbus_generated!()
+ }
+
#[dbus_method("GetRemoteClass")]
fn get_remote_class(&self, _device: BluetoothDevice) -> u32 {
dbus_generated!()
diff --git a/system/gd/rust/linux/stack/src/bluetooth.rs b/system/gd/rust/linux/stack/src/bluetooth.rs
index f2a610d..3728d1a 100644
--- a/system/gd/rust/linux/stack/src/bluetooth.rs
+++ b/system/gd/rust/linux/stack/src/bluetooth.rs
@@ -131,6 +131,9 @@
/// Gets the alias of the remote device.
fn get_remote_alias(&self, device: BluetoothDevice) -> String;
+ /// Sets the alias of the remote device.
+ fn set_remote_alias(&mut self, device: BluetoothDevice, new_alias: String);
+
/// Gets the class of the remote device.
fn get_remote_class(&self, device: BluetoothDevice) -> u32;
@@ -399,6 +402,16 @@
self.bonded_devices.get(&device.address).or_else(|| self.found_devices.get(&device.address))
}
+ fn get_remote_device_if_found_mut(
+ &mut self,
+ device: &BluetoothDevice,
+ ) -> Option<&mut BluetoothDeviceContext> {
+ match self.bonded_devices.get_mut(&device.address) {
+ None => self.found_devices.get_mut(&device.address),
+ some => some,
+ }
+ }
+
fn get_remote_device_property(
&self,
device: &BluetoothDevice,
@@ -407,6 +420,31 @@
self.get_remote_device_if_found(&device)
.and_then(|d| d.properties.get(property_type).and_then(|p| Some(p.clone())))
}
+
+ fn set_remote_device_property(
+ &mut self,
+ device: &BluetoothDevice,
+ property_type: BtPropertyType,
+ property: BluetoothProperty,
+ ) -> Result<(), ()> {
+ let mut remote_device = match self.get_remote_device_if_found_mut(&device) {
+ Some(d) => d,
+ None => {
+ return Err(());
+ }
+ };
+
+ let mut addr = RawAddress::from_string(device.address.clone());
+ if addr.is_none() {
+ return Err(());
+ }
+ let addr = addr.as_mut().unwrap();
+
+ // TODO: Determine why a callback isn't invoked to do this.
+ remote_device.properties.insert(property_type, property.clone());
+ self.intf.lock().unwrap().set_remote_device_property(addr, property);
+ Ok(())
+ }
}
#[btif_callbacks_dispatcher(Bluetooth, dispatch_base_callbacks, BaseCallbacks)]
@@ -1115,6 +1153,14 @@
}
}
+ fn set_remote_alias(&mut self, device: BluetoothDevice, new_alias: String) {
+ let _ = self.set_remote_device_property(
+ &device,
+ BtPropertyType::RemoteFriendlyName,
+ BluetoothProperty::RemoteFriendlyName(new_alias),
+ );
+ }
+
fn get_remote_class(&self, device: BluetoothDevice) -> u32 {
match self.get_remote_device_property(&device, &BtPropertyType::ClassOfDevice) {
Some(BluetoothProperty::ClassOfDevice(class)) => return class,
diff --git a/system/gd/rust/topshim/src/btif.rs b/system/gd/rust/topshim/src/btif.rs
index 625f815..452d7a6 100644
--- a/system/gd/rust/topshim/src/btif.rs
+++ b/system/gd/rust/topshim/src/btif.rs
@@ -382,7 +382,9 @@
let len = self.get_len();
match &*self {
BluetoothProperty::BdName(name) => {
- data.copy_from_slice(&name.as_bytes()[0..len]);
+ let copy_len = len - 1;
+ data[0..copy_len].copy_from_slice(&name.as_bytes()[0..copy_len]);
+ data[copy_len] = 0;
}
BluetoothProperty::BdAddr(addr) => {
data.copy_from_slice(&addr.val);
@@ -408,11 +410,12 @@
unsafe { &mut *(data.as_mut_ptr() as *mut bindings::bt_service_record_t) };
record.uuid = sr.uuid;
record.channel = sr.channel;
- let name_len = len - mem::size_of::<BtServiceRecord>();
- record.name.copy_from_slice(
+ let name_len = len - mem::size_of::<BtServiceRecord>() - 1;
+ record.name[0..name_len].copy_from_slice(
&(sr.name.as_bytes().iter().map(|x| *x as c_char).collect::<Vec<c_char>>())
[0..name_len],
);
+ record.name[name_len] = 0;
}
BluetoothProperty::AdapterScanMode(sm) => {
data.copy_from_slice(&BtScanMode::to_u32(sm).unwrap_or_default().to_ne_bytes());
@@ -428,7 +431,9 @@
data.copy_from_slice(&timeout.to_ne_bytes());
}
BluetoothProperty::RemoteFriendlyName(name) => {
- data.copy_from_slice(&name.as_bytes()[0..len]);
+ let copy_len = len - 1;
+ data[0..copy_len].copy_from_slice(&name.as_bytes()[0..copy_len]);
+ data[copy_len] = 0;
}
BluetoothProperty::RemoteRssi(rssi) => {
data[0] = *rssi as u8;
@@ -1110,4 +1115,46 @@
let expected: Vec<i32> = vec![1, 2, 3];
assert_eq!(expected, vec);
}
+
+ #[test]
+ fn test_property_with_string_conversions() {
+ {
+ let bdname = BluetoothProperty::BdName("FooBar".into());
+ let prop_pair: (Box<[u8]>, bindings::bt_property_t) = bdname.into();
+ let converted: BluetoothProperty = prop_pair.1.into();
+ assert!(match converted {
+ BluetoothProperty::BdName(name) => "FooBar".to_string() == name,
+ _ => false,
+ });
+ }
+
+ {
+ let orig_record = BtServiceRecord {
+ uuid: Uuid { uu: [0; 16] },
+ channel: 3,
+ name: "FooBar".to_string(),
+ };
+ let service_record = BluetoothProperty::ServiceRecord(orig_record.clone());
+ let prop_pair: (Box<[u8]>, bindings::bt_property_t) = service_record.into();
+ let converted: BluetoothProperty = prop_pair.1.into();
+ assert!(match converted {
+ BluetoothProperty::ServiceRecord(sr) => {
+ sr.uuid == orig_record.uuid
+ && sr.channel == orig_record.channel
+ && sr.name == orig_record.name
+ }
+ _ => false,
+ });
+ }
+
+ {
+ let rfname = BluetoothProperty::RemoteFriendlyName("FooBizz".into());
+ let prop_pair: (Box<[u8]>, bindings::bt_property_t) = rfname.into();
+ let converted: BluetoothProperty = prop_pair.1.into();
+ assert!(match converted {
+ BluetoothProperty::RemoteFriendlyName(name) => "FooBizz".to_string() == name,
+ _ => false,
+ });
+ }
+ }
}