Loading system/gd/rust/linux/stack/src/battery_service.rs +48 −25 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ pub struct BatteryService { /// Enum for GATT callbacks to relay messages to the main processing thread. Newly supported /// callbacks should add a corresponding entry here. pub enum GattBatteryCallbacks { pub enum BatteryServiceActions { /// Params: status, client_id OnClientRegistered(GattStatus, i32), /// Params: status, client_id, connected, addr Loading @@ -54,6 +54,10 @@ pub enum GattBatteryCallbacks { OnCharacteristicRead(String, GattStatus, i32, Vec<u8>), /// Params: addr, handle, value OnNotify(String, i32, Vec<u8>), /// Params: remote_device Connect(BluetoothDevice), /// Params: remote_device Disconnect(BluetoothDevice), } /// API for Floss implementation of the Bluetooth Battery Service (BAS). BAS is built on GATT and Loading Loading @@ -118,6 +122,7 @@ impl BatteryService { /// Must be called after BluetoothGatt's init_profiles method has completed. pub fn init(&self) { debug!("Registering GATT client for BatteryService"); self.gatt.lock().unwrap().register_client( // TODO(b/233101174): make dynamic or decide on a static UUID String::from("e4d2acffcfaa42198f494606b7412117"), Loading @@ -127,14 +132,15 @@ impl BatteryService { } /// Handles all callback messages in a central location to avoid deadlocks. pub fn handle_callback(&mut self, callback: GattBatteryCallbacks) { match callback { GattBatteryCallbacks::OnClientRegistered(_status, client_id) => { pub fn handle_action(&mut self, action: BatteryServiceActions) { match action { BatteryServiceActions::OnClientRegistered(_status, client_id) => { debug!("GATT client registered for BAS with id {}", client_id); self.client_id = Some(client_id); } GattBatteryCallbacks::OnClientConnectionState(_status, _client_id, connected, addr) => { if !connected { BatteryServiceActions::OnClientConnectionState(status, _client_id, connected, addr) => { if !connected || status != GattStatus::Success { return; } let client_id = match self.client_id { Loading @@ -146,7 +152,7 @@ impl BatteryService { self.gatt.lock().unwrap().discover_services(client_id, addr); } GattBatteryCallbacks::OnSearchComplete(addr, services, status) => { BatteryServiceActions::OnSearchComplete(addr, services, status) => { if status != GattStatus::Success { debug!("GATT service discovery for {} failed with status {:?}", addr, status); return; Loading Loading @@ -204,7 +210,7 @@ impl BatteryService { } } GattBatteryCallbacks::OnCharacteristicRead(addr, status, _handle, value) => { BatteryServiceActions::OnCharacteristicRead(addr, status, _handle, value) => { if status != GattStatus::Success { return; } Loading @@ -214,23 +220,27 @@ impl BatteryService { }); } GattBatteryCallbacks::OnNotify(addr, _handle, value) => { BatteryServiceActions::OnNotify(addr, _handle, value) => { let battery_info = self.set_battery_info(&addr, &value); self.callbacks.for_all_callbacks(|callback| { callback.on_battery_info_updated(addr.clone(), battery_info.clone()); }); } } } /// Attempt to (re)establish connection to a device when it becomes connected. pub fn device_connected(&mut self, device: BluetoothDevice) { BatteryServiceActions::Connect(device) => { self.init_device(device.address); } BatteryServiceActions::Disconnect(device) => { self.drop_device(device.address); } } } fn set_battery_info(&mut self, remote_address: &String, value: &Vec<u8>) -> BatterySet { let level: Vec<_> = value.iter().cloned().chain(iter::repeat(0 as u8)).take(4).collect(); let level = u32::from_le_bytes(level.try_into().unwrap()); debug!("Received battery level for {}: {}", remote_address.clone(), level); let battery_set = self.battery_sets.entry(remote_address.clone()).or_insert_with(|| { BatterySet::new(remote_address.clone(), uuid::BAS.to_string(), "BAS".to_string()) }); Loading @@ -247,6 +257,7 @@ impl BatteryService { Some(id) => id, None => return, }; debug!("Attempting GATT connection to {}", remote_address.clone()); self.gatt.lock().unwrap().client_connect( client_id, remote_address, Loading @@ -257,6 +268,22 @@ impl BatteryService { ); } fn drop_device(&mut self, remote_address: String) { self.handles.remove(&remote_address); match self.client_id { Some(client_id) => { self.gatt.lock().unwrap().client_disconnect(client_id, remote_address.clone()) } None => return, } // Let BatteryProviderManager know that BAS no longer has a battery for this device. self.battery_provider_manager.lock().unwrap().set_battery_info( self.battery_provider_id, BatterySet::new(remote_address.clone(), uuid::BAS.to_string(), "BAS".to_string()), ); self.battery_sets.remove(&remote_address); } /// Perform an explicit read on all devices BAS knows about. pub fn refresh_all_devices(&self) { self.handles.keys().for_each(|device| { Loading Loading @@ -354,7 +381,7 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks(GattBatteryCallbacks::OnClientRegistered( .send(Message::BatteryService(BatteryServiceActions::OnClientRegistered( status, client_id, ))) .await; Loading @@ -371,11 +398,9 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks( GattBatteryCallbacks::OnClientConnectionState( .send(Message::BatteryService(BatteryServiceActions::OnClientConnectionState( status, client_id, connected, addr, ), )) ))) .await; }); } Loading @@ -389,7 +414,7 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks(GattBatteryCallbacks::OnSearchComplete( .send(Message::BatteryService(BatteryServiceActions::OnSearchComplete( addr, services, status, ))) .await; Loading @@ -406,7 +431,7 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks(GattBatteryCallbacks::OnCharacteristicRead( .send(Message::BatteryService(BatteryServiceActions::OnCharacteristicRead( addr, status, handle, value, ))) .await; Loading @@ -417,9 +442,7 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks(GattBatteryCallbacks::OnNotify( addr, handle, value, ))) .send(Message::BatteryService(BatteryServiceActions::OnNotify(addr, handle, value))) .await; }); } Loading system/gd/rust/linux/stack/src/bluetooth.rs +31 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ use tokio::sync::mpsc::Sender; use tokio::task::JoinHandle; use tokio::time; use crate::battery_service::BatteryServiceActions; use crate::bluetooth_admin::BluetoothAdmin; use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions}; use crate::callbacks::Callbacks; Loading Loading @@ -1123,13 +1124,17 @@ impl BtifBluetoothCallbacks for Bluetooth { }); let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx.send(Message::OnDeviceConnected(device.clone())).await; let _ = tx.send(Message::OnAclConnected(device.clone())).await; }); } BtAclState::Disconnected => { self.connection_callbacks.for_all_callbacks(|callback| { callback.on_device_disconnected(device.clone()); }); let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx.send(Message::OnAclDisconnected(device.clone())).await; }); } }; } Loading Loading @@ -1726,6 +1731,19 @@ impl IBluetooth for Bluetooth { .await; }); } Profile::Bas => { let tx = self.tx.clone(); let device_to_send = device.clone(); topstack::get_runtime().spawn(async move { let _ = tx .send(Message::BatteryService( BatteryServiceActions::Connect(device_to_send), )) .await; }); } // We don't connect most profiles _ => (), } Loading Loading @@ -1794,6 +1812,18 @@ impl IBluetooth for Bluetooth { }); } Profile::Bas => { let tx = self.tx.clone(); let device_to_send = device.clone(); topstack::get_runtime().spawn(async move { let _ = tx .send(Message::BatteryService( BatteryServiceActions::Disconnect(device_to_send), )) .await; }); } // We don't connect most profiles _ => (), } Loading system/gd/rust/linux/stack/src/lib.rs +22 −9 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ use tokio::sync::mpsc::{Receiver, Sender}; use crate::battery_manager::{BatteryManager, BatterySet}; use crate::battery_provider_manager::BatteryProviderManager; use crate::battery_service::{BatteryService, GattBatteryCallbacks}; use crate::battery_service::{BatteryService, BatteryServiceActions}; use crate::bluetooth::{ dispatch_base_callbacks, dispatch_hid_host_callbacks, dispatch_sdp_callbacks, Bluetooth, BluetoothDevice, IBluetooth, Loading Loading @@ -81,9 +81,10 @@ pub enum Message { // Update list of found devices and remove old instances. DeviceFreshnessCheck, // Sent whenever a device connects. Follows IBluetooth's on_device_connected // callback but doesn't require depening on Bluetooth. OnDeviceConnected(BluetoothDevice), // Follows IBluetooth's on_device_(dis)connected callback but doesn't require depending on // Bluetooth. OnAclConnected(BluetoothDevice), OnAclDisconnected(BluetoothDevice), // Suspend related SuspendCallbackRegistered(u32), Loading @@ -104,7 +105,7 @@ pub enum Message { BatteryProviderManagerCallbackDisconnected(u32), BatteryProviderManagerBatteryUpdated(String, BatterySet), BatteryServiceCallbackDisconnected(u32), BatteryServiceCallbacks(GattBatteryCallbacks), BatteryService(BatteryServiceActions), BatteryServiceRefresh, BatteryManagerCallbackDisconnected(u32), Loading Loading @@ -237,8 +238,20 @@ impl Stack { // Any service needing an updated list of devices can have an // update method triggered from here rather than needing a // reference to Bluetooth. Message::OnDeviceConnected(device) => { battery_service.lock().unwrap().device_connected(device); Message::OnAclConnected(device) => { battery_service .lock() .unwrap() .handle_action(BatteryServiceActions::Connect(device)); } // For battery service, use this to clean up internal handles. GATT connection is // already dropped if ACL disconnect has occurred. Message::OnAclDisconnected(device) => { battery_service .lock() .unwrap() .handle_action(BatteryServiceActions::Disconnect(device)); } Message::SuspendCallbackRegistered(id) => { Loading Loading @@ -283,8 +296,8 @@ impl Stack { Message::BatteryServiceCallbackDisconnected(id) => { battery_service.lock().unwrap().remove_callback(id); } Message::BatteryServiceCallbacks(callback) => { battery_service.lock().unwrap().handle_callback(callback); Message::BatteryService(action) => { battery_service.lock().unwrap().handle_action(action); } Message::BatteryServiceRefresh => { battery_service.lock().unwrap().refresh_all_devices(); Loading system/gd/rust/linux/stack/src/uuid.rs +2 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ lazy_static! { static ref SUPPORTED_PROFILES: HashSet<Profile> = [ Profile::A2dpSink, Profile::A2dpSource, Profile::Bas, Profile::Hsp, Profile::Hfp, Profile::Hid, Loading @@ -129,6 +130,7 @@ lazy_static! { (UuidHelper::from_string(A2DP_SINK).unwrap(), Profile::A2dpSink), (UuidHelper::from_string(A2DP_SOURCE).unwrap(), Profile::A2dpSource), (UuidHelper::from_string(ADV_AUDIO_DIST).unwrap(), Profile::AdvAudioDist), (UuidHelper::from_string(BAS).unwrap(), Profile::Bas), (UuidHelper::from_string(HSP).unwrap(), Profile::Hsp), (UuidHelper::from_string(HSP_AG).unwrap(), Profile::HspAg), (UuidHelper::from_string(HFP).unwrap(), Profile::Hfp), Loading Loading
system/gd/rust/linux/stack/src/battery_service.rs +48 −25 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ pub struct BatteryService { /// Enum for GATT callbacks to relay messages to the main processing thread. Newly supported /// callbacks should add a corresponding entry here. pub enum GattBatteryCallbacks { pub enum BatteryServiceActions { /// Params: status, client_id OnClientRegistered(GattStatus, i32), /// Params: status, client_id, connected, addr Loading @@ -54,6 +54,10 @@ pub enum GattBatteryCallbacks { OnCharacteristicRead(String, GattStatus, i32, Vec<u8>), /// Params: addr, handle, value OnNotify(String, i32, Vec<u8>), /// Params: remote_device Connect(BluetoothDevice), /// Params: remote_device Disconnect(BluetoothDevice), } /// API for Floss implementation of the Bluetooth Battery Service (BAS). BAS is built on GATT and Loading Loading @@ -118,6 +122,7 @@ impl BatteryService { /// Must be called after BluetoothGatt's init_profiles method has completed. pub fn init(&self) { debug!("Registering GATT client for BatteryService"); self.gatt.lock().unwrap().register_client( // TODO(b/233101174): make dynamic or decide on a static UUID String::from("e4d2acffcfaa42198f494606b7412117"), Loading @@ -127,14 +132,15 @@ impl BatteryService { } /// Handles all callback messages in a central location to avoid deadlocks. pub fn handle_callback(&mut self, callback: GattBatteryCallbacks) { match callback { GattBatteryCallbacks::OnClientRegistered(_status, client_id) => { pub fn handle_action(&mut self, action: BatteryServiceActions) { match action { BatteryServiceActions::OnClientRegistered(_status, client_id) => { debug!("GATT client registered for BAS with id {}", client_id); self.client_id = Some(client_id); } GattBatteryCallbacks::OnClientConnectionState(_status, _client_id, connected, addr) => { if !connected { BatteryServiceActions::OnClientConnectionState(status, _client_id, connected, addr) => { if !connected || status != GattStatus::Success { return; } let client_id = match self.client_id { Loading @@ -146,7 +152,7 @@ impl BatteryService { self.gatt.lock().unwrap().discover_services(client_id, addr); } GattBatteryCallbacks::OnSearchComplete(addr, services, status) => { BatteryServiceActions::OnSearchComplete(addr, services, status) => { if status != GattStatus::Success { debug!("GATT service discovery for {} failed with status {:?}", addr, status); return; Loading Loading @@ -204,7 +210,7 @@ impl BatteryService { } } GattBatteryCallbacks::OnCharacteristicRead(addr, status, _handle, value) => { BatteryServiceActions::OnCharacteristicRead(addr, status, _handle, value) => { if status != GattStatus::Success { return; } Loading @@ -214,23 +220,27 @@ impl BatteryService { }); } GattBatteryCallbacks::OnNotify(addr, _handle, value) => { BatteryServiceActions::OnNotify(addr, _handle, value) => { let battery_info = self.set_battery_info(&addr, &value); self.callbacks.for_all_callbacks(|callback| { callback.on_battery_info_updated(addr.clone(), battery_info.clone()); }); } } } /// Attempt to (re)establish connection to a device when it becomes connected. pub fn device_connected(&mut self, device: BluetoothDevice) { BatteryServiceActions::Connect(device) => { self.init_device(device.address); } BatteryServiceActions::Disconnect(device) => { self.drop_device(device.address); } } } fn set_battery_info(&mut self, remote_address: &String, value: &Vec<u8>) -> BatterySet { let level: Vec<_> = value.iter().cloned().chain(iter::repeat(0 as u8)).take(4).collect(); let level = u32::from_le_bytes(level.try_into().unwrap()); debug!("Received battery level for {}: {}", remote_address.clone(), level); let battery_set = self.battery_sets.entry(remote_address.clone()).or_insert_with(|| { BatterySet::new(remote_address.clone(), uuid::BAS.to_string(), "BAS".to_string()) }); Loading @@ -247,6 +257,7 @@ impl BatteryService { Some(id) => id, None => return, }; debug!("Attempting GATT connection to {}", remote_address.clone()); self.gatt.lock().unwrap().client_connect( client_id, remote_address, Loading @@ -257,6 +268,22 @@ impl BatteryService { ); } fn drop_device(&mut self, remote_address: String) { self.handles.remove(&remote_address); match self.client_id { Some(client_id) => { self.gatt.lock().unwrap().client_disconnect(client_id, remote_address.clone()) } None => return, } // Let BatteryProviderManager know that BAS no longer has a battery for this device. self.battery_provider_manager.lock().unwrap().set_battery_info( self.battery_provider_id, BatterySet::new(remote_address.clone(), uuid::BAS.to_string(), "BAS".to_string()), ); self.battery_sets.remove(&remote_address); } /// Perform an explicit read on all devices BAS knows about. pub fn refresh_all_devices(&self) { self.handles.keys().for_each(|device| { Loading Loading @@ -354,7 +381,7 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks(GattBatteryCallbacks::OnClientRegistered( .send(Message::BatteryService(BatteryServiceActions::OnClientRegistered( status, client_id, ))) .await; Loading @@ -371,11 +398,9 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks( GattBatteryCallbacks::OnClientConnectionState( .send(Message::BatteryService(BatteryServiceActions::OnClientConnectionState( status, client_id, connected, addr, ), )) ))) .await; }); } Loading @@ -389,7 +414,7 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks(GattBatteryCallbacks::OnSearchComplete( .send(Message::BatteryService(BatteryServiceActions::OnSearchComplete( addr, services, status, ))) .await; Loading @@ -406,7 +431,7 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks(GattBatteryCallbacks::OnCharacteristicRead( .send(Message::BatteryService(BatteryServiceActions::OnCharacteristicRead( addr, status, handle, value, ))) .await; Loading @@ -417,9 +442,7 @@ impl IBluetoothGattCallback for GattCallback { let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx .send(Message::BatteryServiceCallbacks(GattBatteryCallbacks::OnNotify( addr, handle, value, ))) .send(Message::BatteryService(BatteryServiceActions::OnNotify(addr, handle, value))) .await; }); } Loading
system/gd/rust/linux/stack/src/bluetooth.rs +31 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ use tokio::sync::mpsc::Sender; use tokio::task::JoinHandle; use tokio::time; use crate::battery_service::BatteryServiceActions; use crate::bluetooth_admin::BluetoothAdmin; use crate::bluetooth_media::{BluetoothMedia, IBluetoothMedia, MediaActions}; use crate::callbacks::Callbacks; Loading Loading @@ -1123,13 +1124,17 @@ impl BtifBluetoothCallbacks for Bluetooth { }); let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx.send(Message::OnDeviceConnected(device.clone())).await; let _ = tx.send(Message::OnAclConnected(device.clone())).await; }); } BtAclState::Disconnected => { self.connection_callbacks.for_all_callbacks(|callback| { callback.on_device_disconnected(device.clone()); }); let tx = self.tx.clone(); tokio::spawn(async move { let _ = tx.send(Message::OnAclDisconnected(device.clone())).await; }); } }; } Loading Loading @@ -1726,6 +1731,19 @@ impl IBluetooth for Bluetooth { .await; }); } Profile::Bas => { let tx = self.tx.clone(); let device_to_send = device.clone(); topstack::get_runtime().spawn(async move { let _ = tx .send(Message::BatteryService( BatteryServiceActions::Connect(device_to_send), )) .await; }); } // We don't connect most profiles _ => (), } Loading Loading @@ -1794,6 +1812,18 @@ impl IBluetooth for Bluetooth { }); } Profile::Bas => { let tx = self.tx.clone(); let device_to_send = device.clone(); topstack::get_runtime().spawn(async move { let _ = tx .send(Message::BatteryService( BatteryServiceActions::Disconnect(device_to_send), )) .await; }); } // We don't connect most profiles _ => (), } Loading
system/gd/rust/linux/stack/src/lib.rs +22 −9 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ use tokio::sync::mpsc::{Receiver, Sender}; use crate::battery_manager::{BatteryManager, BatterySet}; use crate::battery_provider_manager::BatteryProviderManager; use crate::battery_service::{BatteryService, GattBatteryCallbacks}; use crate::battery_service::{BatteryService, BatteryServiceActions}; use crate::bluetooth::{ dispatch_base_callbacks, dispatch_hid_host_callbacks, dispatch_sdp_callbacks, Bluetooth, BluetoothDevice, IBluetooth, Loading Loading @@ -81,9 +81,10 @@ pub enum Message { // Update list of found devices and remove old instances. DeviceFreshnessCheck, // Sent whenever a device connects. Follows IBluetooth's on_device_connected // callback but doesn't require depening on Bluetooth. OnDeviceConnected(BluetoothDevice), // Follows IBluetooth's on_device_(dis)connected callback but doesn't require depending on // Bluetooth. OnAclConnected(BluetoothDevice), OnAclDisconnected(BluetoothDevice), // Suspend related SuspendCallbackRegistered(u32), Loading @@ -104,7 +105,7 @@ pub enum Message { BatteryProviderManagerCallbackDisconnected(u32), BatteryProviderManagerBatteryUpdated(String, BatterySet), BatteryServiceCallbackDisconnected(u32), BatteryServiceCallbacks(GattBatteryCallbacks), BatteryService(BatteryServiceActions), BatteryServiceRefresh, BatteryManagerCallbackDisconnected(u32), Loading Loading @@ -237,8 +238,20 @@ impl Stack { // Any service needing an updated list of devices can have an // update method triggered from here rather than needing a // reference to Bluetooth. Message::OnDeviceConnected(device) => { battery_service.lock().unwrap().device_connected(device); Message::OnAclConnected(device) => { battery_service .lock() .unwrap() .handle_action(BatteryServiceActions::Connect(device)); } // For battery service, use this to clean up internal handles. GATT connection is // already dropped if ACL disconnect has occurred. Message::OnAclDisconnected(device) => { battery_service .lock() .unwrap() .handle_action(BatteryServiceActions::Disconnect(device)); } Message::SuspendCallbackRegistered(id) => { Loading Loading @@ -283,8 +296,8 @@ impl Stack { Message::BatteryServiceCallbackDisconnected(id) => { battery_service.lock().unwrap().remove_callback(id); } Message::BatteryServiceCallbacks(callback) => { battery_service.lock().unwrap().handle_callback(callback); Message::BatteryService(action) => { battery_service.lock().unwrap().handle_action(action); } Message::BatteryServiceRefresh => { battery_service.lock().unwrap().refresh_all_devices(); Loading
system/gd/rust/linux/stack/src/uuid.rs +2 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ lazy_static! { static ref SUPPORTED_PROFILES: HashSet<Profile> = [ Profile::A2dpSink, Profile::A2dpSource, Profile::Bas, Profile::Hsp, Profile::Hfp, Profile::Hid, Loading @@ -129,6 +130,7 @@ lazy_static! { (UuidHelper::from_string(A2DP_SINK).unwrap(), Profile::A2dpSink), (UuidHelper::from_string(A2DP_SOURCE).unwrap(), Profile::A2dpSource), (UuidHelper::from_string(ADV_AUDIO_DIST).unwrap(), Profile::AdvAudioDist), (UuidHelper::from_string(BAS).unwrap(), Profile::Bas), (UuidHelper::from_string(HSP).unwrap(), Profile::Hsp), (UuidHelper::from_string(HSP_AG).unwrap(), Profile::HspAg), (UuidHelper::from_string(HFP).unwrap(), Profile::Hfp), Loading