Skip to main content

sl4f_lib/bluetooth/
profile_server_facade.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::common_utils::common::macros::{fx_err_and_bail, with_line};
6use anyhow::Error;
7use fidl::endpoints::create_request_stream;
8use fidl_fuchsia_bluetooth::{ChannelMode, ChannelParameters};
9use fidl_fuchsia_bluetooth_bredr::{
10    Attribute, Channel, ConnectParameters, ConnectionReceiverRequest,
11    ConnectionReceiverRequestStream, DataElement, Information, L2capParameters,
12    ProfileAdvertiseRequest, ProfileDescriptor, ProfileMarker, ProfileProxy, ProfileSearchRequest,
13    ProtocolDescriptor, ProtocolIdentifier, SearchResultsRequest, SearchResultsRequestStream,
14    ServiceClassProfileIdentifier, ServiceDefinition,
15};
16use fuchsia_async as fasync;
17use fuchsia_bluetooth::types::{PeerId, Uuid};
18use fuchsia_component as component;
19use fuchsia_sync::RwLock;
20use futures::channel::oneshot;
21use futures::stream::StreamExt;
22use futures::{FutureExt, select};
23use log::*;
24use serde_json::value::Value;
25use std::collections::HashMap;
26
27#[derive(Debug)]
28struct ProfileServerFacadeInner {
29    /// The current Profile Server Proxy
30    profile_server_proxy: Option<ProfileProxy>,
31
32    /// Total count of services advertised so far.
33    advertisement_count: usize,
34
35    /// Services currently active on the Profile Server Proxy
36    advertisement_stoppers: HashMap<usize, oneshot::Sender<()>>,
37
38    // Holds the channel so the connection remains open.
39    l2cap_channel_holder: Option<Channel>,
40}
41
42/// Perform Profile Server operations.
43///
44/// Note this object is shared among all threads created by the server.
45#[derive(Debug)]
46pub struct ProfileServerFacade {
47    inner: RwLock<ProfileServerFacadeInner>,
48}
49
50impl ProfileServerFacade {
51    pub fn new() -> ProfileServerFacade {
52        ProfileServerFacade {
53            inner: RwLock::new(ProfileServerFacadeInner {
54                profile_server_proxy: None,
55                advertisement_count: 0,
56                advertisement_stoppers: HashMap::new(),
57                l2cap_channel_holder: None,
58            }),
59        }
60    }
61
62    /// Creates a Profile Server Proxy.
63    pub fn create_profile_server_proxy(&self) -> Result<ProfileProxy, Error> {
64        let tag = "ProfileServerFacade::create_profile_server_proxy";
65        match self.inner.read().profile_server_proxy.clone() {
66            Some(profile_server_proxy) => {
67                info!(
68                    tag = &with_line!(tag);
69                    "Current profile server proxy: {:?}", profile_server_proxy
70                );
71                Ok(profile_server_proxy)
72            }
73            None => {
74                info!(tag = &with_line!(tag); "Setting new profile server proxy");
75                let profile_server_proxy =
76                    component::client::connect_to_protocol::<ProfileMarker>();
77                if let Err(err) = profile_server_proxy {
78                    fx_err_and_bail!(
79                        &with_line!(tag),
80                        format_err!("Failed to create profile server proxy: {}", err)
81                    );
82                }
83                profile_server_proxy
84            }
85        }
86    }
87
88    /// Initialize the ProfileServer proxy.
89    pub async fn init_profile_server_proxy(&self) -> Result<(), Error> {
90        self.inner.write().profile_server_proxy = Some(self.create_profile_server_proxy()?);
91        Ok(())
92    }
93
94    /// Returns a list of String UUIDs from a Serde JSON list of Values.
95    ///
96    /// # Arguments
97    /// * `uuid_list` - A serde json list of Values to parse.
98    ///  Example input:
99    /// 'uuid_list': ["00000001-0000-1000-8000-00805F9B34FB"]
100    pub fn generate_service_class_uuids(&self, uuid_list: &Vec<Value>) -> Result<Vec<Uuid>, Error> {
101        let tag = "ProfileServerFacade::generate_service_class_uuids";
102        let mut service_class_uuid_list = Vec::new();
103        for raw_uuid in uuid_list {
104            let uuid = if let Some(u) = raw_uuid.as_str() {
105                u
106            } else {
107                fx_err_and_bail!(
108                    &with_line!(tag),
109                    format_err!("Unable to convert Value to String.")
110                )
111            };
112            let uuid: Uuid = match uuid.parse() {
113                Ok(uuid) => uuid,
114                Err(e) => {
115                    fx_err_and_bail!(
116                        &with_line!(tag),
117                        format_err!("Unable to convert to Uuid: {:?}", e)
118                    );
119                }
120            };
121            service_class_uuid_list.push(uuid);
122        }
123        Ok(service_class_uuid_list)
124    }
125
126    /// Returns a list of ProtocolDescriptors from a Serde JSON input.
127    ///
128    /// Defined Protocol Identifiers for the Protocol Descriptor
129    /// We intentionally omit deprecated profile identifiers.
130    /// From Bluetooth Assigned Numbers:
131    /// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
132    ///
133    /// # Arguments
134    /// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
135    ///     to set up. Example:
136    ///  'protocol_descriptors': [
137    ///      {
138    ///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
139    ///          'params': [
140    ///              {
141    ///                 'data': 0x0103  # to indicate 1.3
142    ///              },
143    ///              {
144    ///                  'data': 0x0105  # to indicate 1.5
145    ///              }
146    ///          ]
147    ///      },
148    ///      {
149    ///          'protocol': 1,  # u64 Representation of ProtocolIdentifier::SDP
150    ///          'params': [{
151    ///              'data': 0x0019
152    ///          }]
153    ///      }
154    ///  ]
155    pub fn generate_protocol_descriptors(
156        &self,
157        protocol_descriptors: &Vec<Value>,
158    ) -> Result<Vec<ProtocolDescriptor>, Error> {
159        let tag = "ProfileServerFacade::generate_protocol_descriptors";
160        let mut protocol_descriptor_list = Vec::new();
161
162        for raw_protocol_descriptor in protocol_descriptors {
163            let protocol = match raw_protocol_descriptor["protocol"].as_u64() {
164                Some(p) => match p as u16 {
165                    1 => ProtocolIdentifier::Sdp,
166                    3 => ProtocolIdentifier::Rfcomm,
167                    7 => ProtocolIdentifier::Att,
168                    8 => ProtocolIdentifier::Obex,
169                    15 => ProtocolIdentifier::Bnep,
170                    17 => ProtocolIdentifier::Hidp,
171                    18 => ProtocolIdentifier::HardcopyControlChannel,
172                    20 => ProtocolIdentifier::HardcopyDataChannel,
173                    22 => ProtocolIdentifier::HardcopyNotification,
174                    23 => ProtocolIdentifier::Avctp,
175                    25 => ProtocolIdentifier::Avdtp,
176                    30 => ProtocolIdentifier::McapControlChannel,
177                    31 => ProtocolIdentifier::McapDataChannel,
178                    256 => ProtocolIdentifier::L2Cap,
179                    _ => fx_err_and_bail!(
180                        &with_line!(tag),
181                        format!("Input protocol does not match supported protocols: {}", p)
182                    ),
183                },
184                None => fx_err_and_bail!(&with_line!(tag), "Value 'protocol' not found."),
185            };
186
187            let raw_params = if let Some(p) = raw_protocol_descriptor["params"].as_array() {
188                p
189            } else {
190                fx_err_and_bail!(&with_line!(tag), "Value 'params' not found or invalid type.")
191            };
192
193            let mut params = Vec::new();
194            for param in raw_params {
195                let data = if let Some(d) = param["data"].as_u64() {
196                    d as u16
197                } else {
198                    fx_err_and_bail!(&with_line!(tag), "Value 'data' not found or invalid type.")
199                };
200
201                params.push(DataElement::Uint16(data as u16));
202            }
203
204            protocol_descriptor_list.push(ProtocolDescriptor {
205                protocol: Some(protocol),
206                params: Some(params),
207                ..Default::default()
208            });
209        }
210        Ok(protocol_descriptor_list)
211    }
212
213    /// Returns a list of ProfileDescriptors from a Serde JSON input.
214    ///
215    /// Identifiers that are valid for Bluetooth Classes / Profiles
216    /// We intentionally omit classes and profile IDs that are unsupported, deprecated,
217    /// or reserved for use by Fuchsia Bluetooth.
218    /// From Bluetooth Assigned Numbers for SDP
219    /// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
220    ///
221    /// # Arguments
222    /// * `profile_descriptors`: A Json Representation of the ProtocolDescriptors.
223    /// Example:
224    ///  'profile_descriptors': [{
225    ///      'profile_id': 0x110D, # Represents ServiceClassProfileIdentifier::AdvancedAudioDistribution
226    ///      'major_version': 1, # u64 representation of the major_version.
227    ///      'minor_version': 3, # u64 representation of the minor_version.
228    ///  }],
229    pub fn generate_profile_descriptors(
230        &self,
231        profile_descriptors: &Vec<Value>,
232    ) -> Result<Vec<ProfileDescriptor>, Error> {
233        let tag = "ProfileServerFacade::generate_profile_descriptors";
234        let mut profile_descriptor_list = Vec::new();
235        for raw_profile_descriptor in profile_descriptors.iter() {
236            let profile_id = if let Some(r) = raw_profile_descriptor.get("profile_id") {
237                match self.get_service_class_profile_identifier_from_id(r) {
238                    Ok(id) => id,
239                    Err(e) => fx_err_and_bail!(&with_line!(tag), e),
240                }
241            } else {
242                let log_err = "Invalid SDP search input. Missing 'profile_id'";
243                fx_err_and_bail!(&with_line!(tag), log_err)
244            };
245
246            let minor_version = if let Some(num) = raw_profile_descriptor["minor_version"].as_u64()
247            {
248                num as u8
249            } else {
250                let log_err = "Type of 'minor_version' incorrect or incorrect type.";
251                fx_err_and_bail!(&with_line!(tag), log_err)
252            };
253
254            let major_version = if let Some(num) = raw_profile_descriptor["major_version"].as_u64()
255            {
256                num as u8
257            } else {
258                let log_err = "Type of 'major_version' incorrect or incorrect type.";
259                fx_err_and_bail!(&with_line!(tag), log_err)
260            };
261
262            profile_descriptor_list.push(ProfileDescriptor {
263                profile_id: Some(profile_id),
264                minor_version: Some(minor_version),
265                major_version: Some(major_version),
266                ..Default::default()
267            });
268        }
269        Ok(profile_descriptor_list)
270    }
271
272    /// Returns a list of Information objects from a Serde JSON input.
273    ///
274    /// # Arguments
275    /// * `information_list`: A Json Representation of the Information objects.
276    ///  Example:
277    ///  'information_list': [{
278    ///      'language': "en",
279    ///      'name': "A2DP",
280    ///      'description': "Advanced Audio Distribution Profile",
281    ///      'provider': "Fuchsia"
282    ///  }],
283    pub fn generate_information(
284        &self,
285        information_list: &Vec<Value>,
286    ) -> Result<Vec<Information>, Error> {
287        let tag = "ProfileServerFacade::generate_information";
288        let mut info_list = Vec::new();
289        for raw_information in information_list {
290            let language = if let Some(v) = raw_information["language"].as_str() {
291                Some(v.to_string())
292            } else {
293                let log_err = "Type of 'language' incorrect of invalid type.";
294                fx_err_and_bail!(&with_line!(tag), log_err)
295            };
296
297            let name = if let Some(v) = raw_information["name"].as_str() {
298                Some(v.to_string())
299            } else {
300                None
301            };
302
303            let description = if let Some(v) = raw_information["description"].as_str() {
304                Some(v.to_string())
305            } else {
306                None
307            };
308
309            let provider = if let Some(v) = raw_information["provider"].as_str() {
310                Some(v.to_string())
311            } else {
312                None
313            };
314
315            info_list.push(Information {
316                language,
317                name,
318                description,
319                provider,
320                ..Default::default()
321            });
322        }
323        Ok(info_list)
324    }
325
326    /// Returns a list of Attributes from a Serde JSON input.
327    ///
328    /// # Arguments
329    /// * `additional_attributes_list`: A Json Representation of the Attribute objects.
330    ///  Example:
331    ///    'additional_attributes': [{
332    ///         'id': 201,
333    ///         'element': {
334    ///             'data': int(sig_uuid_constants['AVDTP'], 16)
335    ///         }
336    ///    }]
337    pub fn generate_additional_attributes(
338        &self,
339        additional_attributes_list: &Vec<Value>,
340    ) -> Result<Vec<Attribute>, Error> {
341        let tag = "ProfileServerFacade::generate_additional_attributes";
342        let mut attribute_list = Vec::new();
343        for raw_attribute in additional_attributes_list {
344            let id = if let Some(v) = raw_attribute["id"].as_u64() {
345                v as u16
346            } else {
347                let log_err = "Type of 'id' incorrect or invalid type.";
348                fx_err_and_bail!(&with_line!(tag), log_err)
349            };
350
351            let raw_element = if let Some(e) = raw_attribute.get("element") {
352                e
353            } else {
354                let log_err = "Type of 'element' incorrect.";
355                fx_err_and_bail!(&with_line!(tag), log_err)
356            };
357
358            let data_element = if let Some(d) = raw_element["data"].as_u64() {
359                DataElement::Uint8(d as u8)
360            } else {
361                fx_err_and_bail!(&with_line!(tag), "Value 'data' not found.")
362            };
363
364            attribute_list.push(Attribute {
365                id: Some(id),
366                element: Some(data_element),
367                ..Default::default()
368            })
369        }
370        Ok(attribute_list)
371    }
372
373    /// Monitor the connection request stream, printing outputs when connections happen.
374    pub async fn monitor_connection_receiver(
375        mut requests: ConnectionReceiverRequestStream,
376        end_signal: oneshot::Receiver<()>,
377    ) -> Result<(), Error> {
378        let tag = "ProfileServerFacade::monitor_connection_receiver";
379        let mut fused_end_signal = end_signal.fuse();
380        loop {
381            select! {
382                _ = fused_end_signal => {
383                    info!("Ending advertisement on signal..");
384                    return Ok(());
385                },
386                request = requests.next() => {
387                    let request = match request {
388                        None => {
389                            let log_err = format_err!("Connection request stream ended");
390                            fx_err_and_bail!(&with_line!(tag), log_err)
391                        }
392                        Some(Err(e)) => {
393                            let log_err = format_err!("Error during connection request: {}", e);
394                            fx_err_and_bail!(&with_line!(tag), log_err)
395                        },
396                        Some(Ok(r)) => r,
397                    };
398                    let ConnectionReceiverRequest::Connected { peer_id, channel, .. } = request else {
399                        fx_err_and_bail!(&with_line!(tag), "unknown method")
400                    };
401                    let peer_id: PeerId = peer_id.into();
402                    info!(
403                        tag = &with_line!(tag);
404                        "Connection from {}: {:?}!",
405                        peer_id,
406                        channel
407                    );
408                }
409            }
410        }
411    }
412
413    /// Monitor the search results stream, printing logs when results are produced.
414    pub async fn monitor_search_results(
415        mut requests: SearchResultsRequestStream,
416    ) -> Result<(), Error> {
417        let tag = "ProfileServerFacade::monitor_search_results";
418        while let Some(request) = requests.next().await {
419            let request = match request {
420                Err(e) => {
421                    let log_err = format_err!("Error during search results request: {}", e);
422                    fx_err_and_bail!(&with_line!(tag), log_err)
423                }
424                Ok(r) => r,
425            };
426            let SearchResultsRequest::ServiceFound { peer_id, protocol, attributes, responder } =
427                request
428            else {
429                fx_err_and_bail!(&with_line!(tag), "unknown method")
430            };
431            let peer_id: PeerId = peer_id.into();
432            info!(
433                tag = &with_line!(tag);
434                "Search Result: Peer {} with protocol {:?}: {:?}", peer_id, protocol, attributes
435            );
436            responder.send()?;
437        }
438        let log_err = format_err!("Search result request stream ended");
439        fx_err_and_bail!(&with_line!(tag), log_err)
440    }
441
442    /// Adds a service record based on a JSON dictrionary.
443    ///
444    /// # Arguments:
445    /// * `args` : A Json object representing the service to add:
446    ///Example Python dictionary pre JSON conversion
447    ///args:
448    ///{
449    ///    'service_class_uuids': ["0001"],
450    ///    'protocol_descriptors': [
451    ///        {
452    ///            'protocol':
453    ///            int(sig_uuid_constants['AVDTP'], 16),
454    ///            'params': [
455    ///                {
456    ///                    'data': 0x0103
457    ///                }
458    ///            ]
459    ///        },
460    ///        {
461    ///            'protocol': int(sig_uuid_constants['SDP'], 16),
462    ///            'params': [{
463    ///                'data': int(sig_uuid_constants['AVDTP'], 16),
464    ///            }]
465    ///        }
466    ///    ],
467    ///    'profile_descriptors': [{
468    ///        'profile_id': int(sig_uuid_constants['AdvancedAudioDistribution'], 16),
469    ///        'major_version': 1,
470    ///        'minor_version': 3,
471    ///    }],
472    ///    'additional_protocol_descriptors': [{
473    ///        'protocol': int(sig_uuid_constants['L2CAP'], 16),
474    ///        'params': [{
475    ///            'data': int(sig_uuid_constants['AVDTP'], 16),
476    ///        }]
477    ///    }],
478    ///    'information': [{
479    ///        'language': "en",
480    ///        'name': "A2DP",
481    ///        'description': "Advanced Audio Distribution Profile",
482    ///        'provider': "Fuchsia"
483    ///    }],
484    ///    'additional_attributes': [{
485    ///         'id': 201,
486    ///         'element': {
487    ///             'data': int(sig_uuid_constants['AVDTP'], 16)
488    ///         }
489    ///    }]
490    ///}
491    pub async fn add_service(&self, args: Value) -> Result<usize, Error> {
492        let tag = "ProfileServerFacade::write_sdp_record";
493        info!(tag = &with_line!(tag); "Writing SDP record");
494
495        let record_description = if let Some(r) = args.get("record") {
496            r
497        } else {
498            let log_err = "Invalid SDP record input. Missing 'record'";
499            fx_err_and_bail!(&with_line!(tag), log_err)
500        };
501
502        let service_class_uuids = if let Some(v) = record_description.get("service_class_uuids") {
503            if let Some(r) = v.as_array() {
504                self.generate_service_class_uuids(r)?
505            } else {
506                let log_err = "Invalid type for service_class_uuids in record input.";
507                fx_err_and_bail!(&with_line!(tag), log_err)
508            }
509        } else {
510            let log_err = "Invalid SDP record input. Missing 'service_class_uuids'";
511            fx_err_and_bail!(&with_line!(tag), log_err)
512        };
513
514        let protocol_descriptors = if let Some(v) = record_description.get("protocol_descriptors") {
515            if let Some(r) = v.as_array() {
516                self.generate_protocol_descriptors(r)?
517            } else {
518                let log_err = "Invalid type for protocol_descriptors in record input.";
519                fx_err_and_bail!(&with_line!(tag), log_err)
520            }
521        } else {
522            let log_err = "Invalid SDP record input. Missing 'protocol_descriptors'";
523            fx_err_and_bail!(&with_line!(tag), log_err)
524        };
525
526        let profile_descriptors = if let Some(v) = record_description.get("profile_descriptors") {
527            if let Some(r) = v.as_array() {
528                self.generate_profile_descriptors(r)?
529            } else {
530                let log_err = "Invalid type for profile_descriptors in record input.";
531                fx_err_and_bail!(&with_line!(tag), log_err)
532            }
533        } else {
534            let log_err = "Invalid SDP record input. Missing 'profile_descriptors'";
535            fx_err_and_bail!(&with_line!(tag), log_err)
536        };
537
538        let raw_additional_protocol_descriptors = if let Some(v) =
539            record_description.get("additional_protocol_descriptors")
540        {
541            if let Some(arr) = v.as_array() {
542                Some(self.generate_protocol_descriptors(arr)?)
543            } else if v.is_null() {
544                None
545            } else {
546                let log_err =
547                    "Invalid type for 'additional_protocol_descriptors'. Expected null or array.";
548                fx_err_and_bail!(&with_line!(tag), log_err)
549            }
550        } else {
551            let log_err = "Invalid SDP record input. Missing 'additional_protocol_descriptors'";
552            fx_err_and_bail!(&with_line!(tag), log_err)
553        };
554
555        let information = if let Some(v) = record_description.get("information") {
556            if let Some(r) = v.as_array() {
557                self.generate_information(r)?
558            } else {
559                let log_err = "Invalid type for information in record input.";
560                fx_err_and_bail!(&with_line!(tag), log_err)
561            }
562        } else {
563            let log_err = "Invalid SDP record input. Missing 'information'";
564            fx_err_and_bail!(&with_line!(tag), log_err)
565        };
566
567        let additional_attributes = if let Some(v) = record_description.get("additional_attributes")
568        {
569            if let Some(r) = v.as_array() {
570                Some(self.generate_additional_attributes(r)?)
571            } else {
572                None
573            }
574        } else {
575            let log_err = "Invalid SDP record input. Missing 'additional_attributes'";
576            fx_err_and_bail!(&with_line!(tag), log_err)
577        };
578
579        let service_defs = vec![ServiceDefinition {
580            service_class_uuids: Some(service_class_uuids.into_iter().map(Into::into).collect()),
581            protocol_descriptor_list: Some(protocol_descriptors),
582            profile_descriptors: Some(profile_descriptors),
583            additional_protocol_descriptor_lists: match raw_additional_protocol_descriptors {
584                Some(d) => Some(vec![d]),
585                None => None,
586            },
587            information: Some(information),
588            additional_attributes,
589            ..Default::default()
590        }];
591
592        let (connect_client, connect_requests) = create_request_stream();
593
594        match &self.inner.read().profile_server_proxy {
595            Some(server) => {
596                let _ = server.advertise(ProfileAdvertiseRequest {
597                    services: Some(service_defs),
598                    receiver: Some(connect_client),
599                    ..Default::default()
600                });
601            }
602            None => fx_err_and_bail!(&with_line!(tag), "No Server Proxy created."),
603        };
604
605        let (end_ad_sender, end_ad_receiver) = oneshot::channel::<()>();
606        let request_handler_fut =
607            Self::monitor_connection_receiver(connect_requests, end_ad_receiver);
608        fasync::Task::spawn(async move {
609            if let Err(err) = request_handler_fut.await {
610                error!(err:?; "Connection receiver handler ended with error");
611            }
612        })
613        .detach();
614
615        let next = self.inner.write().advertisement_count + 1;
616        self.inner.write().advertisement_stoppers.insert(next, end_ad_sender);
617        self.inner.write().advertisement_count = next;
618        Ok(next)
619    }
620
621    /// Removes a remote service by id.
622    ///
623    /// # Arguments:
624    /// * `service_id`: The service id to remove.
625    pub async fn remove_service(&self, service_id: usize) -> Result<(), Error> {
626        let tag = "ProfileServerFacade::remove_service";
627        match self.inner.write().advertisement_stoppers.remove(&service_id) {
628            Some(_) => Ok(()),
629            None => fx_err_and_bail!(&with_line!(tag), "Service ID not found"),
630        }
631    }
632
633    pub fn get_service_class_profile_identifier_from_id(
634        &self,
635        raw_profile_id: &Value,
636    ) -> Result<ServiceClassProfileIdentifier, Error> {
637        let tag = "ProfileServerFacade::get_service_class_profile_identifier_from_id";
638        match raw_profile_id.as_u64().map(u16::try_from) {
639            Some(Ok(id)) => match ServiceClassProfileIdentifier::from_primitive(id) {
640                Some(id) => return Ok(id),
641                None => {
642                    let log_err = format!("UUID {} not supported by profile server.", id);
643                    fx_err_and_bail!(&with_line!(tag), log_err)
644                }
645            },
646            _ => fx_err_and_bail!(&with_line!(tag), "Type of raw_profile_id incorrect."),
647        };
648    }
649
650    pub async fn add_search(&self, args: Value) -> Result<(), Error> {
651        let tag = "ProfileServerFacade::add_search";
652        info!(tag = &with_line!(tag); "Adding Search");
653
654        let raw_attribute_list = if let Some(v) = args.get("attribute_list") {
655            if let Some(r) = v.as_array() {
656                r
657            } else {
658                let log_err = "Expected 'attribute_list' as an array.";
659                fx_err_and_bail!(&with_line!(tag), log_err)
660            }
661        } else {
662            let log_err = "Invalid SDP search input. Missing 'attribute_list'";
663            fx_err_and_bail!(&with_line!(tag), log_err)
664        };
665
666        let mut attribute_list = Vec::new();
667        for item in raw_attribute_list {
668            match item.as_u64() {
669                Some(v) => attribute_list.push(v as u16),
670                None => fx_err_and_bail!(
671                    &with_line!(tag),
672                    "Failed to convert value in attribute_list to u16."
673                ),
674            };
675        }
676
677        let profile_id = if let Some(r) = args.get("profile_id") {
678            self.get_service_class_profile_identifier_from_id(r)?
679        } else {
680            let log_err = "Invalid SDP search input. Missing 'profile_id'";
681            fx_err_and_bail!(&with_line!(tag), log_err)
682        };
683
684        let (search_client, result_requests) = create_request_stream();
685
686        match &self.inner.read().profile_server_proxy {
687            Some(server) => server.search(ProfileSearchRequest {
688                service_uuid: Some(profile_id),
689                attr_ids: Some(attribute_list),
690                results: Some(search_client),
691                ..Default::default()
692            })?,
693            None => fx_err_and_bail!(&with_line!(tag), "No Server Proxy created."),
694        };
695
696        let search_fut = Self::monitor_search_results(result_requests);
697        fasync::Task::spawn(async move {
698            if let Err(err) = search_fut.await {
699                error!(err:?; "Search result handler ended with error");
700            }
701        })
702        .detach();
703
704        Ok(())
705    }
706
707    /// Sends an outgoing l2cap connection request
708    ///
709    /// # Arguments:
710    /// * `id`: String - The peer id to connect to.
711    /// * `psm`: u16 - The PSM value to connect to:
712    ///     Valid PSM values: https://www.bluetooth.com/specifications/assigned-numbers/logical-link-control/
713    /// * `mode`: String - The channel mode to connect over
714    ///     Available Values: BASIC, ERTM
715    pub async fn connect(&self, id: String, psm: u16, mode: &str) -> Result<(), Error> {
716        let tag = "ProfileServerFacade::connect";
717        let peer_id: PeerId = match id.parse() {
718            Ok(id) => id,
719            Err(_) => {
720                fx_err_and_bail!(
721                    &with_line!(tag),
722                    "Failed to convert value in attribute_list to u16."
723                );
724            }
725        };
726
727        let mode = match mode {
728            "BASIC" => ChannelMode::Basic,
729            "ERTM" => ChannelMode::EnhancedRetransmission,
730            _ => fx_err_and_bail!(&with_line!(tag), format!("Invalid mode: {:?}.", mode)),
731        };
732
733        let proxy_opt = self.inner.read().profile_server_proxy.clone();
734
735        let connection_result = match proxy_opt {
736            Some(server) => {
737                let l2cap_params = L2capParameters {
738                    psm: Some(psm),
739                    parameters: Some(ChannelParameters {
740                        channel_mode: Some(mode),
741                        ..Default::default()
742                    }),
743                    ..Default::default()
744                };
745                server.connect(&peer_id.into(), &ConnectParameters::L2cap(l2cap_params)).await?
746            }
747            None => fx_err_and_bail!(&with_line!(tag), "No Server Proxy created."),
748        };
749
750        match connection_result {
751            Ok(r) => self.inner.write().l2cap_channel_holder = Some(r),
752            Err(e) => {
753                fx_err_and_bail!(&with_line!(tag), format!("Failed to connect with error: {:?}", e))
754            }
755        };
756
757        Ok(())
758    }
759
760    /// Cleanup any Profile Server related objects.
761    pub async fn cleanup(&self) -> Result<(), Error> {
762        // Dropping these will signal the other end with an Err, which is enough.
763        self.inner.write().advertisement_stoppers.clear();
764        self.inner.write().advertisement_count = 0;
765        self.inner.write().l2cap_channel_holder = None;
766        self.inner.write().profile_server_proxy = None;
767        Ok(())
768    }
769}