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