Skip to main content

sl4f_lib/bluetooth/
gatt_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 anyhow::{Error, format_err};
6use fidl::prelude::*;
7use fidl_fuchsia_bluetooth_gatt2::{
8    self as gatt, AttributePermissions, Characteristic, CharacteristicPropertyBits, Descriptor,
9    Handle, LocalServiceControlHandle, LocalServiceMarker, LocalServiceReadValueResponder,
10    LocalServiceRequest, LocalServiceRequestStream, LocalServiceWriteValueResponder,
11    SecurityRequirements, Server_Marker, Server_Proxy, ServiceHandle, ServiceInfo, ServiceKind,
12    ValueChangedParameters,
13};
14use fuchsia_async as fasync;
15use fuchsia_bluetooth::types::{PeerId, Uuid};
16use fuchsia_component as app;
17use fuchsia_sync::RwLock;
18use futures::stream::TryStreamExt;
19use log::{error, info, warn};
20use serde_json::value::Value;
21use std::collections::HashMap;
22use std::str::FromStr;
23
24use crate::bluetooth::constants::{
25    CHARACTERISTIC_EXTENDED_PROPERTIES_UUID, GATT_MAX_ATTRIBUTE_VALUE_LENGTH,
26    PERMISSION_READ_ENCRYPTED, PERMISSION_READ_ENCRYPTED_MITM, PERMISSION_WRITE_ENCRYPTED,
27    PERMISSION_WRITE_ENCRYPTED_MITM, PERMISSION_WRITE_SIGNED, PERMISSION_WRITE_SIGNED_MITM,
28    PROPERTY_INDICATE, PROPERTY_NOTIFY, PROPERTY_READ, PROPERTY_WRITE,
29};
30
31#[derive(Debug)]
32struct Counter {
33    count: u64,
34}
35
36impl Counter {
37    pub fn new() -> Counter {
38        Counter { count: 0 }
39    }
40
41    fn next(&mut self) -> u64 {
42        let id: u64 = self.count;
43        self.count += 1;
44        id
45    }
46}
47
48#[derive(Debug)]
49struct InnerGattServerFacade {
50    /// attribute_value_mapping: A Hashmap that will be used for capturing
51    /// and updating Characteristic and Descriptor values for each service.
52    /// The bool value represents whether value size of the initial Characteristic
53    /// Descriptor value should be enforced or not for prepared writes. True
54    /// for enforce, false to allow the size to grow to max values.
55    attribute_value_mapping: HashMap<u64, (Vec<u8>, bool)>,
56
57    /// A generic counter GATT server attributes
58    generic_id_counter: Counter,
59
60    /// The current Gatt Server Proxy
61    server_proxy: Option<Server_Proxy>,
62
63    /// List of active LocalService server tasks.
64    service_tasks: Vec<fasync::Task<()>>,
65}
66
67/// Perform Gatt Server operations.
68///
69/// Note this object is shared among all threads created by server.
70///
71#[derive(Debug)]
72pub struct GattServerFacade {
73    inner: RwLock<InnerGattServerFacade>,
74}
75
76impl GattServerFacade {
77    pub fn new() -> GattServerFacade {
78        GattServerFacade {
79            inner: RwLock::new(InnerGattServerFacade {
80                attribute_value_mapping: HashMap::new(),
81                generic_id_counter: Counter::new(),
82                server_proxy: None,
83                service_tasks: vec![],
84            }),
85        }
86    }
87
88    fn create_server_proxy(&self) -> Result<Server_Proxy, Error> {
89        let tag = "GattServerFacade::create_server_proxy:";
90        match self.inner.read().server_proxy.clone() {
91            Some(service) => {
92                info!(
93                    tag = &[tag, &line!().to_string()].join("").as_str();
94                    "Current service proxy: {:?}", service
95                );
96                Ok(service)
97            }
98            None => {
99                info!(
100                    tag = &[tag, &line!().to_string()].join("").as_str();
101                    "Setting new server proxy"
102                );
103                let service = app::client::connect_to_protocol::<Server_Marker>();
104                if let Err(err) = service {
105                    error!(
106                        tag = &[tag, &line!().to_string()].join("").as_str(),
107                        err:?;
108                        "Failed to create server proxy"
109                    );
110                    return Err(format_err!("Failed to create server proxy: {:?}", err));
111                }
112                service
113            }
114        }
115    }
116
117    /// Function to take the input attribute value and parse it to
118    /// a byte array. Types can be Strings, u8, or generic Array.
119    fn parse_attribute_value_to_byte_array(&self, value_to_parse: &Value) -> Vec<u8> {
120        match value_to_parse {
121            Value::String(obj) => String::from(obj.as_str()).into_bytes(),
122            Value::Number(obj) => match obj.as_u64() {
123                Some(num) => vec![num as u8],
124                None => vec![],
125            },
126            Value::Array(obj) => obj.iter().filter_map(|v| v.as_u64()).map(|v| v as u8).collect(),
127            _ => vec![],
128        }
129    }
130
131    fn on_characteristic_configuration(
132        peer_id: PeerId,
133        handle: Handle,
134        notify: bool,
135        indicate: bool,
136        control_handle: &LocalServiceControlHandle,
137    ) {
138        let tag = "GattServerFacade::on_characteristic_configuration:";
139        info!(
140            tag = &[tag, &line!().to_string()].join("").as_str(),
141            notify:%,
142            indicate:%,
143            id:% = peer_id;
144            "OnCharacteristicConfiguration"
145        );
146
147        if indicate {
148            let value = ValueChangedParameters {
149                handle: Some(handle),
150                value: Some(vec![0x02, 0x00]),
151                peer_ids: Some(vec![peer_id.into()]),
152                ..Default::default()
153            };
154            // Ignore the confirmation.
155            let (confirmation, _) = fidl::EventPair::create();
156            let _ = control_handle.send_on_indicate_value(&value, confirmation);
157        } else if notify {
158            let value = ValueChangedParameters {
159                handle: Some(handle),
160                value: Some(vec![0x01, 0x00]),
161                peer_ids: Some(vec![peer_id.into()]),
162                ..Default::default()
163            };
164            let _ = control_handle.send_on_notify_value(&value);
165        }
166    }
167
168    fn on_read_value(
169        peer_id: PeerId,
170        handle: Handle,
171        offset: i32,
172        responder: LocalServiceReadValueResponder,
173        value_in_mapping: Option<&(Vec<u8>, bool)>,
174    ) {
175        let tag = "GattServerFacade::on_read_value:";
176        info!(
177            tag = &[tag, &line!().to_string()].join("").as_str(),
178            at_id:? = handle.value,
179            offset:? = offset,
180            id:% = peer_id;
181            "OnReadValue request",
182        );
183        match value_in_mapping {
184            Some(v) => {
185                let (value, _enforce_initial_attribute_length) = v;
186                if value.len() < offset as usize {
187                    let _result = responder.send(Err(gatt::Error::InvalidOffset));
188                } else {
189                    let _result = responder.send(Ok(&value[offset as usize..]));
190                }
191            }
192            None => {
193                // ID doesn't exist in the database
194                let _result = responder.send(Err(gatt::Error::ReadNotPermitted));
195            }
196        };
197    }
198
199    fn write_and_extend(value: &mut Vec<u8>, value_to_write: Vec<u8>, offset: usize) {
200        let split_idx = (value.len() - offset).min(value_to_write.len());
201        let (overlapping, extending) = value_to_write.split_at(split_idx);
202        let end_of_overlap = offset + overlapping.len();
203        value.splice(offset..end_of_overlap, overlapping.iter().cloned());
204        value.extend_from_slice(extending);
205    }
206
207    fn on_write_value(
208        peer_id: PeerId,
209        handle: Handle,
210        offset: u32,
211        value_to_write: Vec<u8>,
212        responder: LocalServiceWriteValueResponder,
213        value_in_mapping: Option<&mut (Vec<u8>, bool)>,
214    ) {
215        let tag = "GattServerFacade::on_write_value:";
216        info!(
217            tag = &[tag, &line!().to_string()].join("").as_str(),
218            at_id = handle.value,
219            offset = offset,
220            value:? = value_to_write,
221            id:% = peer_id;
222            "OnWriteValue request",
223        );
224
225        match value_in_mapping {
226            Some(v) => {
227                let (value, enforce_initial_attribute_length) = v;
228                let max_attribute_size: usize = match enforce_initial_attribute_length {
229                    true => value.len(),
230                    false => GATT_MAX_ATTRIBUTE_VALUE_LENGTH,
231                };
232                if max_attribute_size < (value_to_write.len() + offset as usize) {
233                    let _result = responder.send(Err(gatt::Error::InvalidAttributeValueLength));
234                } else if value.len() < offset as usize {
235                    let _result = responder.send(Err(gatt::Error::InvalidOffset));
236                } else {
237                    GattServerFacade::write_and_extend(value, value_to_write, offset as usize);
238                    let _result = responder.send(Ok(()));
239                }
240            }
241            None => {
242                // ID doesn't exist in the database
243                let _result = responder.send(Err(gatt::Error::WriteNotPermitted));
244            }
245        }
246    }
247
248    async fn monitor_service_request_stream(
249        stream: LocalServiceRequestStream,
250        control_handle: LocalServiceControlHandle,
251        mut attribute_value_mapping: HashMap<u64, (Vec<u8>, bool)>,
252    ) -> Result<(), Error> {
253        stream
254            .map_ok(move |request| match request {
255                LocalServiceRequest::CharacteristicConfiguration {
256                    peer_id,
257                    handle,
258                    notify,
259                    indicate,
260                    responder,
261                } => {
262                    GattServerFacade::on_characteristic_configuration(
263                        peer_id.into(),
264                        handle,
265                        notify,
266                        indicate,
267                        &control_handle,
268                    );
269                    let _ = responder.send();
270                }
271                LocalServiceRequest::ReadValue { peer_id, handle, offset, responder } => {
272                    GattServerFacade::on_read_value(
273                        peer_id.into(),
274                        handle,
275                        offset,
276                        responder,
277                        attribute_value_mapping.get(&handle.value),
278                    );
279                }
280                LocalServiceRequest::WriteValue { payload, responder } => {
281                    GattServerFacade::on_write_value(
282                        payload.peer_id.unwrap().into(),
283                        payload.handle.unwrap(),
284                        payload.offset.unwrap(),
285                        payload.value.unwrap(),
286                        responder,
287                        attribute_value_mapping.get_mut(&payload.handle.unwrap().value),
288                    );
289                }
290                LocalServiceRequest::PeerUpdate { payload: _, responder } => {
291                    responder.drop_without_shutdown();
292                }
293                LocalServiceRequest::ValueChangedCredit { .. } => {}
294            })
295            .try_collect::<()>()
296            .await
297            .map_err(|e| e.into())
298    }
299
300    /// Convert a number representing permissions into AttributePermissions.
301    ///
302    /// Fuchsia GATT Server uses a u32 as a property value and an AttributePermissions
303    /// object to represent Characteristic and Descriptor permissions. In order to
304    /// simplify the incoming json object the incoming permission value will be
305    /// treated as a u32 and converted into the proper AttributePermission object.
306    ///
307    /// The incoming permissions number is represented by adding the numbers representing
308    /// the permission level.
309    /// Values:
310    /// 0x001 - Allow read permission
311    /// 0x002 - Allow encrypted read operations
312    /// 0x004 - Allow reading with man-in-the-middle protection
313    /// 0x010 - Allow write permission
314    /// 0x020 - Allow encrypted writes
315    /// 0x040 - Allow writing with man-in-the-middle protection
316    /// 0x080 - Allow signed writes
317    /// 0x100 - Allow signed write perations with man-in-the-middle protection
318    ///
319    /// Example input that allows read and write: 0x01 | 0x10 = 0x11
320    /// This function will convert this to the proper AttributePermission permissions.
321    fn permissions_and_properties_from_raw_num(
322        &self,
323        permissions: u32,
324        properties: u32,
325    ) -> AttributePermissions {
326        let mut read_encryption_required = false;
327        let mut read_authentication_required = false;
328        let mut read_authorization_required = false;
329
330        let mut write_encryption_required = false;
331        let mut write_authentication_required = false;
332        let mut write_authorization_required = false;
333
334        let mut update_encryption_required = false;
335        let mut update_authentication_required = false;
336        let mut update_authorization_required = false;
337
338        if permissions & PERMISSION_READ_ENCRYPTED != 0 {
339            read_encryption_required = true;
340            read_authentication_required = true;
341            read_authorization_required = true;
342        }
343
344        if permissions & PERMISSION_READ_ENCRYPTED_MITM != 0 {
345            read_encryption_required = true;
346            update_encryption_required = true;
347        }
348
349        if permissions & PERMISSION_WRITE_ENCRYPTED != 0 {
350            write_encryption_required = true;
351            update_encryption_required = true;
352        }
353
354        if permissions & PERMISSION_WRITE_ENCRYPTED_MITM != 0 {
355            write_encryption_required = true;
356            update_encryption_required = true;
357            update_authentication_required = true;
358            update_authorization_required = true;
359        }
360
361        if permissions & PERMISSION_WRITE_SIGNED != 0 {
362            write_authorization_required = true;
363        }
364
365        if permissions & PERMISSION_WRITE_SIGNED_MITM != 0 {
366            write_encryption_required = true;
367            write_authentication_required = true;
368            write_authorization_required = true;
369            update_encryption_required = true;
370            update_authentication_required = true;
371            update_authorization_required = true;
372        }
373
374        // Update Security Requirements only required if notify or indicate
375        // properties set.
376        let update_sec_requirement = if properties & (PROPERTY_NOTIFY | PROPERTY_INDICATE) != 0 {
377            Some(SecurityRequirements {
378                encryption_required: Some(update_encryption_required),
379                authentication_required: Some(update_authentication_required),
380                authorization_required: Some(update_authorization_required),
381                ..Default::default()
382            })
383        } else {
384            None
385        };
386
387        let read_sec_requirement = if properties & PROPERTY_READ != 0 {
388            Some(SecurityRequirements {
389                encryption_required: Some(read_encryption_required),
390                authentication_required: Some(read_authentication_required),
391                authorization_required: Some(read_authorization_required),
392                ..Default::default()
393            })
394        } else {
395            None
396        };
397
398        let write_sec_requirement = if properties & PROPERTY_WRITE != 0 {
399            Some(SecurityRequirements {
400                encryption_required: Some(write_encryption_required),
401                authentication_required: Some(write_authentication_required),
402                authorization_required: Some(write_authorization_required),
403                ..Default::default()
404            })
405        } else {
406            None
407        };
408
409        AttributePermissions {
410            read: read_sec_requirement,
411            write: write_sec_requirement,
412            update: update_sec_requirement,
413            ..Default::default()
414        }
415    }
416
417    /// Converts `descriptor_list_json` to FIDL descriptors and filters out descriptors banned by
418    /// the Server FIDL API. The Characteristic Extended Properties descriptor is one such banned
419    /// descriptor, and its value will be returned.
420    ///
421    /// Returns a tuple of (filtered FIDL descriptors, extended property bits)
422    fn process_descriptors(
423        &self,
424        descriptor_list_json: &Value,
425    ) -> Result<(Vec<Descriptor>, CharacteristicPropertyBits), Error> {
426        let mut descriptors: Vec<Descriptor> = Vec::new();
427        // Fuchsia will automatically setup these descriptors and manage them.
428        // Skip setting them up if found in the input descriptor list.
429        let banned_descriptor_uuids = [
430            Uuid::from_str("00002900-0000-1000-8000-00805f9b34fb").unwrap(), // CCC Descriptor
431            Uuid::from_str("00002902-0000-1000-8000-00805f9b34fb").unwrap(), // Client Configuration Descriptor
432            Uuid::from_str("00002903-0000-1000-8000-00805f9b34fb").unwrap(), // Server Configuration Descriptor
433        ];
434
435        if descriptor_list_json.is_null() {
436            return Ok((descriptors, CharacteristicPropertyBits::empty()));
437        }
438
439        let descriptor_list = descriptor_list_json
440            .as_array()
441            .ok_or_else(|| format_err!("Attribute 'descriptors' is not a parseable list."))?;
442
443        let mut ext_property_bits = CharacteristicPropertyBits::empty();
444
445        for descriptor in descriptor_list.iter() {
446            let descriptor_uuid: Uuid = match descriptor["uuid"].as_str() {
447                Some(uuid_str) => Uuid::from_str(uuid_str)
448                    .map_err(|_| format_err!("Descriptor uuid is invalid"))?,
449                None => return Err(format_err!("Descriptor uuid was unable to cast to str.")),
450            };
451            let descriptor_value = self.parse_attribute_value_to_byte_array(&descriptor["value"]);
452
453            // Intercept the Extended Properties descriptor.
454            if descriptor_uuid == Uuid::new16(CHARACTERISTIC_EXTENDED_PROPERTIES_UUID) {
455                if descriptor_value.is_empty() {
456                    warn!("Extended properties descriptor has empty value. Ignoring.");
457                    continue;
458                }
459                // The second byte in CharacteristicPropertyBits is for extended property bits.
460                let ext_bits_raw: u16 = (descriptor_value[0] as u16) << u8::BITS;
461                ext_property_bits = CharacteristicPropertyBits::from_bits_truncate(ext_bits_raw);
462                continue;
463            }
464
465            let raw_enforce_enforce_initial_attribute_length =
466                descriptor["enforce_initial_attribute_length"].as_bool().unwrap_or(false);
467
468            // No properties for descriptors.
469            let properties = 0u32;
470
471            if banned_descriptor_uuids.contains(&descriptor_uuid) {
472                continue;
473            }
474
475            let raw_descriptor_permissions = match descriptor["permissions"].as_u64() {
476                Some(permissions) => permissions as u32,
477                None => {
478                    return Err(format_err!("Descriptor permissions was unable to cast to u64."));
479                }
480            };
481
482            let desc_permission_attributes = self
483                .permissions_and_properties_from_raw_num(raw_descriptor_permissions, properties);
484
485            let descriptor_id = self.inner.write().generic_id_counter.next();
486            self.inner.write().attribute_value_mapping.insert(
487                descriptor_id,
488                (descriptor_value, raw_enforce_enforce_initial_attribute_length),
489            );
490            let fidl_descriptor = Descriptor {
491                handle: Some(Handle { value: descriptor_id }),
492                type_: Some(descriptor_uuid.into()),
493                permissions: Some(desc_permission_attributes),
494                ..Default::default()
495            };
496
497            descriptors.push(fidl_descriptor);
498        }
499        Ok((descriptors, ext_property_bits))
500    }
501
502    fn generate_characteristics(
503        &self,
504        characteristic_list_json: &Value,
505    ) -> Result<Vec<Characteristic>, Error> {
506        let mut characteristics: Vec<Characteristic> = Vec::new();
507        if characteristic_list_json.is_null() {
508            return Ok(characteristics);
509        }
510
511        let characteristic_list = match characteristic_list_json.as_array() {
512            Some(c) => c,
513            None => {
514                return Err(format_err!("Attribute 'characteristics' is not a parseable list."));
515            }
516        };
517
518        for characteristic in characteristic_list.iter() {
519            let characteristic_uuid = match characteristic["uuid"].as_str() {
520                Some(uuid_str) => Uuid::from_str(uuid_str)
521                    .map_err(|_| format_err!("Invalid characteristic uuid: {}", uuid_str))?,
522                None => return Err(format_err!("Characteristic uuid was unable to cast to str.")),
523            };
524
525            let characteristic_properties = match characteristic["properties"].as_u64() {
526                Some(properties) => properties as u32,
527                None => {
528                    return Err(format_err!(
529                        "Characteristic properties was unable to cast to u64."
530                    ));
531                }
532            };
533
534            let raw_characteristic_permissions = match characteristic["permissions"].as_u64() {
535                Some(permissions) => permissions as u32,
536                None => {
537                    return Err(format_err!(
538                        "Characteristic permissions was unable to cast to u64."
539                    ));
540                }
541            };
542
543            let characteristic_value =
544                self.parse_attribute_value_to_byte_array(&characteristic["value"]);
545
546            let raw_enforce_enforce_initial_attribute_length =
547                characteristic["enforce_initial_attribute_length"].as_bool().unwrap_or(false);
548
549            let descriptor_list = &characteristic["descriptors"];
550            let (fidl_descriptors, ext_properties_bits) =
551                self.process_descriptors(descriptor_list)?;
552
553            let characteristic_permissions = self.permissions_and_properties_from_raw_num(
554                raw_characteristic_permissions,
555                characteristic_properties,
556            );
557
558            // Properties map directly to CharacteristicPropertyBits except for
559            // property_extended_props (0x80), so we truncate. The extended properties descriptor is
560            // intercepted and added to the property bits (the Bluetooth stack will add the
561            // descriptor later).
562            let characteristic_properties =
563                CharacteristicPropertyBits::from_bits_truncate(characteristic_properties as u16)
564                    | ext_properties_bits;
565
566            let characteristic_id = self.inner.write().generic_id_counter.next();
567            self.inner.write().attribute_value_mapping.insert(
568                characteristic_id,
569                (characteristic_value, raw_enforce_enforce_initial_attribute_length),
570            );
571            let fidl_characteristic = Characteristic {
572                handle: Some(Handle { value: characteristic_id }),
573                type_: Some(characteristic_uuid.into()),
574                properties: Some(characteristic_properties),
575                permissions: Some(characteristic_permissions),
576                descriptors: Some(fidl_descriptors),
577                ..Default::default()
578            };
579
580            characteristics.push(fidl_characteristic);
581        }
582        Ok(characteristics)
583    }
584
585    fn generate_service(&self, service_json: &Value) -> Result<ServiceInfo, Error> {
586        // Determine if the service is primary or not.
587        let service_id = self.inner.write().generic_id_counter.next();
588        let service_kind = match service_json["type"]
589            .as_i64()
590            .ok_or_else(|| format_err!("Invalid service type"))?
591        {
592            0 => ServiceKind::Primary,
593            1 => ServiceKind::Secondary,
594            _ => return Err(format_err!("Invalid Service type")),
595        };
596
597        // Get the service UUID.
598        let service_uuid_str = service_json["uuid"]
599            .as_str()
600            .ok_or_else(|| format_err!("Service uuid was unable to cast  to str"))?;
601        let service_uuid =
602            Uuid::from_str(service_uuid_str).map_err(|_| format_err!("Invalid service uuid"))?;
603
604        //Get the Characteristics from the service.
605        let characteristics = self.generate_characteristics(&service_json["characteristics"])?;
606
607        Ok(ServiceInfo {
608            handle: Some(ServiceHandle { value: service_id }),
609            kind: Some(service_kind),
610            type_: Some(service_uuid.into()),
611            characteristics: Some(characteristics),
612            ..Default::default()
613        })
614    }
615
616    async fn publish_service(
617        &self,
618        service_info: ServiceInfo,
619        service_uuid: String,
620    ) -> Result<(), Error> {
621        let tag = "GattServerFacade::publish_service:";
622        let (service_client, service_server) =
623            fidl::endpoints::create_endpoints::<LocalServiceMarker>();
624        let (service_request_stream, service_control_handle) =
625            service_server.into_stream_and_control_handle();
626
627        let server_proxy = self
628            .inner
629            .read()
630            .server_proxy
631            .as_ref()
632            .ok_or_else(|| format_err!("No Server Proxy created."))?
633            .clone();
634        match server_proxy.publish_service(&service_info, service_client).await? {
635            Ok(()) => info!(
636                tag = &[tag, &line!().to_string()].join("").as_str(),
637                uuid:? = service_uuid;
638                "Successfully published GATT service",
639            ),
640            Err(e) => return Err(format_err!("PublishService error: {:?}", e)),
641        }
642
643        let monitor_delegate_fut = GattServerFacade::monitor_service_request_stream(
644            service_request_stream,
645            service_control_handle,
646            self.inner.read().attribute_value_mapping.clone(),
647        );
648        let fut = async {
649            let result = monitor_delegate_fut.await;
650            if let Err(err) = result {
651                error!(
652                    tag = "publish_service",
653                    err:?;
654                    "Failed to create or monitor the gatt service delegate"
655                );
656            }
657        };
658        self.inner.write().service_tasks.push(fasync::Task::spawn(fut));
659        Ok(())
660    }
661
662    /// Publish a GATT Server.
663    ///
664    /// The input is a JSON object representing the attributes of the GATT
665    /// server Database to setup. This function will also start listening for
666    /// incoming requests to Characteristics and Descriptors in each Service.
667    ///
668    /// This is primarially using the same input syntax as in the Android AOSP
669    /// ACTS test framework at:
670    /// <aosp_root>/tools/test/connectivity/acts/framework/acts/test_utils/bt/gatt_test_database.py
671    ///
672    /// A "database" key wraps the database at:
673    /// <aosp root>/tools/test/connectivity/acts/framework/acts/controllers/fuchsia_lib/bt/gatts_lib.py
674    ///
675    /// Example python dictionary that's turned into JSON (sub dic values can be found
676    /// in <aosp_root>/tools/test/connectivity/acts/framework/acts/test_utils/bt/bt_constants.py:
677    ///
678    /// SMALL_DATABASE = {
679    ///     'services': [{
680    ///         'uuid': '00001800-0000-1000-8000-00805f9b34fb',
681    ///         'type': gatt_service_types['primary'],
682    ///         'characteristics': [{
683    ///             'uuid': gatt_char_types['device_name'],
684    ///             'properties': gatt_characteristic['property_read'],
685    ///             'permissions': gatt_characteristic['permission_read'],
686    ///             'handle': 0x0003,
687    ///             'value_type': gatt_characteristic_value_format['string'],
688    ///             'value': 'Test Database'
689    ///         }, {
690    ///             'uuid': gatt_char_types['appearance'],
691    ///             'properties': gatt_characteristic['property_read'],
692    ///             'permissions': gatt_characteristic['permission_read'],
693    ///             'handle': 0x0005,
694    ///             'value_type': gatt_characteristic_value_format['sint32'],
695    ///             'offset': 0,
696    ///             'value': 17
697    ///         }, {
698    ///             'uuid': gatt_char_types['peripheral_pref_conn'],
699    ///             'properties': gatt_characteristic['property_read'],
700    ///             'permissions': gatt_characteristic['permission_read'],
701    ///             'handle': 0x0007
702    ///         }]
703    ///     }, {
704    ///         'uuid': '00001801-0000-1000-8000-00805f9b34fb',
705    ///         'type': gatt_service_types['primary'],
706    ///         'characteristics': [{
707    ///             'uuid': gatt_char_types['service_changed'],
708    ///             'properties': gatt_characteristic['property_indicate'],
709    ///             'permissions': gatt_characteristic['permission_read'] |
710    ///             gatt_characteristic['permission_write'],
711    ///             'handle': 0x0012,
712    ///             'value_type': gatt_characteristic_value_format['byte'],
713    ///             'value': [0x0000],
714    ///             'descriptors': [{
715    ///                 'uuid': gatt_char_desc_uuids['client_char_cfg'],
716    ///                 'permissions': gatt_descriptor['permission_read'] |
717    ///                 gatt_descriptor['permission_write'],
718    ///                 'value': [0x0000]
719    ///             }]
720    ///         }, {
721    ///             'uuid': '0000b004-0000-1000-8000-00805f9b34fb',
722    ///             'properties': gatt_characteristic['property_read'],
723    ///             'permissions': gatt_characteristic['permission_read'],
724    ///             'handle': 0x0015,
725    ///             'value_type': gatt_characteristic_value_format['byte'],
726    ///             'value': [0x04]
727    ///         }]
728    ///     }]
729    /// }
730    pub async fn publish_server(&self, args: Value) -> Result<(), Error> {
731        let tag = "GattServerFacade::publish_server:";
732        info!(tag = &[tag, &line!().to_string()].join("").as_str(); "Publishing service");
733        let server_proxy = self.create_server_proxy()?;
734        self.inner.write().server_proxy = Some(server_proxy);
735        let services = args
736            .get("database")
737            .ok_or_else(|| format_err!("Could not find the 'database' key in the json database."))?
738            .get("services")
739            .ok_or_else(|| {
740                format_err!("Could not find the 'services' key in the json database.")
741            })?;
742
743        let service_list = match services.as_array() {
744            Some(s) => s,
745            None => return Err(format_err!("Attribute 'service' is not a parseable list.")),
746        };
747
748        for service in service_list.iter() {
749            self.inner.write().attribute_value_mapping.clear();
750            let service_info = self.generate_service(service)?;
751            let service_uuid = &service["uuid"];
752            self.publish_service(service_info, service_uuid.to_string()).await?;
753        }
754        Ok(())
755    }
756
757    pub async fn close_server(&self) {
758        self.inner.write().server_proxy = None;
759        let _ = std::mem::take(&mut self.inner.write().service_tasks);
760    }
761
762    // GattServerFacade for cleaning up objects in use.
763    pub fn cleanup(&self) {
764        let tag = "GattServerFacade::cleanup:";
765        info!(tag = &[tag, &line!().to_string()].join("").as_str(); "Cleanup GATT server objects");
766        self.inner.write().server_proxy = None;
767        let _ = std::mem::take(&mut self.inner.write().service_tasks);
768    }
769
770    // GattServerFacade for printing useful information pertaining to the facade for
771    // debug purposes.
772    pub fn print(&self) {
773        let tag = "GattServerFacade::print:";
774        info!(tag = &[tag, &line!().to_string()].join("").as_str(); "Unimplemented print function");
775    }
776}