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