1 /*
2  * Copyright (C) 2020 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.connectivity;
18 
19 import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
20 
21 import android.annotation.NonNull;
22 import android.net.IQosCallback;
23 import android.net.Network;
24 import android.net.QosCallbackException;
25 import android.net.QosFilter;
26 import android.net.QosSession;
27 import android.os.IBinder;
28 import android.os.RemoteException;
29 import android.telephony.data.EpsBearerQosSessionAttributes;
30 import android.telephony.data.NrQosSessionAttributes;
31 import android.util.Log;
32 
33 import com.android.modules.utils.build.SdkLevel;
34 
35 import java.util.Objects;
36 
37 /**
38  * Wraps callback related information and sends messages between network agent and the application.
39  * <p/>
40  * This is a satellite class of {@link com.android.server.ConnectivityService} and not meant
41  * to be used in other contexts.
42  *
43  * @hide
44  */
45 class QosCallbackAgentConnection implements IBinder.DeathRecipient {
46     private static final String TAG = QosCallbackAgentConnection.class.getSimpleName();
47     private static final boolean DBG = false;
48 
49     private final int mAgentCallbackId;
50     @NonNull private final QosCallbackTracker mQosCallbackTracker;
51     @NonNull private final IQosCallback mCallback;
52     @NonNull private final IBinder mBinder;
53     @NonNull private final QosFilter mFilter;
54     @NonNull private final NetworkAgentInfo mNetworkAgentInfo;
55 
56     private final int mUid;
57 
58     /**
59      * Gets the uid
60      * @return uid
61      */
getUid()62     int getUid() {
63         return mUid;
64     }
65 
66     /**
67      * Gets the binder
68      * @return binder
69      */
70     @NonNull
getBinder()71     IBinder getBinder() {
72         return mBinder;
73     }
74 
75     /**
76      * Gets the callback id
77      *
78      * @return callback id
79      */
getAgentCallbackId()80     int getAgentCallbackId() {
81         return mAgentCallbackId;
82     }
83 
84     /**
85      * Gets the network tied to the callback of this connection
86      *
87      * @return network
88      */
89     @NonNull
getNetwork()90     Network getNetwork() {
91         return mFilter.getNetwork();
92     }
93 
QosCallbackAgentConnection(@onNull final QosCallbackTracker qosCallbackTracker, final int agentCallbackId, @NonNull final IQosCallback callback, @NonNull final QosFilter filter, final int uid, @NonNull final NetworkAgentInfo networkAgentInfo)94     QosCallbackAgentConnection(@NonNull final QosCallbackTracker qosCallbackTracker,
95             final int agentCallbackId,
96             @NonNull final IQosCallback callback,
97             @NonNull final QosFilter filter,
98             final int uid,
99             @NonNull final NetworkAgentInfo networkAgentInfo) {
100         Objects.requireNonNull(qosCallbackTracker, "qosCallbackTracker must be non-null");
101         Objects.requireNonNull(callback, "callback must be non-null");
102         Objects.requireNonNull(filter, "filter must be non-null");
103         Objects.requireNonNull(networkAgentInfo, "networkAgentInfo must be non-null");
104 
105         mQosCallbackTracker = qosCallbackTracker;
106         mAgentCallbackId = agentCallbackId;
107         mCallback = callback;
108         mFilter = filter;
109         mUid = uid;
110         mBinder = mCallback.asBinder();
111         mNetworkAgentInfo = networkAgentInfo;
112     }
113 
114     @Override
binderDied()115     public void binderDied() {
116         logw("binderDied: binder died with callback id: " + mAgentCallbackId);
117         mQosCallbackTracker.unregisterCallback(mCallback);
118     }
119 
unlinkToDeathRecipient()120     void unlinkToDeathRecipient() {
121         mBinder.unlinkToDeath(this, 0);
122     }
123 
124     // Returns false if the NetworkAgent was never notified.
sendCmdRegisterCallback()125     boolean sendCmdRegisterCallback() {
126         final int exceptionType = mFilter.validate();
127         if (exceptionType != EX_TYPE_FILTER_NONE) {
128             try {
129                 if (DBG) log("sendCmdRegisterCallback: filter validation failed");
130                 mCallback.onError(exceptionType);
131             } catch (final RemoteException e) {
132                 loge("sendCmdRegisterCallback:", e);
133             }
134             return false;
135         }
136 
137         try {
138             mBinder.linkToDeath(this, 0);
139         } catch (final RemoteException e) {
140             loge("failed linking to death recipient", e);
141             return false;
142         }
143         mNetworkAgentInfo.onQosFilterCallbackRegistered(mAgentCallbackId, mFilter);
144         return true;
145     }
146 
sendCmdUnregisterCallback()147     void sendCmdUnregisterCallback() {
148         if (DBG) log("sendCmdUnregisterCallback: unregistering");
149         mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
150     }
151 
sendEventEpsQosSessionAvailable(final QosSession session, final EpsBearerQosSessionAttributes attributes)152     void sendEventEpsQosSessionAvailable(final QosSession session,
153             final EpsBearerQosSessionAttributes attributes) {
154         if (!validateOrSendErrorAndUnregister()) return;
155         try {
156             if (DBG) log("sendEventEpsQosSessionAvailable: sending...");
157             mCallback.onQosEpsBearerSessionAvailable(session, attributes);
158         } catch (final RemoteException e) {
159             loge("sendEventEpsQosSessionAvailable: remote exception", e);
160         }
161     }
162 
sendEventNrQosSessionAvailable(final QosSession session, final NrQosSessionAttributes attributes)163     void sendEventNrQosSessionAvailable(final QosSession session,
164             final NrQosSessionAttributes attributes) {
165         if (!validateOrSendErrorAndUnregister()) return;
166         try {
167             if (DBG) log("sendEventNrQosSessionAvailable: sending...");
168             mCallback.onNrQosSessionAvailable(session, attributes);
169         } catch (final RemoteException e) {
170             loge("sendEventNrQosSessionAvailable: remote exception", e);
171         }
172     }
173 
sendEventQosSessionLost(@onNull final QosSession session)174     void sendEventQosSessionLost(@NonNull final QosSession session) {
175         if (!validateOrSendErrorAndUnregister()) return;
176         try {
177             if (DBG) log("sendEventQosSessionLost: sending...");
178             mCallback.onQosSessionLost(session);
179         } catch (final RemoteException e) {
180             loge("sendEventQosSessionLost: remote exception", e);
181         }
182     }
183 
sendEventQosCallbackError(@osCallbackException.ExceptionType final int exceptionType)184     void sendEventQosCallbackError(@QosCallbackException.ExceptionType final int exceptionType) {
185         try {
186             if (DBG) log("sendEventQosCallbackError: sending...");
187             mCallback.onError(exceptionType);
188         } catch (final RemoteException e) {
189             loge("sendEventQosCallbackError: remote exception", e);
190         }
191     }
192 
validateOrSendErrorAndUnregister()193     private boolean validateOrSendErrorAndUnregister() {
194         final int exceptionType = mFilter.validate();
195         if (exceptionType != EX_TYPE_FILTER_NONE) {
196              log("validation fail before sending QosCallback.");
197              // Error callback is returned from Android T to prevent any disruption of application
198              // running on Android S.
199              if (SdkLevel.isAtLeastT()) {
200                 sendEventQosCallbackError(exceptionType);
201                 mQosCallbackTracker.unregisterCallback(mCallback);
202             }
203             return false;
204         }
205         return true;
206     }
207 
log(@onNull final String msg)208     private static void log(@NonNull final String msg) {
209         Log.d(TAG, msg);
210     }
211 
logw(@onNull final String msg)212     private static void logw(@NonNull final String msg) {
213         Log.w(TAG, msg);
214     }
215 
loge(@onNull final String msg, final Throwable t)216     private static void loge(@NonNull final String msg, final Throwable t) {
217         Log.e(TAG, msg, t);
218     }
219 }
220