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 com.android.internal.telephony;
18 
19 import static android.telephony.TelephonyManager.HAL_SERVICE_DATA;
20 import static android.telephony.TelephonyManager.HAL_SERVICE_IMS;
21 import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING;
22 import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM;
23 import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK;
24 import static android.telephony.TelephonyManager.HAL_SERVICE_SIM;
25 import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE;
26 
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.ServiceConnection;
31 import android.os.IBinder;
32 
33 import com.android.telephony.Rlog;
34 
35 /** This class provides wrapper APIs for binding interfaces to mock service. */
36 public class MockModem {
37     private static final String TAG = "MockModem";
38     private static final String BIND_IRADIOMODEM = "android.telephony.mockmodem.iradiomodem";
39     private static final String BIND_IRADIOSIM = "android.telephony.mockmodem.iradiosim";
40     private static final String BIND_IRADIOMESSAGING =
41             "android.telephony.mockmodem.iradiomessaging";
42     private static final String BIND_IRADIODATA = "android.telephony.mockmodem.iradiodata";
43     private static final String BIND_IRADIONETWORK = "android.telephony.mockmodem.iradionetwork";
44     private static final String BIND_IRADIOVOICE = "android.telephony.mockmodem.iradiovoice";
45     private static final String BIND_IRADIOIMS = "android.telephony.mockmodem.iradioims";
46     private static final String BIND_IRADIOCONFIG = "android.telephony.mockmodem.iradioconfig";
47     private static final String PHONE_ID = "phone_id";
48 
49     private static final byte DEFAULT_PHONE_ID = 0x00;
50 
51     static final int RADIOCONFIG_SERVICE = RIL.MAX_SERVICE_IDX + 1;
52 
53     static final int BINDER_RETRY_MILLIS = 3 * 100;
54     static final int BINDER_MAX_RETRY = 10;
55 
56     private Context mContext;
57     private String mServiceName;
58     private String mPackageName;
59 
60     private IBinder mModemBinder;
61     private IBinder mSimBinder;
62     private IBinder mMessagingBinder;
63     private IBinder mDataBinder;
64     private IBinder mNetworkBinder;
65     private IBinder mVoiceBinder;
66     private IBinder mImsBinder;
67     private IBinder mConfigBinder;
68     private ServiceConnection mModemServiceConnection;
69     private ServiceConnection mSimServiceConnection;
70     private ServiceConnection mMessagingServiceConnection;
71     private ServiceConnection mDataServiceConnection;
72     private ServiceConnection mNetworkServiceConnection;
73     private ServiceConnection mVoiceServiceConnection;
74     private ServiceConnection mImsServiceConnection;
75     private ServiceConnection mConfigServiceConnection;
76 
77     private byte mPhoneId;
78     private String mTag;
79 
MockModem(Context context, String serviceName)80     MockModem(Context context, String serviceName) {
81         this(context, serviceName, 0);
82     }
83 
MockModem(Context context, String serviceName, int phoneId)84     MockModem(Context context, String serviceName, int phoneId) {
85         mPhoneId = (byte) phoneId;
86         mTag = TAG + "-" + mPhoneId;
87         mContext = context;
88         String[] componentInfo = serviceName.split("/", 2);
89         mPackageName = componentInfo[0];
90         mServiceName = componentInfo[1];
91     }
92 
93     private class MockModemConnection implements ServiceConnection {
94         private int mService;
95 
MockModemConnection(int module)96         MockModemConnection(int module) {
97             mService = module;
98         }
99 
100         @Override
onServiceConnected(ComponentName name, IBinder binder)101         public void onServiceConnected(ComponentName name, IBinder binder) {
102             Rlog.d(mTag, "IRadio " + getModuleName(mService) + "  - onServiceConnected");
103 
104             if (mService == HAL_SERVICE_MODEM) {
105                 mModemBinder = binder;
106             } else if (mService == HAL_SERVICE_SIM) {
107                 mSimBinder = binder;
108             } else if (mService == HAL_SERVICE_MESSAGING) {
109                 mMessagingBinder = binder;
110             } else if (mService == HAL_SERVICE_DATA) {
111                 mDataBinder = binder;
112             } else if (mService == HAL_SERVICE_NETWORK) {
113                 mNetworkBinder = binder;
114             } else if (mService == HAL_SERVICE_VOICE) {
115                 mVoiceBinder = binder;
116             } else if (mService == HAL_SERVICE_IMS) {
117                 mImsBinder = binder;
118             } else if (mService == RADIOCONFIG_SERVICE) {
119                 mConfigBinder = binder;
120             }
121         }
122 
123         @Override
onServiceDisconnected(ComponentName name)124         public void onServiceDisconnected(ComponentName name) {
125             Rlog.d(mTag, "IRadio " + getModuleName(mService) + "  - onServiceDisconnected");
126 
127             if (mService == HAL_SERVICE_MODEM) {
128                 mModemBinder = null;
129             } else if (mService == HAL_SERVICE_SIM) {
130                 mSimBinder = null;
131             } else if (mService == HAL_SERVICE_MESSAGING) {
132                 mMessagingBinder = null;
133             } else if (mService == HAL_SERVICE_DATA) {
134                 mDataBinder = null;
135             } else if (mService == HAL_SERVICE_NETWORK) {
136                 mNetworkBinder = null;
137             } else if (mService == HAL_SERVICE_VOICE) {
138                 mVoiceBinder = null;
139             } else if (mService == HAL_SERVICE_IMS) {
140                 mImsBinder = null;
141             } else if (mService == RADIOCONFIG_SERVICE) {
142                 mConfigBinder = null;
143             }
144         }
145     }
146 
bindModuleToMockModemService( String actionName, ServiceConnection serviceConnection)147     private boolean bindModuleToMockModemService(
148             String actionName, ServiceConnection serviceConnection) {
149         return bindModuleToMockModemService(DEFAULT_PHONE_ID, actionName, serviceConnection);
150     }
151 
bindModuleToMockModemService( byte phoneId, String actionName, ServiceConnection serviceConnection)152     private boolean bindModuleToMockModemService(
153             byte phoneId, String actionName, ServiceConnection serviceConnection) {
154         boolean status = false;
155 
156         Intent intent = new Intent();
157         intent.setComponent(new ComponentName(mPackageName, mServiceName));
158         intent.setAction(actionName + phoneId);
159         intent.putExtra(PHONE_ID, phoneId);
160 
161         status = mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
162         return status;
163     }
164 
165     /** waitForBinder */
getServiceBinder(int service)166     public IBinder getServiceBinder(int service) {
167         switch (service) {
168             case HAL_SERVICE_MODEM:
169                 return mModemBinder;
170             case HAL_SERVICE_SIM:
171                 return mSimBinder;
172             case HAL_SERVICE_MESSAGING:
173                 return mMessagingBinder;
174             case HAL_SERVICE_DATA:
175                 return mDataBinder;
176             case HAL_SERVICE_NETWORK:
177                 return mNetworkBinder;
178             case HAL_SERVICE_VOICE:
179                 return mVoiceBinder;
180             case HAL_SERVICE_IMS:
181                 return mImsBinder;
182             case RADIOCONFIG_SERVICE:
183                 return mConfigBinder;
184             default:
185                 return null;
186         }
187     }
188 
189     /** Binding interfaces with mock modem service */
bindAllMockModemService()190     public void bindAllMockModemService() {
191         for (int service = RIL.MIN_SERVICE_IDX; service <= RIL.MAX_SERVICE_IDX; service++) {
192             bindToMockModemService(service);
193         }
194     }
195 
196     /** bindToMockModemService */
bindToMockModemService(int service)197     public void bindToMockModemService(int service) {
198         if (service == RADIOCONFIG_SERVICE) {
199             if (mConfigBinder == null) {
200                 mConfigServiceConnection = new MockModemConnection(RADIOCONFIG_SERVICE);
201 
202                 boolean status =
203                         bindModuleToMockModemService(BIND_IRADIOCONFIG, mConfigServiceConnection);
204                 if (!status) {
205                     Rlog.d(mTag, "IRadio Config bind fail");
206                     mConfigServiceConnection = null;
207                 }
208             } else {
209                 Rlog.d(mTag, "IRadio Config is bound");
210             }
211         } else if (service == HAL_SERVICE_MODEM) {
212             if (mModemBinder == null) {
213                 mModemServiceConnection = new MockModemConnection(HAL_SERVICE_MODEM);
214 
215                 boolean status =
216                         bindModuleToMockModemService(
217                                 mPhoneId, BIND_IRADIOMODEM, mModemServiceConnection);
218                 if (!status) {
219                     Rlog.d(mTag, "IRadio Modem bind fail");
220                     mModemServiceConnection = null;
221                 }
222             } else {
223                 Rlog.d(mTag, "IRadio Modem is bound");
224             }
225         } else if (service == HAL_SERVICE_SIM) {
226             if (mSimBinder == null) {
227                 mSimServiceConnection = new MockModemConnection(HAL_SERVICE_SIM);
228 
229                 boolean status =
230                         bindModuleToMockModemService(
231                                 mPhoneId, BIND_IRADIOSIM, mSimServiceConnection);
232                 if (!status) {
233                     Rlog.d(mTag, "IRadio Sim bind fail");
234                     mSimServiceConnection = null;
235                 }
236             } else {
237                 Rlog.d(mTag, "IRadio Sim is bound");
238             }
239         } else if (service == HAL_SERVICE_MESSAGING) {
240             if (mMessagingBinder == null) {
241                 mMessagingServiceConnection = new MockModemConnection(HAL_SERVICE_MESSAGING);
242 
243                 boolean status =
244                         bindModuleToMockModemService(
245                                 mPhoneId, BIND_IRADIOMESSAGING, mMessagingServiceConnection);
246                 if (!status) {
247                     Rlog.d(mTag, "IRadio Messaging bind fail");
248                     mMessagingServiceConnection = null;
249                 }
250             } else {
251                 Rlog.d(mTag, "IRadio Messaging is bound");
252             }
253         } else if (service == HAL_SERVICE_DATA) {
254             if (mDataBinder == null) {
255                 mDataServiceConnection = new MockModemConnection(HAL_SERVICE_DATA);
256 
257                 boolean status =
258                         bindModuleToMockModemService(
259                                 mPhoneId, BIND_IRADIODATA, mDataServiceConnection);
260                 if (!status) {
261                     Rlog.d(mTag, "IRadio Data bind fail");
262                     mDataServiceConnection = null;
263                 }
264             } else {
265                 Rlog.d(mTag, "IRadio Data is bound");
266             }
267         } else if (service == HAL_SERVICE_NETWORK) {
268             if (mNetworkBinder == null) {
269                 mNetworkServiceConnection = new MockModemConnection(HAL_SERVICE_NETWORK);
270 
271                 boolean status =
272                         bindModuleToMockModemService(
273                                 mPhoneId, BIND_IRADIONETWORK, mNetworkServiceConnection);
274                 if (!status) {
275                     Rlog.d(mTag, "IRadio Network bind fail");
276                     mNetworkServiceConnection = null;
277                 }
278             } else {
279                 Rlog.d(mTag, "IRadio Network is bound");
280             }
281         } else if (service == HAL_SERVICE_VOICE) {
282             if (mVoiceBinder == null) {
283                 mVoiceServiceConnection = new MockModemConnection(HAL_SERVICE_VOICE);
284 
285                 boolean status =
286                         bindModuleToMockModemService(
287                                 mPhoneId, BIND_IRADIOVOICE, mVoiceServiceConnection);
288                 if (!status) {
289                     Rlog.d(mTag, "IRadio Voice bind fail");
290                     mVoiceServiceConnection = null;
291                 }
292             } else {
293                 Rlog.d(mTag, "IRadio Voice is bound");
294             }
295         } else if (service == HAL_SERVICE_IMS) {
296             if (mImsBinder == null) {
297                 mImsServiceConnection = new MockModemConnection(HAL_SERVICE_IMS);
298 
299                 boolean status =
300                         bindModuleToMockModemService(
301                                 mPhoneId, BIND_IRADIOIMS, mImsServiceConnection);
302                 if (!status) {
303                     Rlog.d(TAG, "IRadio Ims bind fail");
304                     mImsServiceConnection = null;
305                 }
306             } else {
307                 Rlog.d(TAG, "IRadio Ims is bound");
308             }
309         }
310     }
311 
312     /** unbindMockModemService */
unbindMockModemService(int service)313     public void unbindMockModemService(int service) {
314 
315         if (service == RADIOCONFIG_SERVICE) {
316             if (mConfigServiceConnection != null) {
317                 mContext.unbindService(mConfigServiceConnection);
318                 mConfigServiceConnection = null;
319                 mConfigBinder = null;
320                 Rlog.d(mTag, "unbind IRadio Config");
321             }
322         } else if (service == HAL_SERVICE_MODEM) {
323             if (mModemServiceConnection != null) {
324                 mContext.unbindService(mModemServiceConnection);
325                 mModemServiceConnection = null;
326                 mModemBinder = null;
327                 Rlog.d(mTag, "unbind IRadio Modem");
328             }
329         } else if (service == HAL_SERVICE_SIM) {
330             if (mSimServiceConnection != null) {
331                 mContext.unbindService(mSimServiceConnection);
332                 mSimServiceConnection = null;
333                 mSimBinder = null;
334                 Rlog.d(mTag, "unbind IRadio Sim");
335             }
336         } else if (service == HAL_SERVICE_MESSAGING) {
337             if (mMessagingServiceConnection != null) {
338                 mContext.unbindService(mMessagingServiceConnection);
339                 mMessagingServiceConnection = null;
340                 mMessagingBinder = null;
341                 Rlog.d(mTag, "unbind IRadio Messaging");
342             }
343         } else if (service == HAL_SERVICE_DATA) {
344             if (mDataServiceConnection != null) {
345                 mContext.unbindService(mDataServiceConnection);
346                 mDataServiceConnection = null;
347                 mDataBinder = null;
348                 Rlog.d(mTag, "unbind IRadio Data");
349             }
350         } else if (service == HAL_SERVICE_NETWORK) {
351             if (mNetworkServiceConnection != null) {
352                 mContext.unbindService(mNetworkServiceConnection);
353                 mNetworkServiceConnection = null;
354                 mNetworkBinder = null;
355                 Rlog.d(mTag, "unbind IRadio Network");
356             }
357         } else if (service == HAL_SERVICE_VOICE) {
358             if (mVoiceServiceConnection != null) {
359                 mContext.unbindService(mVoiceServiceConnection);
360                 mVoiceServiceConnection = null;
361                 mVoiceBinder = null;
362                 Rlog.d(mTag, "unbind IRadio Voice");
363             }
364         } else if (service == HAL_SERVICE_IMS) {
365             if (mImsServiceConnection != null) {
366                 mContext.unbindService(mImsServiceConnection);
367                 mImsServiceConnection = null;
368                 mImsBinder = null;
369                 Rlog.d(TAG, "unbind IRadio Ims");
370             }
371         }
372     }
373 
getServiceName()374     public String getServiceName() {
375         return mServiceName;
376     }
377 
getModuleName(int service)378     private String getModuleName(int service) {
379         switch (service) {
380             case HAL_SERVICE_MODEM:
381                 return "modem";
382             case HAL_SERVICE_SIM:
383                 return "sim";
384             case HAL_SERVICE_MESSAGING:
385                 return "messaging";
386             case HAL_SERVICE_DATA:
387                 return "data";
388             case HAL_SERVICE_NETWORK:
389                 return "network";
390             case HAL_SERVICE_VOICE:
391                 return "voice";
392             case HAL_SERVICE_IMS:
393                 return "ims";
394             case RADIOCONFIG_SERVICE:
395                 return "config";
396             default:
397                 return "none";
398         }
399     }
400 }
401