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