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,
+            });
+        }
+    }
 }