blob: bad665a504912715530010707e5a31c1f14c4d2e [file] [log] [blame]
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from autotest_lib.client.common_lib import error
from autotest_lib.server.cros.bluetooth import bluetooth_test
class bluetooth_SDP_ServiceBrowse(bluetooth_test.BluetoothTest):
"""
Verify that the IUT behave correct during Service Browse procedure.
"""
version = 1
MAX_REC_CNT = 100
MAX_ATTR_BYTE_CNT = 300
PUBLIC_BROWSE_ROOT = 0x1002
SERVICE_CLASS_ID_LIST = 0x0001
BROWSE_GROUP_DESCRIPTOR = 0x1001
GROUP_ID = 0x0200
def get_attribute_ssr_sar(self, class_id, attr_id, size):
"""Get service attributes using Service Search Request and Service
Attribute Request.
@param class_id: Class ID of service to check.
@param attr_id: ID of attribute to check.
@param size: Preferred size of UUID.
@return attribute value if attribute exists, None otherwise
"""
handles = self.tester.service_search_request(
[class_id], self.MAX_REC_CNT, size)
if not (isinstance(handles, list) and len(handles) > 0):
return None
res = []
for record_handle in handles:
value = self.tester.service_attribute_request(
record_handle, self.MAX_ATTR_BYTE_CNT, [attr_id])
if not (isinstance(value, list) and len(value) == 2 and
value[0] == attr_id):
return None
res.append(value[1])
return res
def get_attribute_ssar(self, class_id, attr_id, size):
"""Get service attributes using Service Search Attribute Request.
@param class_id: Class ID of service to check.
@param attr_id: ID of attribute to check.
@param size: Preferred size of UUID.
@return attribute value if attribute exists, None otherwise
"""
response = self.tester.service_search_attribute_request(
[class_id], self.MAX_ATTR_BYTE_CNT, [attr_id], size)
if not isinstance(response, list):
return None
res = []
for elem in response:
if not (isinstance(elem, list) and len(elem) == 2 and
elem[0] == attr_id):
return None
res.append(elem[1])
return res
def test_attribute(self, class_id, attr_id, get_attribute):
"""Test service attributes using 16-bit, 32-bit and 128-bit
size of UUID.
@param class_id: Class ID of service to check.
@param attr_id: ID of attribute to check.
@param get_attribute: Method to use to get an attribute value.
@return attribute value if attribute exists and values from three tests
are equal, None otherwise
"""
result_16 = get_attribute(class_id, attr_id, 16)
for size in 32, 128:
result_cur = get_attribute(class_id, attr_id, size)
if result_16 != result_cur:
return None
return result_16
def service_browse(self, get_attribute):
"""Execute a Service Browse procedure.
@param get_attribute: Method to use to get an attribute value.
@return sorted list of unique services on the DUT, or False if browse
did not finish correctly
"""
# Find services on top of hierarchy.
root_services = self.test_attribute(self.PUBLIC_BROWSE_ROOT,
self.SERVICE_CLASS_ID_LIST,
get_attribute)
if not root_services:
return False
# Find additional browse groups.
group_ids = self.test_attribute(self.BROWSE_GROUP_DESCRIPTOR,
self.GROUP_ID,
get_attribute)
if not group_ids:
return False
# Find services from all browse groups.
all_services = []
for group_id in group_ids:
services = self.test_attribute(group_id,
self.SERVICE_CLASS_ID_LIST,
get_attribute)
if not services:
return False
all_services.extend(services)
# Ensure that root services are among all services.
for service in root_services:
if service not in all_services:
return False
# Sort all services and remove duplicates.
all_services.sort()
last = 0
for service in all_services[1:]:
if all_services[last] != service:
last += 1
all_services[last] = service
return all_services[:last + 1]
def correct_request(self):
"""Run basic tests for Service Browse procedure.
@return True if all tests finishes correctly, False otherwise
"""
# Connect to the DUT via L2CAP using SDP socket.
self.tester.connect(self.adapter['Address'])
browse_ssar = self.service_browse(self.get_attribute_ssar)
if not browse_ssar:
return False
browse_ssr_sar = self.service_browse(self.get_attribute_ssr_sar)
# Ensure that two different browse methods return the same results.
return browse_ssar == browse_ssr_sar
def run_once(self):
# Reset the adapter to the powered on, discoverable state.
if not (self.device.reset_on() and
self.device.set_discoverable(True)):
raise error.TestFail('DUT could not be reset to initial state')
self.adapter = self.device.get_adapter_properties()
# Setup the tester as a generic computer.
if not self.tester.setup('computer'):
raise error.TestFail('Tester could not be initialized')
# Since radio is involved, this test is not 100% reliable; instead we
# repeat a few times until it succeeds.
for failed_attempts in range(0, 5):
if self.correct_request():
break
else:
raise error.TestFail('Expected device was not found')
# Record how many attempts this took, hopefully we'll one day figure out
# a way to reduce this to zero and then the loop above can go away.
self.write_perf_keyval({'failed_attempts': failed_attempts })