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 17 package com.android.server.uwb.secure; 18 19 import android.os.Handler; 20 import android.os.Looper; 21 import android.util.Log; 22 23 import androidx.annotation.NonNull; 24 25 import com.android.server.uwb.pm.RunningProfileSessionInfo; 26 import com.android.server.uwb.secure.csml.CsmlUtil; 27 import com.android.server.uwb.secure.csml.DispatchResponse; 28 import com.android.server.uwb.secure.csml.SessionData; 29 30 import java.util.Optional; 31 32 /** 33 * Interface for a Dynamic STS session, which set up secure channel and exchange 34 * the UWB parameters. 35 */ 36 public abstract class SecureSession { 37 private static final String LOG_TAG = "SecureSession"; 38 39 protected final Handler mWorkHandler; 40 protected final FiRaSecureChannel mFiRaSecureChannel; 41 protected final Callback mSessionCallback; 42 protected final RunningProfileSessionInfo mRunningProfileSessionInfo; 43 44 // it could be sessionId for unicast session or subSessionId for multicast session. 45 protected Optional<Integer> mUniqueSessionId = Optional.empty(); 46 // default session id/sub session id is derived in FiRa applet. 47 protected boolean mIsDefaultUniqueSessionId = false; 48 // session data is used by both controller and controlee finally. 49 protected SessionData mSessionData; 50 51 protected boolean mIsController = false; 52 53 private final FiRaSecureChannel.SecureChannelCallback mSecureChannelCallback = 54 new FiRaSecureChannel.SecureChannelCallback() { 55 @Override 56 public void onEstablished(Optional<Integer> defaultUniqueSessionId) { 57 if (defaultUniqueSessionId.isPresent()) { 58 mUniqueSessionId = defaultUniqueSessionId; 59 mIsDefaultUniqueSessionId = true; 60 } else if (mIsController) { 61 mUniqueSessionId = Optional.of(CsmlUtil.generateRandomSessionId()); 62 } 63 handleFiRaSecureChannelEstablished(); 64 } 65 66 @Override 67 public void onSetUpError(FiRaSecureChannel.SetupError error) { 68 logw("secure channel set up error: " + error); 69 mFiRaSecureChannel.cleanUpTerminatedOrAbortedSession(); 70 mSessionCallback.onSessionAborted(); 71 } 72 73 @Override 74 public void onDispatchResponseAvailable(DispatchResponse dispatchResponse) { 75 handleDispatchResponse(dispatchResponse); 76 } 77 78 @Override 79 public void onDispatchCommandFailure() { 80 handleDispatchCommandFailure(); 81 } 82 83 @Override 84 public void onTerminated(boolean withError) { 85 logd("session is terminated with error: " + withError); 86 mSessionCallback.onSessionTerminated(); 87 } 88 89 @Override 90 public void onSeChannelClosed(boolean withError) { 91 // TODO: no action, may be removed. 92 } 93 94 @Override 95 public void onRdsAvailableAndTerminated(int sessionId) { 96 mUniqueSessionId = Optional.of(sessionId); 97 mSessionCallback.onSessionDataReady( 98 sessionId, Optional.empty(), /*isSessionTerminated=*/ true); 99 } 100 }; 101 SecureSession( @onNull Looper workLooper, @NonNull FiRaSecureChannel fiRaSecureChannel, @NonNull Callback sessionCallback, @NonNull RunningProfileSessionInfo runningProfileSessionInfo)102 SecureSession( 103 @NonNull Looper workLooper, 104 @NonNull FiRaSecureChannel fiRaSecureChannel, 105 @NonNull Callback sessionCallback, 106 @NonNull RunningProfileSessionInfo runningProfileSessionInfo) { 107 mWorkHandler = new Handler(workLooper); 108 mFiRaSecureChannel = fiRaSecureChannel; 109 mSessionCallback = sessionCallback; 110 mRunningProfileSessionInfo = runningProfileSessionInfo; 111 } 112 handleDispatchCommandFailure()113 protected abstract void handleDispatchCommandFailure(); 114 handleDispatchResponse(@onNull DispatchResponse dispatchResponse)115 protected abstract void handleDispatchResponse(@NonNull DispatchResponse dispatchResponse); 116 handleFiRaSecureChannelEstablished()117 protected abstract void handleFiRaSecureChannelEstablished(); 118 119 /** 120 * Start the dynamic STS secure session set up. 121 */ startSession()122 public final void startSession() { 123 mFiRaSecureChannel.init(mSecureChannelCallback); 124 } 125 126 /** 127 * Terminate the dynamic STS secure session. 128 */ terminateSession()129 public abstract void terminateSession(); 130 131 /** 132 * Callback to get the secure session information. 133 */ 134 public interface Callback { 135 /** 136 * The session data is ready, the UWB configuration of Controller can be sent to UWBS. 137 * 138 * @param sessionData empty if the session is terminated automatically, profile/app 139 * defined the session data in advance. 140 * @param isSessionTerminated If the session is terminated, the client shouldn't use 141 * the session further. 142 */ onSessionDataReady( int updatedSessionId, Optional<SessionData> sessionData, boolean isSessionTerminated)143 void onSessionDataReady( 144 int updatedSessionId, 145 Optional<SessionData> sessionData, 146 boolean isSessionTerminated); 147 148 /** 149 * Something wrong, the session is aborted. 150 */ onSessionAborted()151 void onSessionAborted(); 152 153 /** 154 * Session is terminated as responding to the calling of {@code #terminateSession}. 155 */ onSessionTerminated()156 void onSessionTerminated(); 157 } 158 logd(@onNull String dbgMsg)159 private void logd(@NonNull String dbgMsg) { 160 Log.d(LOG_TAG, dbgMsg); 161 } 162 logw(@onNull String dbgMsg)163 private void logw(@NonNull String dbgMsg) { 164 Log.w(LOG_TAG, dbgMsg); 165 } 166 } 167