aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-04-01 04:31:00 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-04-01 04:31:00 +0000
commit3736d4423c481118739ae088724d3486bfabc474 (patch)
tree159b057396bd4080d67276a27aca60da708bf1b2
parent62c4f640f6684d9c004e8c613296a1b19330d18f (diff)
parent4fc0c5a969e7c50732d908a77ba6e0ed71c28f58 (diff)
downloadavatar-android14-d1-s7-release.tar.gz
Change-Id: I0967d73d4b1a5786735e8587c9dc46cb16876ace
-rw-r--r--avatar/bumble_server/__init__.py3
-rw-r--r--avatar/bumble_server/asha.py42
-rw-r--r--avatar/bumble_server/host.py6
-rw-r--r--avatar/bumble_server/security.py39
-rw-r--r--avatar/pandora_client.py23
5 files changed, 40 insertions, 73 deletions
diff --git a/avatar/bumble_server/__init__.py b/avatar/bumble_server/__init__.py
index c903154..184968f 100644
--- a/avatar/bumble_server/__init__.py
+++ b/avatar/bumble_server/__init__.py
@@ -22,11 +22,9 @@ import grpc.aio
import logging
from avatar.bumble_device import BumbleDevice
-from avatar.bumble_server.asha import ASHAService
from avatar.bumble_server.host import HostService
from avatar.bumble_server.security import SecurityService, SecurityStorageService
from bumble.smp import PairingDelegate
-from pandora.asha_grpc_aio import add_ASHAServicer_to_server
from pandora.host_grpc_aio import add_HostServicer_to_server
from pandora.security_grpc_aio import add_SecurityServicer_to_server, add_SecurityStorageServicer_to_server
from typing import Callable, List, Optional
@@ -54,7 +52,6 @@ async def serve_bumble(bumble: BumbleDevice, grpc_server: Optional[grpc.aio.Serv
add_HostServicer_to_server(HostService(server, bumble.device), server)
add_SecurityServicer_to_server(SecurityService(bumble.device, io_capability), server)
add_SecurityStorageServicer_to_server(SecurityStorageService(bumble.device), server)
- add_ASHAServicer_to_server(ASHAService(bumble.device), server)
# call hooks if any.
for hook in _SERVICERS_HOOKS:
diff --git a/avatar/bumble_server/asha.py b/avatar/bumble_server/asha.py
deleted file mode 100644
index fdea220..0000000
--- a/avatar/bumble_server/asha.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2022 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import grpc
-import logging
-
-from . import utils
-from bumble.device import Device
-from bumble.profiles.asha_service import AshaService
-from google.protobuf.empty_pb2 import Empty # pytype: disable=pyi-error
-from pandora.asha_grpc_aio import ASHAServicer
-from pandora.asha_pb2 import RegisterRequest
-from typing import Optional
-
-
-class ASHAService(ASHAServicer):
- device: Device
- asha_service: Optional[AshaService]
-
- def __init__(self, device: Device) -> None:
- self.log = utils.BumbleServerLoggerAdapter(logging.getLogger(), {'service_name': 'Asha', 'device': device})
- self.device = device
- self.asha_service = None
-
- @utils.rpc
- async def Register(self, request: RegisterRequest, context: grpc.ServicerContext) -> Empty:
- self.log.info('Register')
- # asha service from bumble profile
- self.asha_service = AshaService(request.capability, request.hisyncid, self.device)
- self.device.add_service(self.asha_service) # type: ignore[no-untyped-call]
- return Empty()
diff --git a/avatar/bumble_server/host.py b/avatar/bumble_server/host.py
index 5f84d41..d9d6e4a 100644
--- a/avatar/bumble_server/host.py
+++ b/avatar/bumble_server/host.py
@@ -520,14 +520,14 @@ class HostService(HostServicer):
ad_structures.append(
(
AdvertisingData.INCOMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
- b''.join([uuid128_from_str(uuid) for uuid in uuids])
+ b''.join([uuid128_from_str(uuid) for uuid in uuids]),
)
)
if uuids := dt.complete_service_class_uuids128:
ad_structures.append(
(
AdvertisingData.COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS,
- b''.join([uuid128_from_str(uuid) for uuid in uuids])
+ b''.join([uuid128_from_str(uuid) for uuid in uuids]),
)
)
if dt.HasField('include_shortened_local_name'):
@@ -583,7 +583,7 @@ class HostService(HostServicer):
ad_structures.append(
(
AdvertisingData.LIST_OF_128_BIT_SERVICE_SOLICITATION_UUIDS,
- b''.join([uuid128_from_str(uuid) for uuid in uuids])
+ b''.join([uuid128_from_str(uuid) for uuid in uuids]),
)
)
if datas := dt.service_data_uuid16:
diff --git a/avatar/bumble_server/security.py b/avatar/bumble_server/security.py
index 4b8cf1b..000d49f 100644
--- a/avatar/bumble_server/security.py
+++ b/avatar/bumble_server/security.py
@@ -85,46 +85,67 @@ class PairingDelegate(BasePairingDelegate):
async def confirm(self) -> bool:
self.log.info(f"Pairing event: `just_works` (io_capability: {self.io_capability})")
- if not self.service.event_queue or not self.service.event_answer:
+ if self.service.event_queue is None or self.service.event_answer is None:
return True
event = self.add_origin(PairingEvent(just_works=empty_pb2.Empty()))
self.service.event_queue.put_nowait(event)
answer = await anext(self.service.event_answer) # pytype: disable=name-error
assert answer.event == event
- assert answer.confirm
+ assert answer.answer_variant() == 'confirm' and answer.confirm is not None
return answer.confirm
async def compare_numbers(self, number: int, digits: int = 6) -> bool:
self.log.info(f"Pairing event: `numeric_comparison` (io_capability: {self.io_capability})")
- if not self.service.event_queue or not self.service.event_answer:
+ if self.service.event_queue is None or self.service.event_answer is None:
raise RuntimeError('security: unhandled number comparison request')
event = self.add_origin(PairingEvent(numeric_comparison=number))
self.service.event_queue.put_nowait(event)
answer = await anext(self.service.event_answer) # pytype: disable=name-error
assert answer.event == event
- assert answer.confirm
+ assert answer.answer_variant() == 'confirm' and answer.confirm is not None
return answer.confirm
- async def get_number(self) -> int:
+ async def get_number(self) -> Optional[int]:
self.log.info(f"Pairing event: `passkey_entry_request` (io_capability: {self.io_capability})")
- if not self.service.event_queue or not self.service.event_answer:
+ if self.service.event_queue is None or self.service.event_answer is None:
raise RuntimeError('security: unhandled number request')
event = self.add_origin(PairingEvent(passkey_entry_request=empty_pb2.Empty()))
self.service.event_queue.put_nowait(event)
answer = await anext(self.service.event_answer) # pytype: disable=name-error
assert answer.event == event
- assert answer.passkey is not None
+ assert answer.answer_variant() == 'passkey'
return answer.passkey
+ async def get_string(self, max_length: int) -> Optional[str]:
+ self.log.info(f"Pairing event: `pin_code_request` (io_capability: {self.io_capability})")
+
+ if self.service.event_queue is None or self.service.event_answer is None:
+ raise RuntimeError('security: unhandled pin_code request')
+
+ event = self.add_origin(PairingEvent(pin_code_request=empty_pb2.Empty()))
+ self.service.event_queue.put_nowait(event)
+ answer = await anext(self.service.event_answer) # pytype: disable=name-error
+ assert answer.event == event
+ assert answer.answer_variant() == 'pin'
+
+ if answer.pin is None:
+ return None
+
+ pin = answer.pin.decode('utf-8')
+ if not pin or len(pin) > max_length:
+ raise ValueError(f'Pin must be utf-8 encoded up to {max_length} bytes')
+
+ return pin
+
async def display_number(self, number: int, digits: int = 6) -> None:
self.log.info(f"Pairing event: `passkey_entry_notification` (io_capability: {self.io_capability})")
- if not self.service.event_queue:
+ if self.service.event_queue is None:
raise RuntimeError('security: unhandled number display request')
event = self.add_origin(PairingEvent(passkey_entry_notification=number))
@@ -181,7 +202,7 @@ class SecurityService(SecurityServicer):
) -> AsyncGenerator[PairingEvent, None]:
self.log.info('OnPairing')
- if self.event_queue:
+ if self.event_queue is not None:
raise RuntimeError('already streaming pairing events')
if len(self.device.connections):
diff --git a/avatar/pandora_client.py b/avatar/pandora_client.py
index cdeec07..548e6d1 100644
--- a/avatar/pandora_client.py
+++ b/avatar/pandora_client.py
@@ -26,7 +26,7 @@ import logging
from avatar.bumble_device import BumbleDevice
from bumble.hci import Address as BumbleAddress
from dataclasses import dataclass
-from pandora import asha_grpc, asha_grpc_aio, host_grpc, host_grpc_aio, security_grpc, security_grpc_aio
+from pandora import host_grpc, host_grpc_aio, security_grpc, security_grpc_aio
from typing import Any, Dict, MutableMapping, Optional, Tuple, Union
@@ -110,11 +110,12 @@ class PandoraClient:
)
return
except grpc.aio.AioRpcError as e:
- if attempts <= max_attempts and e.code() == grpc.StatusCode.UNAVAILABLE:
- self.log.debug(f'Server unavailable, retry [{attempts}/{max_attempts}].')
- attempts += 1
- continue
- self.log.exception(f'Server still unavailable after {attempts} attempts, abort.')
+ if e.code() in (grpc.StatusCode.UNAVAILABLE, grpc.StatusCode.DEADLINE_EXCEEDED):
+ if attempts <= max_attempts:
+ self.log.debug(f'Server unavailable, retry [{attempts}/{max_attempts}].')
+ attempts += 1
+ continue
+ self.log.exception(f'Server still unavailable after {attempts} attempts, abort.')
raise e
@property
@@ -143,11 +144,6 @@ class PandoraClient:
"""Returns the Pandora SecurityStorage gRPC interface."""
return security_grpc.SecurityStorage(self.channel)
- @property
- def asha(self) -> asha_grpc.ASHA:
- """Returns the Pandora ASHA gRPC interface."""
- return asha_grpc.ASHA(self.channel)
-
@dataclass
class Aio:
channel: grpc.aio.Channel
@@ -167,11 +163,6 @@ class PandoraClient:
"""Returns the Pandora SecurityStorage gRPC interface."""
return security_grpc_aio.SecurityStorage(self.channel)
- @property
- def asha(self) -> asha_grpc_aio.ASHA:
- """Returns the Pandora ASHA gRPC interface."""
- return asha_grpc_aio.ASHA(self.channel)
-
@property
def aio(self) -> 'PandoraClient.Aio':
if not self._aio: