1 /*
2  * Copyright (C) 2021 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 android.telephony.mockmodem;
18 
19 import android.content.Context;
20 import android.hardware.radio.RadioError;
21 import android.hardware.radio.RadioIndicationType;
22 import android.hardware.radio.RadioResponseInfo;
23 import android.hardware.radio.data.DataProfileInfo;
24 import android.hardware.radio.data.IRadioData;
25 import android.hardware.radio.data.IRadioDataIndication;
26 import android.hardware.radio.data.IRadioDataResponse;
27 import android.hardware.radio.data.KeepaliveRequest;
28 import android.hardware.radio.data.LinkAddress;
29 import android.hardware.radio.data.SetupDataCallResult;
30 import android.hardware.radio.data.SliceInfo;
31 import android.os.AsyncResult;
32 import android.os.Handler;
33 import android.os.Message;
34 import android.os.RemoteException;
35 import android.util.Log;
36 
37 import java.util.List;
38 
39 public class IRadioDataImpl extends IRadioData.Stub {
40     private static final String TAG = "MRDATA";
41 
42     private final MockModemService mService;
43     private final MockDataService mMockDataService;
44     private IRadioDataResponse mRadioDataResponse;
45     private IRadioDataIndication mRadioDataIndication;
46     private MockModemConfigInterface mMockModemConfigInterface;
47     private static Object sCacheUpdateMutex = new Object();
48     private final Handler mHandler;
49     private int mSubId;
50     private String mTag;
51 
52     private static MockNetworkService sServiceState;
53 
54     // Event
55     static final int EVENT_NETWORK_STATUS_CHANGED = 1;
56 
IRadioDataImpl( MockModemService service, Context context, MockModemConfigInterface configInterface, int instanceId)57     public IRadioDataImpl(
58             MockModemService service,
59             Context context,
60             MockModemConfigInterface configInterface,
61             int instanceId) {
62         mTag = TAG + "-" + instanceId;
63         Log.d(mTag, "Instantiated");
64 
65         mMockDataService = new MockDataService(context, instanceId);
66         this.mService = service;
67 
68         mMockModemConfigInterface = configInterface;
69         mSubId = instanceId;
70 
71         mHandler = new IRadioDataHandler();
72 
73         // Register event
74         mMockModemConfigInterface.registerForServiceStateChanged(
75                 mSubId, mHandler, EVENT_NETWORK_STATUS_CHANGED, null);
76     }
77 
getMockDataServiceInstance()78     public MockDataService getMockDataServiceInstance() {
79         return mMockDataService;
80     }
81 
82     // Implementation of IRadioData functions
83     @Override
setResponseFunctions( IRadioDataResponse radioDataResponse, IRadioDataIndication radioDataIndication)84     public void setResponseFunctions(
85             IRadioDataResponse radioDataResponse, IRadioDataIndication radioDataIndication) {
86         Log.d(mTag, "setResponseFunctions");
87         mRadioDataResponse = radioDataResponse;
88         mRadioDataIndication = radioDataIndication;
89         mService.countDownLatch(MockModemService.LATCH_RADIO_INTERFACES_READY);
90 
91         unsolDataCallListChanged();
92     }
93 
94     @Override
allocatePduSessionId(int serial)95     public void allocatePduSessionId(int serial) {
96         Log.d(mTag, "allocatePduSessionId");
97         int id = 0;
98         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
99         try {
100             mRadioDataResponse.allocatePduSessionIdResponse(rsp, id);
101         } catch (RemoteException ex) {
102             Log.e(mTag, "Failed to allocatePduSessionId from AIDL. Exception" + ex);
103         }
104     }
105 
106     @Override
cancelHandover(int serial, int callId)107     public void cancelHandover(int serial, int callId) {
108         Log.d(mTag, "cancelHandover");
109         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
110         try {
111             mRadioDataResponse.cancelHandoverResponse(rsp);
112         } catch (RemoteException ex) {
113             Log.e(mTag, "Failed to cancelHandover from AIDL. Exception" + ex);
114         }
115     }
116 
117     @Override
deactivateDataCall(int serial, int cid, int reason)118     public void deactivateDataCall(int serial, int cid, int reason) {
119         Log.d(mTag, "deactivateDataCall");
120 
121         mMockDataService.deactivateDataCall(cid, reason);
122         RadioResponseInfo rsp = mService.makeSolRsp(serial);
123         try {
124             mRadioDataResponse.deactivateDataCallResponse(rsp);
125         } catch (RemoteException ex) {
126             Log.e(mTag, "Failed to deactivateDataCall from AIDL. Exception" + ex);
127         }
128         // send the data call list changed
129         unsolDataCallListChanged();
130     }
131 
132     @Override
getDataCallList(int serial)133     public void getDataCallList(int serial) {
134         Log.d(mTag, "getDataCallList");
135 
136         List<SetupDataCallResult> dataCallLists = mMockDataService.getDataCallList();
137         SetupDataCallResult[] dcList = new SetupDataCallResult[dataCallLists.size()];
138         dcList = dataCallLists.toArray(dcList);
139 
140         RadioResponseInfo rsp = mService.makeSolRsp(serial);
141         try {
142             mRadioDataResponse.getDataCallListResponse(rsp, dcList);
143         } catch (RemoteException ex) {
144             Log.e(mTag, "Failed to getDataCallList from AIDL. Exception" + ex);
145         }
146     }
147 
148     @Override
getSlicingConfig(int serial)149     public void getSlicingConfig(int serial) {
150         Log.d(mTag, "getSlicingConfig");
151         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
152         try {
153             mRadioDataResponse.getSlicingConfigResponse(rsp, null);
154         } catch (RemoteException ex) {
155             Log.e(mTag, "Failed to getSlicingConfig from AIDL. Exception" + ex);
156         }
157     }
158 
159     @Override
releasePduSessionId(int serial, int id)160     public void releasePduSessionId(int serial, int id) {
161         Log.d(mTag, "releasePduSessionId");
162         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
163         try {
164             mRadioDataResponse.releasePduSessionIdResponse(rsp);
165         } catch (RemoteException ex) {
166             Log.e(mTag, "Failed to releasePduSessionId from AIDL. Exception" + ex);
167         }
168     }
169 
170     @Override
responseAcknowledgement()171     public void responseAcknowledgement() {
172         Log.d(mTag, "responseAcknowledgement");
173     }
174 
175     @Override
setDataAllowed(int serial, boolean allow)176     public void setDataAllowed(int serial, boolean allow) {
177         Log.d(mTag, "setDataAllowed");
178         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
179         try {
180             mRadioDataResponse.setDataAllowedResponse(rsp);
181         } catch (RemoteException ex) {
182             Log.e(mTag, "Failed to setDataAllowed from AIDL. Exception" + ex);
183         }
184     }
185 
186     @Override
setDataProfile(int serial, DataProfileInfo[] profiles)187     public void setDataProfile(int serial, DataProfileInfo[] profiles) {
188         Log.d(mTag, "setDataProfile");
189 
190         // set data profiles to mockdataservice
191         mMockDataService.setDataProfileInfo(profiles);
192 
193         RadioResponseInfo rsp = mService.makeSolRsp(serial);
194         try {
195             mRadioDataResponse.setDataProfileResponse(rsp);
196         } catch (RemoteException ex) {
197             Log.e(mTag, "Failed to setDataProfile from AIDL. Exception" + ex);
198         }
199     }
200 
201     @Override
setDataThrottling( int serial, byte dataThrottlingAction, long completionDurationMillis)202     public void setDataThrottling(
203             int serial, byte dataThrottlingAction, long completionDurationMillis) {
204         Log.d(mTag, "setDataThrottling");
205         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
206         try {
207             mRadioDataResponse.setDataThrottlingResponse(rsp);
208         } catch (RemoteException ex) {
209             Log.e(mTag, "Failed to setDataThrottling from AIDL. Exception" + ex);
210         }
211     }
212 
213     @Override
setInitialAttachApn(int serial, DataProfileInfo dataProfileInfo)214     public void setInitialAttachApn(int serial, DataProfileInfo dataProfileInfo) {
215         Log.d(mTag, "setInitialAttachApn");
216         // set initial attach apn to mockdataservice
217         mMockDataService.setInitialAttachProfile(dataProfileInfo);
218 
219         RadioResponseInfo rsp = mService.makeSolRsp(serial);
220         try {
221             mRadioDataResponse.setInitialAttachApnResponse(rsp);
222         } catch (RemoteException ex) {
223             Log.e(mTag, "Failed to setInitialAttachApn from AIDL. Exception" + ex);
224         }
225     }
226 
227     @Override
setupDataCall( int serial, int accessNetwork, DataProfileInfo dataProfileInfo, boolean roamingAllowed, int reason, LinkAddress[] addresses, String[] dnses, int pduSessionId, SliceInfo sliceInfo, boolean matchAllRuleAllowed)228     public void setupDataCall(
229             int serial,
230             int accessNetwork,
231             DataProfileInfo dataProfileInfo,
232             boolean roamingAllowed,
233             int reason,
234             LinkAddress[] addresses,
235             String[] dnses,
236             int pduSessionId,
237             SliceInfo sliceInfo,
238             boolean matchAllRuleAllowed) {
239         Log.d(mTag, "setupDataCall");
240 
241         RadioResponseInfo rsp;
242         SetupDataCallResult dc = new SetupDataCallResult();
243         rsp = mService.makeSolRsp(serial);
244         synchronized (sCacheUpdateMutex) {
245             if (sServiceState == null || !sServiceState.isPsInService()) {
246                 rsp = mService.makeSolRsp(serial, RadioError.OP_NOT_ALLOWED_BEFORE_REG_TO_NW);
247             } else {
248                 if (mMockDataService.isSupportedCapability(dataProfileInfo.apn)) {
249                     if (dataProfileInfo.apn.equals("ims")) {
250                         dc = mMockDataService.setupDataCall(mMockDataService.APN_TYPE_IMS);
251                     } else if (dataProfileInfo.apn.equals("internet")) {
252                         dc = mMockDataService.setupDataCall(mMockDataService.APN_TYPE_DEFAULT);
253                     }
254                 } else {
255                     rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
256                 }
257             }
258         }
259 
260         try {
261             mRadioDataResponse.setupDataCallResponse(rsp, dc);
262         } catch (RemoteException ex) {
263             Log.e(mTag, "Failed to setupDataCall from AIDL. Exception" + ex);
264         }
265         // send the data call list changed
266         unsolDataCallListChanged();
267     }
268 
269     @Override
startHandover(int serial, int callId)270     public void startHandover(int serial, int callId) {
271         Log.d(mTag, "startHandover");
272         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
273         try {
274             mRadioDataResponse.startHandoverResponse(rsp);
275         } catch (RemoteException ex) {
276             Log.e(mTag, "Failed to startHandover from AIDL. Exception" + ex);
277         }
278     }
279 
280     @Override
startKeepalive(int serial, KeepaliveRequest keepalive)281     public void startKeepalive(int serial, KeepaliveRequest keepalive) {
282         Log.d(mTag, "startKeepalive");
283         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
284         try {
285             mRadioDataResponse.startKeepaliveResponse(rsp, null);
286         } catch (RemoteException ex) {
287             Log.e(mTag, "Failed to startKeepalive from AIDL. Exception" + ex);
288         }
289     }
290 
291     @Override
stopKeepalive(int serial, int sessionHandle)292     public void stopKeepalive(int serial, int sessionHandle) {
293         Log.d(mTag, "stopKeepalive");
294         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
295         try {
296             mRadioDataResponse.stopKeepaliveResponse(rsp);
297         } catch (RemoteException ex) {
298             Log.e(mTag, "Failed to stopKeepalive from AIDL. Exception" + ex);
299         }
300     }
301 
302     @Override
getInterfaceHash()303     public String getInterfaceHash() {
304         return IRadioData.HASH;
305     }
306 
307     @Override
getInterfaceVersion()308     public int getInterfaceVersion() {
309         return IRadioData.VERSION;
310     }
311 
unsolDataCallListChanged()312     public void unsolDataCallListChanged() {
313         Log.d(mTag, "unsolDataCallListChanged");
314 
315         if (mRadioDataIndication != null) {
316             List<SetupDataCallResult> dataCallLists = mMockDataService.getDataCallList();
317             SetupDataCallResult[] dcList = new SetupDataCallResult[dataCallLists.size()];
318             dcList = dataCallLists.toArray(dcList);
319 
320             try {
321                 mRadioDataIndication.dataCallListChanged(RadioIndicationType.UNSOLICITED, dcList);
322             } catch (RemoteException ex) {
323                 Log.e(
324                         mTag,
325                         "Failed to invoke dataCallListChanged change from AIDL. Exception" + ex);
326             }
327         } else {
328             Log.e(mTag, "null mRadioDataIndication");
329         }
330     }
331 
332     /** Handler class to handle callbacks */
333     private static final class IRadioDataHandler extends Handler {
334         @Override
handleMessage(Message msg)335         public void handleMessage(Message msg) {
336             AsyncResult ar;
337             synchronized (sCacheUpdateMutex) {
338                 switch (msg.what) {
339                     case EVENT_NETWORK_STATUS_CHANGED:
340                         Log.d(TAG, "Received EVENT_NETWORK_STATUS_CHANGED");
341                         ar = (AsyncResult) msg.obj;
342                         if (ar != null && ar.exception == null) {
343                             sServiceState = (MockNetworkService) ar.result;
344                             Log.i(TAG, "Service State: " + sServiceState.toString());
345                         } else {
346                             Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
347                         }
348                         break;
349                 }
350             }
351         }
352     }
353 }
354