• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Lint as: python2, python3
2# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6from __future__ import absolute_import
7
8import base64
9import functools
10import json
11import logging
12import threading
13from datetime import datetime
14
15import common
16from autotest_lib.client.bin import utils
17from autotest_lib.client.cros import constants
18from autotest_lib.server import autotest
19
20def proxy_thread_safe(method):
21    """A decorator enabling thread-safe XmlRpc calls"""
22
23    @functools.wraps(method)
24    def wrapper(self, *args, **kwargs):
25        """A wrapper of the decorated method"""
26        with self._proxy_lock:
27            return method(self, *args, **kwargs)
28
29    return wrapper
30
31
32class BluetoothDevice(object):
33    """BluetoothDevice is a thin layer of logic over a remote DUT.
34
35    The Autotest host object representing the remote DUT, passed to this
36    class on initialization, can be accessed from its host property.
37
38    """
39
40    XMLRPC_BRINGUP_TIMEOUT_SECONDS = 60
41    XMLRPC_LOG_PATH = '/var/log/bluetooth_xmlrpc_device.log'
42    XMLRPC_REQUEST_TIMEOUT_SECONDS = 180
43
44    # We currently get dates back in string format due to some inconsistencies
45    # between python2 and python3. This is the standard date format we use.
46    STANDARD_DATE_FORMAT = '%Y-%m-%d %H:%M:%S.%f'
47
48    def __init__(self, device_host, remote_facade_proxy=None, floss=False):
49        """Construct a BluetoothDevice.
50
51        @param device_host: host object representing a remote host.
52
53        """
54        self.host = device_host
55        self.floss = floss
56        self._remote_proxy = remote_facade_proxy
57
58        # Make sure the client library is on the device so that the proxy code
59        # is there when we try to call it.
60        client_at = autotest.Autotest(self.host)
61        client_at.install()
62        self._proxy_lock = threading.Lock()
63
64        # Assign the correct _proxy based on the remote facade
65        if self._remote_proxy:
66            if self.floss:
67                self._proxy = self._remote_proxy.floss
68            else:
69                self._proxy = self._remote_proxy.bluetooth
70        else:
71            # If remote facade wasn't already created, connect directly here
72            self._proxy = self._connect_xmlrpc_directly()
73
74    def __getattr__(self, name):
75        """Override default attribute behavior to call proxy methods.
76
77        To remove duplicate code in this class, we allow methods in the proxy
78        class to be called directly from the bluetooth device class. If an
79        attribute is contained within this class, we return it. Otherwise, if
80        the proxy object contains a callable attribute of that name, we return a
81        function that calls that object when invoked.
82
83        All methods called on the proxy in this way will hold the proxy lock.
84        """
85        try:
86            return object.__getattr__(self, name)
87        except AttributeError as ae:
88            pass
89
90        # We only return proxied methods if no such attribute exists on this
91        # class. Any attribute errors here will be raised at the end if attr
92        # is None
93        try:
94            proxy = object.__getattribute__(self, '_proxy')
95            proxy_lock = object.__getattribute__(self, '_proxy_lock')
96            attr = proxy.__getattr__(name)
97            if attr:
98
99                def wrapper(*args, **kwargs):
100                    """Call target function while holding proxy lock."""
101                    with proxy_lock:
102                        return attr(*args, **kwargs)
103
104                return wrapper
105        except AttributeError as ae:
106            pass
107
108        # Couldn't find the attribute in either self or self._proxy.
109        raise AttributeError('{} has no attribute: {}'.format(
110                type(self).__name__, name))
111
112    def is_floss(self):
113        """Is the current facade running Floss?"""
114        return self.floss
115
116    def _connect_xmlrpc_directly(self):
117        """Connects to the bluetooth facade directly via xmlrpc."""
118        # When the xmlrpc server is already created (using the
119        # RemoteFacadeFactory), we will use the BluezFacadeLocal inside the
120        # remote proxy. Otherwise, we will use the xmlrpc server started from
121        # this class. Currently, there are a few users outside of the Bluetooth
122        # autotests that use this and this can be removed once those users
123        # migrate to using the RemoteFacadeFactory to generate the xmlrpc
124        # connection.
125        proxy = self.host.rpc_server_tracker.xmlrpc_connect(
126                constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_COMMAND,
127                constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT,
128                command_name=constants.
129                BLUETOOTH_DEVICE_XMLRPC_SERVER_CLEANUP_PATTERN,
130                ready_test_name=constants.
131                BLUETOOTH_DEVICE_XMLRPC_SERVER_READY_METHOD,
132                timeout_seconds=self.XMLRPC_BRINGUP_TIMEOUT_SECONDS,
133                logfile=self.XMLRPC_LOG_PATH,
134                request_timeout_seconds=self.XMLRPC_REQUEST_TIMEOUT_SECONDS)
135
136        self._bt_direct_proxy = proxy
137        return proxy
138
139    @property
140    @proxy_thread_safe
141    def address(self):
142        """Get the adapter address."""
143        return self._proxy.get_address()
144
145    @property
146    @proxy_thread_safe
147    def bluez_version(self):
148        """Get the bluez version."""
149        return self._proxy.get_bluez_version()
150
151    @property
152    @proxy_thread_safe
153    def bluetooth_class(self):
154        """Get the bluetooth class."""
155        return self._proxy.get_bluetooth_class()
156
157    @proxy_thread_safe
158    def set_debug_log_levels(self, bluez_vb, kernel_vb):
159        """Enable or disable the debug logs of bluetooth
160
161        @param bluez_vb: verbosity of bluez debug log, either 0 or 1
162        @param kernel_vb: verbosity of kernel debug log, either 0 or 1
163
164        """
165        return self._proxy.set_debug_log_levels(bluez_vb, kernel_vb)
166
167    @proxy_thread_safe
168    def set_quality_debug_log(self, enable):
169        """Enable or disable bluez quality debug log in the DUT
170        @param enable: True to enable all of the debug log,
171                       False to disable all of the debug log.
172        """
173        return self._proxy.set_quality_debug_log(enable)
174
175    @proxy_thread_safe
176    def log_message(self, msg, dut=True, peer=True):
177        """ Log a message in DUT log and peer logs with timestamp.
178
179        @param msg: message to be logged.
180        @param dut: log message on DUT
181        @param peer: log message on peer devices
182        """
183        try:
184            # TODO(b/146671469) Implement logging to tester
185
186            date =  datetime.strftime(datetime.now(),"%Y:%m:%d %H:%M:%S:%f")
187            msg = "bluetooth autotest --- %s : %s ---" % (date, msg)
188            logging.debug("Broadcasting '%s'",msg)
189
190            if dut:
191                self._proxy.log_message(msg)
192
193            if peer:
194                for btpeer in self.host.btpeer_list:
195                    btpeer.log_message(msg)
196        except Exception as e:
197            logging.error("Exception '%s' in log_message '%s'", str(e), msg)
198
199
200    @proxy_thread_safe
201    def is_wrt_supported(self):
202        """ Check if Bluetooth adapter support WRT logs.
203
204        Intel adapter support WRT (except of WP2 and StP2)
205
206        @returns: True if adapter support WRT logs
207        """
208        return self._proxy.is_wrt_supported()
209
210
211    @proxy_thread_safe
212    def enable_wrt_logs(self):
213        """Enable wrt logs on Intel adapters."""
214        return self._proxy.enable_wrt_logs()
215
216
217    @proxy_thread_safe
218    def collect_wrt_logs(self):
219        """Collect wrt logs on Intel adapters."""
220        return self._proxy.collect_wrt_logs()
221
222
223    @proxy_thread_safe
224    def start_bluetoothd(self):
225        """start bluetoothd.
226
227        @returns: True if bluetoothd is started correctly.
228                  False otherwise.
229
230        """
231        return self._proxy.start_bluetoothd()
232
233
234    @proxy_thread_safe
235    def stop_bluetoothd(self):
236        """stop bluetoothd.
237
238        @returns: True if bluetoothd is stopped correctly.
239                  False otherwise.
240
241        """
242        return self._proxy.stop_bluetoothd()
243
244
245    @proxy_thread_safe
246    def is_bluetoothd_running(self):
247        """Is bluetoothd running?
248
249        @returns: True if bluetoothd is running
250
251        """
252        return self._proxy.is_bluetoothd_running()
253
254
255    @proxy_thread_safe
256    def is_bluetoothd_valid(self):
257        """Checks whether the current bluetoothd session is ok.
258
259        Returns:
260            True if the current bluetoothd session is ok. False if bluetoothd is
261            not running or it is a new session.
262        """
263        return self._proxy.is_bluetoothd_proxy_valid()
264
265    @proxy_thread_safe
266    def has_adapter(self):
267        """@return True if an adapter is present, False if not."""
268        return self._proxy.has_adapter()
269
270
271    @proxy_thread_safe
272    def is_wake_enabled(self):
273        """@return True if adapter is wake enabled, False if not."""
274        return self._proxy.is_wake_enabled()
275
276
277    @proxy_thread_safe
278    def set_wake_enabled(self, value):
279        """ Sets the power/wakeup value for the adapter.
280
281        Args:
282            value: Whether the adapter can wake from suspend
283
284        @return True if able to set it to value, False if not."""
285        return self._proxy.set_wake_enabled(value)
286
287
288    def get_hci(self):
289        """Get hci of the adapter; normally, it is 'hci0'.
290
291        @returns: the hci name of the adapter.
292
293        """
294        dev_info = self.get_dev_info()
295        hci = (dev_info[1] if isinstance(dev_info, list) and
296               len(dev_info) > 1 else None)
297        return hci
298
299
300    def get_UUIDs(self):
301        """Get the UUIDs.
302
303        The UUIDs can be dynamically changed at run time due to adapter/CRAS
304        services availability. Therefore, always query them from the adapter,
305        not from the cache.
306
307        An example of UUIDs:
308            [u'00001112-0000-1000-8000-00805f9b34fb',
309             u'00001801-0000-1000-8000-00805f9b34fb',
310             u'0000110a-0000-1000-8000-00805f9b34fb',
311             u'0000111f-0000-1000-8000-00805f9b34fb',
312             u'00001200-0000-1000-8000-00805f9b34fb',
313             u'00001800-0000-1000-8000-00805f9b34fb']
314
315        @returns: the list of the UUIDs.
316
317        """
318        properties = self.get_adapter_properties()
319        return properties.get('UUIDs')
320
321
322    @proxy_thread_safe
323    def set_pairable_timeout(self, pairable_timeout):
324        """Set the adapter PairableTimeout.
325
326        @param pairable_timeout: adapter PairableTimeout
327                value to set in seconds (Integer).
328
329        @return True on success, False otherwise.
330
331        """
332        return self._proxy.set_pairable_timeout(pairable_timeout)
333
334
335    @proxy_thread_safe
336    def get_pairable_timeout(self):
337        """Get the adapter PairableTimeout.
338
339        @return Value of property PairableTimeout in seconds (Integer).
340
341        """
342        return self._proxy.get_pairable_timeout()
343
344
345    @proxy_thread_safe
346    def set_pairable(self, pairable):
347        """Set the adapter pairable state.
348
349        @param pairable: adapter pairable state to set (True or False).
350
351        @return True on success, False otherwise.
352
353        """
354        return self._proxy.set_pairable(pairable)
355
356
357    @proxy_thread_safe
358    def is_pairable(self):
359        """Is the adapter in the pairable state?
360
361        @return True if pairable. False otherwise.
362
363        """
364        return self._proxy.get_pairable()
365
366    @proxy_thread_safe
367    def set_adapter_alias(self, alias):
368        """Set the adapter alias.
369
370        A note on Alias property - providing an empty string ('') will reset the
371        Alias property to the system default
372
373        @param alias: adapter alias to set with type String
374
375        @return True on success, False otherwise.
376        """
377
378        return self._proxy.set_adapter_alias(alias)
379
380    @proxy_thread_safe
381    def get_adapter_properties(self):
382        """Read the adapter properties from the Bluetooth Daemon.
383
384        An example of the adapter properties looks like
385        {u'Name': u'BlueZ 5.35',
386         u'Alias': u'Chromebook',
387         u'Modalias': u'bluetooth:v00E0p2436d0400',
388         u'Powered': 1,
389         u'DiscoverableTimeout': 180,
390         u'PairableTimeout': 0,
391         u'Discoverable': 0,
392         u'Address': u'6C:29:95:1A:D4:6F',
393         u'Discovering': 0,
394         u'Pairable': 1,
395         u'Class': 4718852,
396         u'UUIDs': [u'00001112-0000-1000-8000-00805f9b34fb',
397                    u'00001801-0000-1000-8000-00805f9b34fb',
398                    u'0000110a-0000-1000-8000-00805f9b34fb',
399                    u'0000111f-0000-1000-8000-00805f9b34fb',
400                    u'00001200-0000-1000-8000-00805f9b34fb',
401                    u'00001800-0000-1000-8000-00805f9b34fb']}
402
403        @return the properties as a dictionary on success,
404            the value False otherwise.
405
406        """
407        return json.loads(self._proxy.get_adapter_properties())
408
409
410    @proxy_thread_safe
411    def read_version(self):
412        """Read the version of the management interface from the Kernel.
413
414        @return the version as a tuple of:
415          ( version, revision )
416
417        """
418        return json.loads(self._proxy.read_version())
419
420
421    @proxy_thread_safe
422    def read_supported_commands(self):
423        """Read the set of supported commands from the Kernel.
424
425        @return set of supported commands as arrays in a tuple of:
426          ( commands, events )
427
428        """
429        return json.loads(self._proxy.read_supported_commands())
430
431
432    @proxy_thread_safe
433    def read_index_list(self):
434        """Read the list of currently known controllers from the Kernel.
435
436        @return array of controller indexes.
437
438        """
439        return json.loads(self._proxy.read_index_list())
440
441
442    @proxy_thread_safe
443    def read_info(self):
444        """Read the adapter information from the Kernel.
445
446        An example of the adapter information looks like
447        [u'6C:29:95:1A:D4:6F', 6, 2, 65535, 2769, 4718852, u'Chromebook', u'']
448
449        @return the information as a tuple of:
450          ( address, bluetooth_version, manufacturer_id,
451            supported_settings, current_settings, class_of_device,
452            name, short_name )
453
454        """
455        return json.loads(self._proxy.read_info())
456
457
458    @proxy_thread_safe
459    def add_device(self, address, address_type, action):
460        """Add a device to the Kernel action list.
461
462        @param address: Address of the device to add.
463        @param address_type: Type of device in @address.
464        @param action: Action to take.
465
466        @return tuple of ( address, address_type ) on success,
467          None on failure.
468
469        """
470        return json.loads(self._proxy.add_device(address, address_type, action))
471
472
473    @proxy_thread_safe
474    def remove_device(self, address, address_type):
475        """Remove a device from the Kernel action list.
476
477        @param address: Address of the device to remove.
478        @param address_type: Type of device in @address.
479
480        @return tuple of ( address, address_type ) on success,
481          None on failure.
482
483        """
484        return json.loads(self._proxy.remove_device(address, address_type))
485
486    def _decode_json_base64(self, data):
487        """Load serialized JSON and then base64 decode it
488
489        Required to handle non-ascii data
490        @param data: data to be JSON and base64 decode
491
492        @return : JSON and base64 decoded data
493
494
495        """
496        logging.debug("_decode_json_base64 raw data is %s", data)
497        json_encoded = json.loads(data)
498        logging.debug("JSON encoded data is %s", json_encoded)
499        base64_decoded = utils.base64_recursive_decode(json_encoded)
500        logging.debug("base64 decoded data is %s", base64_decoded)
501        return base64_decoded
502
503
504    @proxy_thread_safe
505    def get_devices(self):
506        """Read information about remote devices known to the adapter.
507
508        An example of the device information of RN-42 looks like
509        [{u'Name': u'RNBT-A96F',
510          u'Alias': u'RNBT-A96F',
511          u'Adapter': u'/org/bluez/hci0',
512          u'LegacyPairing': 0,
513          u'Paired': 1,
514          u'Connected': 0,
515          u'UUIDs': [u'00001124-0000-1000-8000-00805f9b34fb'],
516          u'Address': u'00:06:66:75:A9:6F',
517          u'Icon': u'input-mouse',
518          u'Class': 1408,
519          u'Trusted': 1,
520          u'Blocked': 0}]
521
522        @return the properties of each device as an array of
523            dictionaries on success, the value False otherwise.
524
525        """
526        return json.loads(self._proxy.get_devices())
527
528
529    @proxy_thread_safe
530    def get_device_property(self, address, prop_name):
531        """Read a property of BT device by directly querying device dbus object
532
533        @param address: Address of the device to query
534        @param prop_name: Property to be queried
535
536        @return The property if device is found and has property, None otherwise
537        """
538
539        prop_val = self._proxy.get_device_property(address, prop_name)
540
541        # Handle dbus error case returned by dbus_safe decorator
542        if prop_val is None:
543            return None
544
545        # Decode and return property value
546        return json.loads(prop_val)
547
548
549    @proxy_thread_safe
550    def get_battery_property(self, address, prop_name):
551        """Read a property of battery by directly querying the dbus object
552
553        @param address: Address of the device to query
554        @param prop_name: Property to be queried
555
556        @return The property if battery is found and has property,
557          None otherwise
558        """
559
560        return self._proxy.get_battery_property(address, prop_name)
561
562    @proxy_thread_safe
563    def get_dev_info(self):
564        """Read raw HCI device information.
565
566        An example of the device information looks like:
567        [0, u'hci0', u'6C:29:95:1A:D4:6F', 13, 0, 1, 581900950526, 52472, 7,
568         32768, 1021, 5, 96, 6, 0, 0, 151, 151, 0, 0, 0, 0, 1968, 12507]
569
570        @return tuple of (index, name, address, flags, device_type, bus_type,
571                       features, pkt_type, link_policy, link_mode,
572                       acl_mtu, acl_pkts, sco_mtu, sco_pkts,
573                       err_rx, err_tx, cmd_tx, evt_rx, acl_tx, acl_rx,
574                       sco_tx, sco_rx, byte_rx, byte_tx) on success,
575                None on failure.
576
577        """
578        return json.loads(self._proxy.get_dev_info())
579
580
581    @proxy_thread_safe
582    def get_supported_capabilities(self):
583        """ Get the supported_capabilities of the adapter
584        @returns (capabilities,None) on success (None, <error>) on failure
585        """
586        capabilities, error = self._proxy.get_supported_capabilities()
587        return (json.loads(capabilities), error)
588
589
590    @proxy_thread_safe
591    def register_profile(self, path, uuid, options):
592        """Register new profile (service).
593
594        @param path: Path to the profile object.
595        @param uuid: Service Class ID of the service as string.
596        @param options: Dictionary of options for the new service, compliant
597                        with BlueZ D-Bus Profile API standard.
598
599        @return True on success, False otherwise.
600
601        """
602        return self._proxy.register_profile(path, uuid, options)
603
604
605    @proxy_thread_safe
606    def has_device(self, address):
607        """Checks if the device with a given address exists.
608
609        @param address: Address of the device.
610
611        @returns: True if there is a device with that address.
612                  False otherwise.
613
614        """
615        return self._proxy.has_device(address)
616
617
618    @proxy_thread_safe
619    def device_is_paired(self, address):
620        """Checks if a device is paired.
621
622        @param address: address of the device.
623
624        @returns: True if device is paired. False otherwise.
625
626        """
627        return self._proxy.device_is_paired(address)
628
629
630    @proxy_thread_safe
631    def device_services_resolved(self, address):
632        """Checks if services are resolved for a device.
633
634        @param address: address of the device.
635
636        @returns: True if services are resolved. False otherwise.
637
638        """
639        return self._proxy.device_services_resolved(address)
640
641
642    @proxy_thread_safe
643    def set_trusted(self, address, trusted=True):
644        """Set the device trusted.
645
646        @param address: The bluetooth address of the device.
647        @param trusted: True or False indicating whether to set trusted or not.
648
649        @returns: True if successful. False otherwise.
650
651        """
652        return self._proxy.set_trusted(address, trusted)
653
654
655    @proxy_thread_safe
656    def pair_legacy_device(self, address, pin, trusted, timeout):
657        """Pairs a device with a given pin code.
658
659        Registers an agent who handles pin code request and
660        pairs a device with known pin code.
661
662        @param address: Address of the device to pair.
663        @param pin: The pin code of the device to pair.
664        @param trusted: indicating whether to set the device trusted.
665        @param timeout: The timeout in seconds for pairing.
666
667        @returns: True on success. False otherwise.
668
669        """
670        return self._proxy.pair_legacy_device(address, pin, trusted, timeout)
671
672
673    @proxy_thread_safe
674    def remove_device_object(self, address):
675        """Removes a device object and the pairing information.
676
677        Calls RemoveDevice method to remove remote device
678        object and the pairing information.
679
680        @param address: address of the device to unpair.
681
682        @returns: True on success. False otherwise.
683
684        """
685        return self._proxy.remove_device_object(address)
686
687
688    @proxy_thread_safe
689    def connect_device(self, address):
690        """Connects a device.
691
692        Connects a device if it is not connected.
693
694        @param address: Address of the device to connect.
695
696        @returns: True on success. False otherwise.
697
698        """
699        return self._proxy.connect_device(address)
700
701
702    @proxy_thread_safe
703    def device_is_connected(self, address):
704        """Checks if a device is connected.
705
706        @param address: Address of the device to check if it is connected.
707
708        @returns: True if device is connected. False otherwise.
709
710        """
711        return self._proxy.device_is_connected(address)
712
713
714    @proxy_thread_safe
715    def disconnect_device(self, address):
716        """Disconnects a device.
717
718        Disconnects a device if it is connected.
719
720        @param address: Address of the device to disconnect.
721
722        @returns: True on success. False otherwise.
723
724        """
725        return self._proxy.disconnect_device(address)
726
727
728    @proxy_thread_safe
729    def btmon_start(self):
730        """Start btmon monitoring."""
731        self._proxy.btmon_start()
732
733
734    @proxy_thread_safe
735    def btmon_stop(self):
736        """Stop btmon monitoring."""
737        self._proxy.btmon_stop()
738
739
740    @proxy_thread_safe
741    def btmon_get(self, search_str='', start_str=''):
742        """Get btmon output contents.
743
744        @param search_str: only lines with search_str would be kept.
745        @param start_str: all lines before the occurrence of start_str would be
746                filtered.
747
748        @returns: the recorded btmon output.
749
750        """
751        return self._proxy.btmon_get(search_str, start_str)
752
753
754    @proxy_thread_safe
755    def btmon_find(self, pattern_str):
756        """Find if a pattern string exists in btmon output.
757
758        @param pattern_str: the pattern string to find.
759
760        @returns: True on success. False otherwise.
761
762        """
763        return self._proxy.btmon_find(pattern_str)
764
765
766    @proxy_thread_safe
767    def advmon_check_manager_interface_exist(self):
768        """Check if AdvertisementMonitorManager1 interface is available.
769
770        @returns: True if Manager interface is available, False otherwise.
771
772        """
773        return self._proxy.advmon_check_manager_interface_exist()
774
775
776    @proxy_thread_safe
777    def advmon_read_supported_types(self):
778        """Read the Advertisement Monitor supported monitor types.
779
780        @returns: List of supported advertisement monitor types.
781
782        """
783        return self._proxy.advmon_read_supported_types()
784
785
786    @proxy_thread_safe
787    def advmon_read_supported_features(self):
788        """Read the Advertisement Monitor supported features.
789
790        @returns: List of supported advertisement monitor features.
791
792        """
793        return self._proxy.advmon_read_supported_features()
794
795
796    @proxy_thread_safe
797    def advmon_create_app(self):
798        """Create an advertisement monitor app.
799
800        @returns: app id, once the app is created.
801
802        """
803        return self._proxy.advmon_create_app()
804
805
806    @proxy_thread_safe
807    def advmon_exit_app(self, app_id):
808        """Exit an advertisement monitor app.
809
810        @param app_id: the app id.
811
812        @returns: True on success, False otherwise.
813
814        """
815        return self._proxy.advmon_exit_app(app_id)
816
817
818    @proxy_thread_safe
819    def advmon_kill_app(self, app_id):
820        """Kill an advertisement monitor app by sending SIGKILL.
821
822        @param app_id: the app id.
823
824        @returns: True on success, False otherwise.
825
826        """
827        return self._proxy.advmon_kill_app(app_id)
828
829
830    @proxy_thread_safe
831    def advmon_register_app(self, app_id):
832        """Register an advertisement monitor app.
833
834        @param app_id: the app id.
835
836        @returns: True on success, False otherwise.
837
838        """
839        return self._proxy.advmon_register_app(app_id)
840
841
842    @proxy_thread_safe
843    def advmon_unregister_app(self, app_id):
844        """Unregister an advertisement monitor app.
845
846        @param app_id: the app id.
847
848        @returns: True on success, False otherwise.
849
850        """
851        return self._proxy.advmon_unregister_app(app_id)
852
853
854    @proxy_thread_safe
855    def advmon_add_monitor(self, app_id, monitor_data):
856        """Create an Advertisement Monitor object.
857
858        @param app_id: the app id.
859        @param monitor_data: the list containing monitor type, RSSI filter
860                             values and patterns.
861
862        @returns: monitor id, once the monitor is created, None otherwise.
863
864        """
865        return self._proxy.advmon_add_monitor(app_id, monitor_data)
866
867
868    @proxy_thread_safe
869    def advmon_remove_monitor(self, app_id, monitor_id):
870        """Remove the Advertisement Monitor object.
871
872        @param app_id: the app id.
873        @param monitor_id: the monitor id.
874
875        @returns: True on success, False otherwise.
876
877        """
878        return self._proxy.advmon_remove_monitor(app_id, monitor_id)
879
880
881    @proxy_thread_safe
882    def advmon_get_event_count(self, app_id, monitor_id, event):
883        """Read the count of a particular event on the given monitor.
884
885        @param app_id: the app id.
886        @param monitor_id: the monitor id.
887        @param event: name of the specific event or 'All' for all events.
888
889        @returns: count of the specific event or dict of counts of all events.
890
891        """
892        return self._proxy.advmon_get_event_count(app_id, monitor_id, event)
893
894
895    @proxy_thread_safe
896    def advmon_reset_event_count(self, app_id, monitor_id, event):
897        """Reset the count of a particular event on the given monitor.
898
899        @param app_id: the app id.
900        @param monitor_id: the monitor id.
901        @param event: name of the specific event or 'All' for all events.
902
903        @returns: True on success, False otherwise.
904
905        """
906        return self._proxy.advmon_reset_event_count(app_id, monitor_id, event)
907
908    @proxy_thread_safe
909    def advmon_set_target_devices(self, app_id, monitor_id, devices):
910        """Set the target devices to the given monitor.
911
912        DeviceFound and DeviceLost will only be counted if it is triggered by a
913        target device.
914
915        @param app_id: the app id.
916        @param monitor_id: the monitor id.
917        @param devices: a list of devices in MAC address
918
919        @returns: True on success, False otherwise.
920
921        """
922        return self._proxy.advmon_set_target_devices(app_id, monitor_id,
923                                                     devices)
924
925    @proxy_thread_safe
926    def advmon_interleave_scan_logger_start(self):
927        """ Start interleave logger recording
928        """
929        self._proxy.advmon_interleave_scan_logger_start()
930
931    @proxy_thread_safe
932    def advmon_interleave_scan_logger_stop(self):
933        """ Stop interleave logger recording
934
935        @returns: True if logs were successfully collected,
936                  False otherwise.
937
938        """
939        return self._proxy.advmon_interleave_scan_logger_stop()
940
941    @proxy_thread_safe
942    def advmon_interleave_scan_logger_get_records(self):
943        """ Get records in previous log collections
944
945        @returns: a list of records, where each item is a record of
946                  interleave |state| and the |time| the state starts.
947                  |state| could be {'no filter', 'allowlist'}
948                  |time| is system time in sec
949
950        """
951        return self._proxy.advmon_interleave_scan_logger_get_records()
952
953    @proxy_thread_safe
954    def advmon_interleave_scan_logger_get_cancel_events(self):
955        """ Get cancel events in previous log collections
956
957        @returns: a list of cancel |time| when a interleave cancel event log
958                  was found.
959                  |time| is system time in sec
960
961        """
962        return self._proxy.advmon_interleave_scan_logger_get_cancel_events()
963
964    @proxy_thread_safe
965    def advmon_interleave_scan_get_durations(self):
966        """Get durations of allowlist scan and no filter scan
967
968        @returns: a dict of {'allowlist': allowlist_duration,
969                             'no filter': no_filter_duration},
970                  or None if something went wrong
971        """
972        return self._proxy.get_advmon_interleave_durations()
973
974    @proxy_thread_safe
975    def messages_start(self):
976        """Start messages monitoring."""
977        self._proxy.messages_start()
978
979    @proxy_thread_safe
980    def messages_stop(self):
981        """Stop messages monitoring.
982
983        @returns: True if logs were successfully gathered since logging started,
984                else False
985        """
986        return self._proxy.messages_stop()
987
988    @proxy_thread_safe
989    def messages_find(self, pattern_str):
990        """Find if a pattern string exists in messages output.
991
992        @param pattern_str: the pattern string to find.
993
994        @returns: True on success. False otherwise.
995
996        """
997        return self._proxy.messages_find(pattern_str)
998
999    @proxy_thread_safe
1000    def clean_bluetooth_kernel_log(self, log_level=7):
1001        """Remove Bluetooth kernel logs in /var/log/messages with loglevel
1002           equal to or greater than |log_level|
1003
1004        @param log_level: int in range [0..7]
1005        """
1006        self._proxy.clean_bluetooth_kernel_log(log_level)
1007
1008    @proxy_thread_safe
1009    def register_advertisement(self, advertisement_data):
1010        """Register an advertisement.
1011
1012        Note that rpc supports only conformable types. Hence, a
1013        dict about the advertisement is passed as a parameter such
1014        that the advertisement object could be contructed on the host.
1015
1016        @param advertisement_data: a dict of the advertisement for
1017                                   the adapter to register.
1018
1019        @returns: True on success. False otherwise.
1020
1021        """
1022        return self._proxy.register_advertisement(advertisement_data)
1023
1024
1025    @proxy_thread_safe
1026    def unregister_advertisement(self, advertisement_data):
1027        """Unregister an advertisement.
1028
1029        @param advertisement_data: a dict of the advertisement to unregister.
1030
1031        @returns: True on success. False otherwise.
1032
1033        """
1034        return self._proxy.unregister_advertisement(advertisement_data)
1035
1036
1037    @proxy_thread_safe
1038    def set_advertising_intervals(self, min_adv_interval_ms,
1039                                  max_adv_interval_ms):
1040        """Set advertising intervals.
1041
1042        @param min_adv_interval_ms: the min advertising interval in ms.
1043        @param max_adv_interval_ms: the max advertising interval in ms.
1044
1045        @returns: True on success. False otherwise.
1046
1047        """
1048        return self._proxy.set_advertising_intervals(min_adv_interval_ms,
1049                                                     max_adv_interval_ms)
1050
1051
1052    @proxy_thread_safe
1053    def get_advertisement_property(self, adv_path, prop_name):
1054        """Grab property of an advertisement registered on the DUT
1055
1056        The service on the DUT registers a dbus object and holds it. During the
1057        test, some properties on the object may change, so this allows the test
1058        access to the properties at run-time.
1059
1060        @param adv_path: string path of the dbus object
1061        @param prop_name: string name of the property required
1062
1063        @returns: the value of the property in standard (non-dbus) type if the
1064                    property exists, else None
1065        """
1066
1067        return self._proxy.get_advertisement_property(adv_path, prop_name)
1068
1069    @proxy_thread_safe
1070    def get_advertising_manager_property(self, prop_name):
1071        """Grab property of the bluez advertising manager
1072
1073        This allows us to understand the DUT's advertising capabilities, for
1074        instance the maximum number of advertising instances supported, so that
1075        we can test these capabilities.
1076
1077        @param adv_path: string path of the dbus object
1078        @param prop_name: string name of the property required
1079
1080        @returns: the value of the property in standard (non-dbus) type if the
1081                    property exists, else None
1082        """
1083
1084        return self._proxy.get_advertising_manager_property(prop_name)
1085
1086    @proxy_thread_safe
1087    def reset_advertising(self):
1088        """Reset advertising.
1089
1090        This includes unregister all advertisements, reset advertising
1091        intervals, and disable advertising.
1092
1093        @returns: True on success. False otherwise.
1094
1095        """
1096        return self._proxy.reset_advertising()
1097
1098
1099    @proxy_thread_safe
1100    def create_audio_record_directory(self, audio_record_dir):
1101        """Create the audio recording directory.
1102
1103        @param audio_record_dir: the audio recording directory
1104
1105        @returns: True on success. False otherwise.
1106        """
1107        return self._proxy.create_audio_record_directory(audio_record_dir)
1108
1109    @proxy_thread_safe
1110    def get_audio_thread_summary(self):
1111        """Dumps audio thread info.
1112
1113        @returns: a list of cras audio information.
1114        """
1115        return self._proxy.get_audio_thread_summary()
1116
1117    @proxy_thread_safe
1118    def get_device_id_from_node_type(self, node_type, is_input):
1119        """Gets device id from node type.
1120
1121        @param node_type: a node type defined in CRAS_NODE_TYPES.
1122        @param is_input: True if the node is input. False otherwise.
1123
1124        @returns: a string for device id.
1125        """
1126        return self._proxy.get_device_id_from_node_type(node_type, is_input)
1127
1128    @proxy_thread_safe
1129    def start_capturing_audio_subprocess(self, audio_data, recording_device):
1130        """Start capturing audio in a subprocess.
1131
1132        @param audio_data: the audio test data
1133        @param recording_device: which device recorded the audio,
1134                possible values are 'recorded_by_dut' or 'recorded_by_peer'
1135
1136        @returns: True on success. False otherwise.
1137        """
1138        return self._proxy.start_capturing_audio_subprocess(
1139                json.dumps(audio_data), recording_device)
1140
1141
1142    @proxy_thread_safe
1143    def stop_capturing_audio_subprocess(self):
1144        """Stop capturing audio.
1145
1146        @returns: True on success. False otherwise.
1147        """
1148        return self._proxy.stop_capturing_audio_subprocess()
1149
1150
1151    @proxy_thread_safe
1152    def start_playing_audio_subprocess(self, audio_data, pin_device=None):
1153        """Start playing audio in a subprocess.
1154
1155        @param audio_data: the audio test data.
1156        @param pin_device: the device id to play audio.
1157
1158        @returns: True on success. False otherwise.
1159        """
1160        audio_data = json.dumps(audio_data)
1161        return self._proxy.start_playing_audio_subprocess(
1162                audio_data, pin_device)
1163
1164
1165    @proxy_thread_safe
1166    def stop_playing_audio_subprocess(self):
1167        """Stop playing audio in the subprocess.
1168
1169        @returns: True on success. False otherwise.
1170        """
1171        return self._proxy.stop_playing_audio_subprocess()
1172
1173
1174    @proxy_thread_safe
1175    def play_audio(self, audio_data):
1176        """Play audio.
1177
1178        It blocks until it has completed playing back the audio.
1179
1180        @param audio_data: the audio test data
1181
1182        @returns: True on success. False otherwise.
1183        """
1184        return self._proxy.play_audio(json.dumps(audio_data))
1185
1186
1187    @proxy_thread_safe
1188    def check_audio_frames_legitimacy(self, audio_test_data, recording_device,
1189                                      recorded_file):
1190        """Get the number of frames in the recorded audio file.
1191        @param audio_test_data: the audio test data
1192        @param recording_device: which device recorded the audio,
1193                possible values are 'recorded_by_dut' or 'recorded_by_peer'
1194        @param recorded_file: the recorded file name
1195
1196        @returns: True if audio frames are legitimate.
1197        """
1198        return self._proxy.check_audio_frames_legitimacy(
1199                json.dumps(audio_test_data), recording_device, recorded_file)
1200
1201
1202    @proxy_thread_safe
1203    def convert_audio_sample_rate(self, input_file, out_file, test_data,
1204                                  new_rate):
1205        """Convert audio file to new sample rate.
1206
1207        @param input_file: Path to file to upsample.
1208        @param out_file: Path to create upsampled file.
1209        @param test_data: Dictionary with information about file.
1210        @param new_rate: New rate to upsample file to.
1211
1212        @returns: True if upsampling succeeded, False otherwise.
1213        """
1214        return self._proxy.convert_audio_sample_rate(input_file, out_file,
1215                                                     json.dumps(test_data),
1216                                                     new_rate)
1217
1218
1219    @proxy_thread_safe
1220    def trim_wav_file(self, in_file, out_file, new_duration, test_data,
1221                      tolerance=0.1):
1222        """Trim long file to desired length.
1223
1224        Trims audio file to length by cutting out silence from beginning and
1225        end.
1226
1227        @param in_file: Path to audio file to be trimmed.
1228        @param out_file: Path to trimmed audio file to create.
1229        @param new_duration: A float representing the desired duration of
1230                the resulting trimmed file.
1231        @param test_data: Dictionary containing information about the test file.
1232        @param tolerance: (optional) A float representing the allowable
1233                difference between trimmed file length and desired duration
1234
1235        @returns: True if file was trimmed successfully, False otherwise.
1236        """
1237        return self._proxy.trim_wav_file(in_file, out_file, new_duration,
1238                                         json.dumps(test_data), tolerance)
1239
1240
1241    @proxy_thread_safe
1242    def unzip_audio_test_data(self, tar_path, data_dir):
1243        """Unzip audio test data files.
1244
1245        @param tar_path: Path to audio test data tarball on DUT.
1246        @oaram data_dir: Path to directory where to extract test data directory.
1247
1248        @returns: True if audio test data folder exists, False otherwise.
1249        """
1250        return self._proxy.unzip_audio_test_data(tar_path, data_dir)
1251
1252
1253    @proxy_thread_safe
1254    def convert_raw_to_wav(self, input_file, output_file, test_data):
1255        """Convert raw audio file to wav file.
1256
1257        @oaram input_file: The location of the raw file.
1258        @param output_file: The location to place the resulting wav file.
1259        @param test_data: The data for the file being converted.
1260
1261        @returns: True if conversion was successful, otherwise false.
1262        """
1263        return self._proxy.convert_raw_to_wav(input_file, output_file,
1264                                              json.dumps(test_data))
1265
1266
1267    @proxy_thread_safe
1268    def get_primary_frequencies(self, audio_test_data, recording_device,
1269                                recorded_file):
1270        """Get primary frequencies of the audio test file.
1271
1272        @param audio_test_data: the audio test data
1273        @param recording_device: which device recorded the audio,
1274                possible values are 'recorded_by_dut' or 'recorded_by_peer'
1275        @param recorded_file: the recorded file name
1276
1277        @returns: a list of primary frequencies of channels in the audio file
1278        """
1279        return self._proxy.get_primary_frequencies(
1280                json.dumps(audio_test_data), recording_device, recorded_file)
1281
1282
1283    @proxy_thread_safe
1284    def enable_wbs(self, value):
1285        """Enable or disable wideband speech (wbs) per the value.
1286
1287        @param value: True to enable wbs.
1288
1289        @returns: True if the operation succeeds.
1290        """
1291        logging.debug('%s wbs', 'enable' if value else 'disable')
1292        return self._proxy.enable_wbs(value)
1293
1294
1295    @proxy_thread_safe
1296    def set_player_playback_status(self, status):
1297        """Set playback status for the registered media player.
1298
1299        @param status: playback status in string.
1300
1301        """
1302        logging.debug('Set media player playback status to %s', status)
1303        return self._proxy.set_player_playback_status(status)
1304
1305
1306    @proxy_thread_safe
1307    def set_player_position(self, position):
1308        """Set media position for the registered media player.
1309
1310        @param position: position in micro seconds.
1311
1312        """
1313        logging.debug('Set media player position to %d', position)
1314        return self._proxy.set_player_position(position)
1315
1316
1317    @proxy_thread_safe
1318    def set_player_metadata(self, metadata):
1319        """Set metadata for the registered media player.
1320
1321        @param metadata: dictionary of media metadata.
1322
1323        """
1324        logging.debug('Set media player album:%s artist:%s title:%s',
1325                      metadata.get("album"), metadata.get("artist"),
1326                      metadata.get("title"))
1327        return self._proxy.set_player_metadata(metadata)
1328
1329
1330    @proxy_thread_safe
1331    def set_player_length(self, length):
1332        """Set media length for the registered media player.
1333
1334        @param length: length in micro seconds.
1335
1336        """
1337        logging.debug('Set media player length to %d', length)
1338        return self._proxy.set_player_length(length)
1339
1340
1341    @proxy_thread_safe
1342    def select_input_device(self, device_name):
1343        """Select the audio input device.
1344
1345        @param device_name: the name of the Bluetooth peer device
1346
1347        @returns: True if the operation succeeds.
1348        """
1349        return self._proxy.select_input_device(device_name)
1350
1351
1352    @proxy_thread_safe
1353    def select_output_node(self, node_type):
1354        """Select the audio output node.
1355
1356        @param node_type: the node type of the Bluetooth peer device
1357
1358        @returns: True if the operation succeeds.
1359        """
1360        return self._proxy.select_output_node(node_type)
1361
1362
1363    @proxy_thread_safe
1364    def get_selected_output_device_type(self):
1365        """Get the selected audio output node type.
1366
1367        @returns: the node type of the selected output device.
1368        """
1369        return self._proxy.get_selected_output_device_type()
1370
1371
1372    @proxy_thread_safe
1373    def read_characteristic(self, uuid, address):
1374        """Reads the value of a gatt characteristic.
1375
1376        Reads the current value of a gatt characteristic.
1377
1378        @param uuid: The uuid of the characteristic to read, as a string.
1379        @param address: The MAC address of the remote device.
1380
1381        @returns: A byte array containing the value of the if the uuid/address
1382                      was found in the object tree.
1383                  None if the uuid/address was not found in the object tree, or
1384                      if a DBus exception was raised by the read operation.
1385
1386        """
1387        value = self._proxy.read_characteristic(uuid, address)
1388        if value is None:
1389            return None
1390        return bytearray(base64.standard_b64decode(value))
1391
1392
1393    @proxy_thread_safe
1394    def write_characteristic(self, uuid, address, bytes_to_write):
1395        """Performs a write operation on a gatt characteristic.
1396
1397        Writes to a GATT characteristic on a remote device.
1398
1399        @param uuid: The uuid of the characteristic to write to, as a string.
1400        @param address: The MAC address of the remote device, as a string.
1401        @param bytes_to_write: A byte array containing the data to write.
1402
1403        @returns: True if the write operation does not raise an exception.
1404                  None if the uuid/address was not found in the object tree, or
1405                      if a DBus exception was raised by the write operation.
1406
1407        """
1408        return self._proxy.write_characteristic(
1409            uuid, address, base64.standard_b64encode(bytes_to_write))
1410
1411
1412    @proxy_thread_safe
1413    def exchange_messages(self, tx_object_path, rx_object_path, bytes_to_write):
1414        """Performs a write operation on a gatt characteristic and wait for
1415        the response on another characteristic.
1416
1417        @param tx_object_path: the object path of the characteristic to write.
1418        @param rx_object_path: the object path of the characteristic to read.
1419        @param value: A byte array containing the data to write.
1420
1421        @returns: The value of the characteristic to read from.
1422                  None if the uuid/address was not found in the object tree, or
1423                      if a DBus exception was raised by the write operation.
1424
1425        """
1426        return self._proxy.exchange_messages(
1427            tx_object_path, rx_object_path,
1428            base64.standard_b64encode(bytes_to_write))
1429
1430
1431    @proxy_thread_safe
1432    def start_notify(self, object_path, cccd_value):
1433        """Starts the notification session on the gatt characteristic.
1434
1435        @param object_path: the object path of the characteristic.
1436        @param cccd_value: Possible CCCD values include
1437               0x00 - inferred from the remote characteristic's properties
1438               0x01 - notification
1439               0x02 - indication
1440
1441        @returns: True if the operation succeeds.
1442                  False if the characteristic is not found, or
1443                      if a DBus exception was raised by the operation.
1444
1445        """
1446        return self._proxy.start_notify(object_path, cccd_value)
1447
1448
1449    @proxy_thread_safe
1450    def stop_notify(self, object_path):
1451        """Stops the notification session on the gatt characteristic.
1452
1453        @param object_path: the object path of the characteristic.
1454
1455        @returns: True if the operation succeeds.
1456                  False if the characteristic is not found, or
1457                      if a DBus exception was raised by the operation.
1458
1459        """
1460        return self._proxy.stop_notify(object_path)
1461
1462
1463    @proxy_thread_safe
1464    def is_notifying(self, object_path):
1465        """Is the GATT characteristic in a notifying session?
1466
1467        @param object_path: the object path of the characteristic.
1468
1469        @return True if it is in a notification session. False otherwise.
1470
1471        """
1472        return self._proxy.is_notifying(object_path)
1473
1474
1475    @proxy_thread_safe
1476    def is_characteristic_path_resolved(self, uuid, address):
1477        """Checks whether a characteristic is in the object tree.
1478
1479        Checks whether a characteristic is curently found in the object tree.
1480
1481        @param uuid: The uuid of the characteristic to search for.
1482        @param address: The MAC address of the device on which to search for
1483            the characteristic.
1484
1485        @returns: True if the characteristic is found, False otherwise.
1486
1487        """
1488        return self._proxy.is_characteristic_path_resolved(uuid, address)
1489
1490
1491    @proxy_thread_safe
1492    def get_gatt_attributes_map(self, address):
1493        """Return a JSON formated string of the GATT attributes of a device,
1494        keyed by UUID
1495        @param address: a string of the MAC address of the device
1496
1497        @return: JSON formated string, stored the nested structure of the
1498        attributes. Each attribute has 'path' and ['chrcs' | 'descs'], which
1499        store their object path and children respectively.
1500        """
1501        return self._proxy.get_gatt_attributes_map(address)
1502
1503
1504    @proxy_thread_safe
1505    def get_gatt_service_property(self, object_path, property_name):
1506        """Get property from a service attribute
1507        @param object_path: a string of the object path of the service
1508        @param property_name: a string of a property, ex: 'Value', 'UUID'
1509
1510        @return: the property if success,
1511                 None otherwise
1512        """
1513        return self._proxy.get_gatt_service_property(object_path, property_name)
1514
1515
1516    @proxy_thread_safe
1517    def get_gatt_characteristic_property(self, object_path, property_name):
1518        """Get property from a characteristic attribute
1519        @param object_path: a string of the object path of the characteristic
1520        @param property_name: a string of a property, ex: 'Value', 'UUID'
1521
1522        @return: the property if success,
1523                 None otherwise
1524        """
1525        return self._proxy.get_gatt_characteristic_property(object_path,
1526                                                            property_name)
1527
1528
1529    @proxy_thread_safe
1530    def get_gatt_descriptor_property(self, object_path, property_name):
1531        """Get property from a descriptor attribute
1532        @param object_path: a string of the object path of the descriptor
1533        @param property_name: a string of a property, ex: 'Value', 'UUID'
1534
1535        @return: the property if success,
1536                 None otherwise
1537        """
1538        return self._proxy.get_gatt_descriptor_property(object_path,
1539                                                        property_name)
1540
1541
1542    @proxy_thread_safe
1543    def gatt_characteristic_read_value(self, uuid, object_path):
1544        """Perform method ReadValue on a characteristic attribute
1545        @param uuid: a string of uuid
1546        @param object_path: a string of the object path of the characteristic
1547
1548        @return: base64 string of dbus bytearray
1549        """
1550        return self._proxy.gatt_characteristic_read_value(uuid, object_path)
1551
1552
1553    @proxy_thread_safe
1554    def gatt_descriptor_read_value(self, uuid, object_path):
1555        """Perform method ReadValue on a descriptor attribute
1556        @param uuid: a string of uuid
1557        @param object_path: a string of the object path of the descriptor
1558
1559        @return: base64 string of dbus bytearray
1560        """
1561        return self._proxy.gatt_descriptor_read_value(uuid, object_path)
1562
1563
1564    @proxy_thread_safe
1565    def get_gatt_object_path(self, address, uuid):
1566        """Get property from a characteristic attribute
1567
1568        @param address: The MAC address of the remote device.
1569        @param uuid: The uuid of the attribute.
1570
1571        @return: the object path of the attribute if success,
1572                 none otherwise
1573
1574        """
1575        return self._proxy.get_gatt_object_path(address, uuid)
1576
1577
1578    def copy_logs(self, destination):
1579        """Copy the logs generated by this device to a given location.
1580
1581        @param destination: destination directory for the logs.
1582
1583        """
1584        self.host.collect_logs(self.XMLRPC_LOG_PATH, destination)
1585
1586
1587    @proxy_thread_safe
1588    def get_connection_info(self, address):
1589        """Get device connection info.
1590
1591        @param address: The MAC address of the device.
1592
1593        @returns: On success, a tuple of:
1594                      ( RSSI, transmit_power, max_transmit_power )
1595                  None otherwise.
1596
1597        """
1598        return self._proxy.get_connection_info(address)
1599
1600
1601    @proxy_thread_safe
1602    def set_discovery_filter(self, filter):
1603        """Set the discovery filter.
1604
1605        @param filter: The discovery filter to set.
1606
1607        @return True on success, False otherwise.
1608
1609        """
1610        return self._proxy.set_discovery_filter(filter)
1611
1612
1613    @proxy_thread_safe
1614    def set_le_connection_parameters(self, address, parameters):
1615        """Set the LE connection parameters.
1616
1617        @param address: The MAC address of the device.
1618        @param parameters: The LE connection parameters to set.
1619
1620        @return: True on success. False otherwise.
1621
1622        """
1623        return self._proxy.set_le_connection_parameters(address, parameters)
1624
1625
1626    @proxy_thread_safe
1627    def wait_for_hid_device(self,
1628                            device_address,
1629                            timeout=None,
1630                            sleep_interval=None):
1631        """Wait for hid device with given device address.
1632
1633        Args:
1634            device_address: Peripheral Address
1635            timeout: maximum number of seconds to wait
1636            sleep_interval: time to sleep between polls
1637
1638        Returns:
1639            True if hid device is found.
1640        """
1641        return self._proxy.wait_for_hid_device(device_address, timeout,
1642                                               sleep_interval)
1643
1644
1645    @proxy_thread_safe
1646    def bt_caused_last_resume(self):
1647        """Checks if last resume from suspend was caused by bluetooth
1648
1649        @return: True if BT wake path was cause of resume, False otherwise
1650        """
1651
1652        return self._proxy.bt_caused_last_resume()
1653
1654    @proxy_thread_safe
1655    def find_last_suspend_via_powerd_logs(self):
1656        """Finds the last suspend attempt via powerd logs.
1657
1658        @return: Tuple (suspend start time, suspend end time, suspend result) or
1659                 None
1660        """
1661        info = self._proxy.find_last_suspend_via_powerd_logs()
1662
1663        # Currently, we get the date back in string format due to python2/3
1664        # inconsistencies. We can get rid of this once everything is running
1665        # python3 (hopefully)
1666        # TODO - Revisit converting date to string and back in this method
1667        if info:
1668            start_date = datetime.strptime(info[0], self.STANDARD_DATE_FORMAT)
1669            end_date = datetime.strptime(info[1], self.STANDARD_DATE_FORMAT)
1670            ret = info[2]
1671
1672            return (start_date, end_date, ret)
1673
1674        return None
1675
1676    @proxy_thread_safe
1677    def do_suspend(self, seconds, expect_bt_wake):
1678        """Suspend DUT using the power manager.
1679
1680        @param seconds: The number of seconds to suspend the device.
1681        @param expect_bt_wake: Whether we expect bluetooth to wake us from
1682            suspend. If true, we expect this resume will occur early
1683        """
1684
1685        # Do not retry this RPC if it fails or times out
1686        return self._proxy.do_suspend(seconds, expect_bt_wake, __no_retry=True)
1687
1688
1689    @proxy_thread_safe
1690    def get_wlan_vid_pid(self):
1691        """ Return vendor id and product id of the wlan chip on BT/WiFi module
1692
1693        @returns: (vid,pid) on success; (None,None) on failure
1694        """
1695        return self._proxy.get_wlan_vid_pid()
1696
1697    @proxy_thread_safe
1698    def get_bt_transport(self):
1699        """ Return the transport used by Bluetooth module
1700
1701        @returns: USB/UART/SDIO on success; None on failure
1702        """
1703        return self._proxy.get_bt_transport()
1704
1705    @proxy_thread_safe
1706    def get_bt_module_name(self):
1707        """ Return bluetooth module name for non-USB devices
1708
1709        @returns: Name of the Bluetooth module (or string read from device on
1710                  success); '' on failure
1711        """
1712        return self._proxy.get_bt_module_name()
1713
1714    @proxy_thread_safe
1715    def get_chipset_name(self):
1716        """ Get the name of BT/WiFi chipset on this host
1717
1718        @returns chipset name if successful else ''
1719        """
1720        return self._proxy.get_chipset_name()
1721
1722    @proxy_thread_safe
1723    def get_device_utc_time(self):
1724        """ Get the current device time in UTC. """
1725        return datetime.strptime(self._proxy.get_device_utc_time(),
1726                                 self.STANDARD_DATE_FORMAT)
1727
1728    @proxy_thread_safe
1729    def get_bt_usb_disconnect_str(self):
1730        """ Return the expected log error on USB disconnect
1731
1732        Locate the descriptor that will be used from the list of all usb
1733        descriptors associated with our bluetooth chip, and format into the
1734        expected string error for USB disconnect
1735
1736        @returns: string representing expected usb disconnect log entry if usb
1737                  device could be identified, None otherwise
1738        """
1739        return self._proxy.get_bt_usb_disconnect_str()
1740
1741    @proxy_thread_safe
1742    def close(self, close_host=True):
1743        """Tear down state associated with the client.
1744
1745        @param close_host: If True, shut down the xml rpc server by closing the
1746            underlying host object (which also shuts down all other xml rpc
1747            servers running on the DUT). Otherwise, only shut down the
1748            bluetooth device xml rpc server, which can be desirable if the host
1749            object and/or other xml rpc servers need to be used afterwards.
1750        """
1751        # Turn off the discoverable flag since it may affect future tests.
1752        self._proxy.set_discoverable(False)
1753        # Reset the adapter and leave it on.
1754        self._proxy.reset_on()
1755        # This kills the RPC server.
1756        if close_host:
1757            self.host.close()
1758        elif hasattr(self, '_bt_direct_proxy'):
1759            self.host.rpc_server_tracker.disconnect(
1760                    constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT)
1761
1762
1763    @proxy_thread_safe
1764    def policy_get_service_allow_list(self):
1765        """Get the service allow list for enterprise policy.
1766
1767        @returns: array of strings representing the allowed service UUIDs.
1768        """
1769        return self._proxy.policy_get_service_allow_list()
1770
1771
1772    @proxy_thread_safe
1773    def policy_set_service_allow_list(self, uuids):
1774        """Get the service allow list for enterprise policy.
1775
1776        @param uuids: a string representing the uuids
1777                      e.g., "0x1234,0xabcd" or ""
1778
1779        @returns: (True, '') on success, (False, '<error>') on failure
1780        """
1781        return self._proxy.policy_set_service_allow_list(uuids)
1782
1783    @proxy_thread_safe
1784    def policy_get_device_affected(self, device_address):
1785        """Get if the device is affected by enterprise policy.
1786
1787        @param device_address: address of the device
1788                               e.g. '6C:29:95:1A:D4:6F'
1789
1790        @returns: True if the device is affected by the enterprise policy.
1791                  False if not. None if the device is not found.
1792        """
1793        return self._proxy.policy_get_device_affected(device_address)
1794