1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.uwb.discovery; 17 18 import android.annotation.IntRange; 19 import android.util.Log; 20 21 import androidx.annotation.NonNull; 22 23 import com.android.server.uwb.discovery.info.AdminErrorMessage; 24 import com.android.server.uwb.discovery.info.AdminErrorMessage.ErrorType; 25 import com.android.server.uwb.discovery.info.AdminEventMessage; 26 import com.android.server.uwb.discovery.info.AdminEventMessage.EventType; 27 import com.android.server.uwb.discovery.info.FiraConnectorMessage; 28 import com.android.server.uwb.discovery.info.FiraConnectorMessage.InstructionCode; 29 import com.android.server.uwb.discovery.info.FiraConnectorMessage.MessageType; 30 31 import java.nio.ByteBuffer; 32 33 /** Abstract class for Transport Provider */ 34 public abstract class TransportProvider implements Transport { 35 private static final String TAG = TransportProvider.class.getSimpleName(); 36 37 public enum TerminationReason { 38 /** Disconnection of the remote GATT service. */ 39 REMOTE_DISCONNECTED, 40 /** remote GATT service discovery failure. */ 41 SERVICE_DISCOVERY_FAILURE, 42 /** Characterstic read failure */ 43 CHARACTERSTIC_READ_FAILURE, 44 /** Characterstic write failure */ 45 CHARACTERSTIC_WRITE_FAILURE, 46 /** Descriptor write failure */ 47 DESCRIPTOR_WRITE_FAILURE, 48 /** Remote device message error */ 49 REMOTE_DEVICE_MESSAGE_ERROR, 50 /** Remote device SECID error */ 51 REMOTE_DEVICE_SECID_ERROR, 52 } 53 54 /** Callback for listening to transport events. */ 55 public interface TransportCallback { 56 57 /** Called when the transport started processing. */ onProcessingStarted()58 void onProcessingStarted(); 59 60 /** Called when the transport stopped processing. */ onProcessingStopped()61 void onProcessingStopped(); 62 63 /** 64 * Called when the transport terminated the connection due to an unrecoverable errors. 65 * 66 * @param reason indicates the termination reason. 67 */ onTerminated(TerminationReason reason)68 void onTerminated(TerminationReason reason); 69 } 70 71 /** 72 * administrative SECID shall be exposed on each CS implementation at all times. It shall be 73 * marked as static. 74 */ 75 public static final int ADMIN_SECID = 1; 76 77 private DataReceiver mDataReceiver; 78 79 /** Assigned SECID value (unsigned integer in the range 2..127, values 0 and 1 are reserved). */ 80 private int mSecid = 2; 81 82 /** 83 * Remote device SECID value (unsigned integer in the range 2..127, values 0 and 1 are 84 * reserved). 85 */ 86 private int mDestinationSecid = 2; 87 88 /** Wraps Fira Connector Message byte array and the associated SECID. */ 89 public static class MessagePacket { 90 public final int secid; 91 public ByteBuffer messageBytes; 92 MessagePacket(int secid, ByteBuffer messageBytes)93 public MessagePacket(int secid, ByteBuffer messageBytes) { 94 this.secid = secid; 95 this.messageBytes = messageBytes; 96 } 97 } 98 TransportProvider(@ntRangefrom = 2, to = 127) int secid)99 protected TransportProvider(@IntRange(from = 2, to = 127) int secid) { 100 mSecid = secid; 101 } 102 103 /** 104 * Set the Destination SECID on the Remote device. 105 * 106 * @param secid 7-bit secure component ID. 107 */ setDestinationSecid(@ntRangefrom = 2, to = 127) int secid)108 public void setDestinationSecid(@IntRange(from = 2, to = 127) int secid) { 109 mDestinationSecid = secid; 110 } 111 112 @Override sendData( MessageType messageType, @NonNull byte[] data, SendingDataCallback sendingDataCallback)113 public void sendData( 114 MessageType messageType, 115 @NonNull byte[] data, 116 SendingDataCallback sendingDataCallback) { 117 if (sendMessage( 118 mDestinationSecid, 119 new FiraConnectorMessage( 120 messageType, 121 /*Default instrcution code for message exchange.*/ 122 InstructionCode.DATA_EXCHANGE, 123 data))) { 124 sendingDataCallback.onSuccess(); 125 } else { 126 sendingDataCallback.onFailure(); 127 } 128 } 129 130 @Override registerDataReceiver(DataReceiver dataReceiver)131 public void registerDataReceiver(DataReceiver dataReceiver) { 132 if (mDataReceiver != null) { 133 Log.w(TAG, "Already has a registered data receiver."); 134 return; 135 } 136 mDataReceiver = dataReceiver; 137 } 138 139 @Override unregisterDataReceiver()140 public void unregisterDataReceiver() { 141 mDataReceiver = null; 142 } 143 144 /* Indicates whether the server has started. 145 */ 146 protected boolean mStarted = false; 147 148 /** 149 * Checks if the server has started. 150 * 151 * @return indicates if the server has started. 152 */ isStarted()153 public boolean isStarted() { 154 return mStarted; 155 } 156 157 /** 158 * Starts the transport. 159 * 160 * @return indicates if successfully started. 161 */ start()162 public boolean start() { 163 if (isStarted()) { 164 Log.i(TAG, "Transport already started."); 165 return false; 166 } 167 return true; 168 } 169 170 /** 171 * Stops the transport. 172 * 173 * @return indicates if successfully stopped. 174 */ stop()175 public boolean stop() { 176 if (!isStarted()) { 177 Log.i(TAG, "Transport already stopped."); 178 return false; 179 } 180 return true; 181 } 182 183 /** 184 * Send a FiRa connector message to the remote device through the transport. 185 * 186 * @param secid destination SECID on remote device. 187 * @param message message to be send. 188 * @return indicates if successfully started. 189 */ sendMessage(int secid, FiraConnectorMessage message)190 public abstract boolean sendMessage(int secid, FiraConnectorMessage message); 191 192 /** 193 * Called when the client received a new FiRa connector message from the remote device. 194 * 195 * @param secid destination SECID on this device. 196 * @param message FiRa connector message. 197 */ onMessageReceived(int secid, FiraConnectorMessage message)198 protected void onMessageReceived(int secid, FiraConnectorMessage message) { 199 if (secid == ADMIN_SECID) { 200 processAdminMessage(message); 201 return; 202 } 203 if (secid != mSecid) { 204 Log.w( 205 TAG, 206 "onMessageReceived rejected due to invalid SECID. Expect:" 207 + mSecid 208 + " Received:" 209 + secid); 210 sentAdminErrorMessage(ErrorType.SECID_INVALID); 211 return; 212 } 213 if (mDataReceiver != null) { 214 mDataReceiver.onDataReceived(message.payload); 215 } 216 } 217 218 /** 219 * Send a FiRa OOB administrative Error message to the administrative SECID on the remote 220 * device. 221 * 222 * @param errorType ErrorType of the message. 223 */ sentAdminErrorMessage(ErrorType errorType)224 protected void sentAdminErrorMessage(ErrorType errorType) { 225 if (!sendMessage(ADMIN_SECID, new AdminErrorMessage(errorType))) { 226 Log.w(TAG, "sentAdminErrorMessage with ErrorType:" + errorType + " failed."); 227 } 228 } 229 230 /** 231 * Send a FiRa OOB administrative Event message to the administrative SECID on the remote 232 * device. 233 * 234 * @param eventType EventType of the message. 235 * @param additionalData additional data associated with the event. 236 */ sentAdminEventMessage(EventType eventType, byte[] additionalData)237 protected void sentAdminEventMessage(EventType eventType, byte[] additionalData) { 238 if (!sendMessage(ADMIN_SECID, new AdminEventMessage(eventType, additionalData))) { 239 Log.w(TAG, "sentAdminEventMessage with EventType:" + eventType + " failed."); 240 } 241 } 242 243 /** 244 * Process FiRa OOB administrative message from the remote device. 245 * 246 * @param message FiRa connector message. 247 */ processAdminMessage(FiraConnectorMessage message)248 private void processAdminMessage(FiraConnectorMessage message) { 249 if (AdminErrorMessage.isAdminErrorMessage(message)) { 250 AdminErrorMessage errorMessage = AdminErrorMessage.convertToAdminErrorMessage(message); 251 Log.w(TAG, "Received AdminErrorMessage:" + errorMessage); 252 switch (errorMessage.errorType) { 253 case DATA_PACKET_LENGTH_OVERFLOW: 254 case MESSAGE_LENGTH_OVERFLOW: 255 case TOO_MANY_CONCURRENT_FRAGMENTED_MESSAGE_SESSIONS: 256 terminateOnError(TerminationReason.REMOTE_DEVICE_MESSAGE_ERROR); 257 break; 258 case SECID_INVALID: 259 case SECID_INVALID_FOR_RESPONSE: 260 case SECID_BUSY: 261 case SECID_PROTOCOL_ERROR: 262 case SECID_INTERNAL_ERROR: 263 terminateOnError(TerminationReason.REMOTE_DEVICE_SECID_ERROR); 264 break; 265 } 266 } else if (AdminEventMessage.isAdminEventMessage(message)) { 267 AdminEventMessage eventMessage = AdminEventMessage.convertToAdminEventMessage(message); 268 Log.w(TAG, "Received AdminEventMessage:" + eventMessage); 269 switch (eventMessage.eventType) { 270 case CAPABILITIES_CHANGED: 271 // No-op since this is only applicatble for CS with the role of GATT Server, 272 // which isn't mandated by FiRa. 273 break; 274 } 275 } else { 276 Log.e(TAG, "Invalid Admin FiraConnectorMessage received:" + message); 277 } 278 } 279 280 /** 281 * Terminates the transport provider. 282 * 283 * @param reason reason for the termination. 284 */ terminateOnError(TerminationReason reason)285 protected abstract void terminateOnError(TerminationReason reason); 286 } 287