• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.telephony.mockmodem.MockSimService.MOCK_SIM_PROFILE_ID_DEFAULT;
20 
21 import android.app.Service;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.hardware.radio.RadioError;
25 import android.hardware.radio.RadioResponseInfo;
26 import android.hardware.radio.RadioResponseType;
27 import android.os.Binder;
28 import android.os.IBinder;
29 import android.telephony.TelephonyManager;
30 import android.util.Log;
31 import android.util.Pair;
32 
33 import androidx.test.platform.app.InstrumentationRegistry;
34 
35 import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit;
37 
38 public class MockModemService extends Service {
39     private static final String TAG = "MockModemService";
40     private static final String RESOURCE_PACKAGE_NAME = "android";
41 
42     public static final int TEST_TIMEOUT_MS = 30000;
43     public static final String IRADIOCONFIG_INTERFACE = "android.telephony.mockmodem.iradioconfig";
44     public static final String IRADIOMODEM_INTERFACE = "android.telephony.mockmodem.iradiomodem";
45     public static final String IRADIOSIM_INTERFACE = "android.telephony.mockmodem.iradiosim";
46     public static final String IRADIONETWORK_INTERFACE =
47             "android.telephony.mockmodem.iradionetwork";
48     public static final String IRADIODATA_INTERFACE = "android.telephony.mockmodem.iradiodata";
49     public static final String IRADIOMESSAGING_INTERFACE =
50             "android.telephony.mockmodem.iradiomessaging";
51     public static final String IRADIOVOICE_INTERFACE = "android.telephony.mockmodem.iradiovoice";
52     public static final String IRADIOIMS_INTERFACE = "android.telephony.mockmodem.iradioims";
53     public static final String PHONE_ID = "phone_id";
54 
55     private static MockModemConfigInterface sMockModemConfigInterface;
56     private static IRadioConfigImpl sIRadioConfigImpl;
57     private static IRadioModemImpl[] sIRadioModemImpl;
58     private static IRadioSimImpl[] sIRadioSimImpl;
59     private static IRadioNetworkImpl[] sIRadioNetworkImpl;
60     private static IRadioDataImpl[] sIRadioDataImpl;
61     private static IRadioMessagingImpl[] sIRadioMessagingImpl;
62     private static IRadioVoiceImpl[] sIRadioVoiceImpl;
63     private static IRadioImsImpl[] sIRadioImsImpl;
64 
65     public static final byte PHONE_ID_0 = 0x00;
66     public static final byte PHONE_ID_1 = 0x01;
67 
68     public static final int LATCH_MOCK_MODEM_SERVICE_READY = 0;
69     public static final int LATCH_RADIO_INTERFACES_READY = 1;
70     public static final int LATCH_MAX = 2;
71 
72     private static final int IRADIO_CONFIG_INTERFACE_NUMBER = 1;
73     private static final int IRADIO_INTERFACE_NUMBER = 6;
74 
75     private Context mContext;
76     private TelephonyManager mTelephonyManager;
77     private int mNumOfSim;
78     private int mNumOfPhone;
79     private static final int DEFAULT_SUB_ID = 0;
80 
81     private Object mLock;
82     protected static CountDownLatch[] sLatches;
83     private LocalBinder mBinder;
84 
85     // For local access of this Service.
86     class LocalBinder extends Binder {
getService()87         MockModemService getService() {
88             return MockModemService.this;
89         }
90     }
91 
92     @Override
onCreate()93     public void onCreate() {
94         Log.d(TAG, "Mock Modem Service Created");
95 
96         mContext = InstrumentationRegistry.getInstrumentation().getContext();
97         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
98         mNumOfSim = getNumPhysicalSlots();
99         mNumOfPhone = mTelephonyManager.getActiveModemCount();
100         Log.d(TAG, "Support number of phone = " + mNumOfPhone + ", number of SIM = " + mNumOfSim);
101 
102         // Number of physical Sim slot should be equals to or greater than number of phone.
103         if (mNumOfSim < mNumOfPhone) {
104             mNumOfSim = mNumOfPhone;
105         }
106 
107         mLock = new Object();
108         sLatches = new CountDownLatch[LATCH_MAX];
109 
110         for (int i = 0; i < LATCH_MAX; i++) {
111             sLatches[i] = new CountDownLatch(1);
112             if (i == LATCH_RADIO_INTERFACES_READY) {
113                 int radioServiceSupportedNumber = 0;
114                 int radioInterfaceNumber = 0;
115 
116                 try {
117                     for (int j = TelephonyManager.HAL_SERVICE_DATA;
118                             j <= TelephonyManager.HAL_SERVICE_IMS;
119                             j++) {
120                         Pair<Integer, Integer> halVersion = mTelephonyManager.getHalVersion(j);
121                         if (halVersion.first == -2 && halVersion.second == -2) {
122                             Log.d(TAG, "Service: " + j + " unsupported");
123                         } else {
124                             radioServiceSupportedNumber++;
125                         }
126                     }
127                 } catch (NoSuchMethodError | IllegalStateException e) {
128                     Log.e(TAG, "Use the default number of interfaces - " + IRADIO_INTERFACE_NUMBER);
129                     radioServiceSupportedNumber = IRADIO_INTERFACE_NUMBER;
130                 }
131 
132                 radioInterfaceNumber =
133                         IRADIO_CONFIG_INTERFACE_NUMBER + mNumOfPhone * radioServiceSupportedNumber;
134                 sLatches[i] = new CountDownLatch(radioInterfaceNumber);
135             } else {
136                 sLatches[i] = new CountDownLatch(1);
137             }
138         }
139 
140         sMockModemConfigInterface = new MockModemConfigBase(mContext, mNumOfSim, mNumOfPhone);
141         sIRadioConfigImpl = new IRadioConfigImpl(this, sMockModemConfigInterface, PHONE_ID_0);
142         sIRadioModemImpl = new IRadioModemImpl[mNumOfPhone];
143         sIRadioSimImpl = new IRadioSimImpl[mNumOfPhone];
144         sIRadioNetworkImpl = new IRadioNetworkImpl[mNumOfPhone];
145         sIRadioDataImpl = new IRadioDataImpl[mNumOfPhone];
146         sIRadioMessagingImpl = new IRadioMessagingImpl[mNumOfPhone];
147         sIRadioVoiceImpl = new IRadioVoiceImpl[mNumOfPhone];
148         sIRadioImsImpl = new IRadioImsImpl[mNumOfPhone];
149         for (int i = 0; i < mNumOfPhone; i++) {
150             sIRadioModemImpl[i] = new IRadioModemImpl(this, sMockModemConfigInterface, i);
151             sIRadioSimImpl[i] = new IRadioSimImpl(this, sMockModemConfigInterface, i);
152             sIRadioNetworkImpl[i] =
153                     new IRadioNetworkImpl(this, mContext, sMockModemConfigInterface, i);
154             sIRadioDataImpl[i] = new IRadioDataImpl(this, mContext, sMockModemConfigInterface, i);
155             sIRadioMessagingImpl[i] = new IRadioMessagingImpl(this, sMockModemConfigInterface, i);
156             sIRadioVoiceImpl[i] = new IRadioVoiceImpl(this, sMockModemConfigInterface, i);
157             sIRadioImsImpl[i] = new IRadioImsImpl(this, sMockModemConfigInterface, i);
158         }
159 
160         mBinder = new LocalBinder();
161     }
162 
163     @Override
onDestroy()164     public void onDestroy() {
165         Log.d(TAG, "Mock Modem Service on distory");
166         if (sMockModemConfigInterface != null) {
167             sMockModemConfigInterface.destroy();
168         }
169         super.onDestroy();
170     }
171 
172     @Override
onBind(Intent intent)173     public IBinder onBind(Intent intent) {
174 
175         String action = intent.getAction();
176         if (action == null) {
177             countDownLatch(LATCH_MOCK_MODEM_SERVICE_READY);
178             Log.i(TAG, "onBind-Local");
179             return mBinder;
180         }
181 
182         byte phoneId = intent.getByteExtra(PHONE_ID, PHONE_ID_0);
183 
184         if (phoneId > PHONE_ID_1) {
185             Log.e(TAG, "Not suuport for phone " + phoneId);
186             return null;
187         }
188 
189         if (action.startsWith(IRADIOCONFIG_INTERFACE)) {
190             Log.i(TAG, "onBind-IRadioConfig " + phoneId);
191             return sIRadioConfigImpl;
192         } else if (action.startsWith(IRADIOMODEM_INTERFACE)) {
193             Log.i(TAG, "onBind-IRadioModem " + phoneId);
194             return sIRadioModemImpl[phoneId];
195         } else if (action.startsWith(IRADIOSIM_INTERFACE)) {
196             Log.i(TAG, "onBind-IRadioSim " + phoneId);
197             return sIRadioSimImpl[phoneId];
198         } else if (action.startsWith(IRADIONETWORK_INTERFACE)) {
199             Log.i(TAG, "onBind-IRadioNetwork " + phoneId);
200             return sIRadioNetworkImpl[phoneId];
201         } else if (action.startsWith(IRADIODATA_INTERFACE)) {
202             Log.i(TAG, "onBind-IRadioData " + phoneId);
203             return sIRadioDataImpl[phoneId];
204         } else if (action.startsWith(IRADIOMESSAGING_INTERFACE)) {
205             Log.i(TAG, "onBind-IRadioMessaging " + phoneId);
206             return sIRadioMessagingImpl[phoneId];
207         } else if (action.startsWith(IRADIOVOICE_INTERFACE)) {
208             Log.i(TAG, "onBind-IRadioVoice " + phoneId);
209             return sIRadioVoiceImpl[phoneId];
210         } else if (action.startsWith(IRADIOIMS_INTERFACE)) {
211             Log.i(TAG, "onBind-IRadioIms " + phoneId);
212             return sIRadioImsImpl[phoneId];
213         }
214 
215         return null;
216     }
217 
waitForLatchCountdown(int latchIndex)218     public boolean waitForLatchCountdown(int latchIndex) {
219         boolean complete = false;
220         try {
221             CountDownLatch latch;
222             synchronized (mLock) {
223                 latch = sLatches[latchIndex];
224             }
225             complete = latch.await(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
226         } catch (InterruptedException e) {
227         }
228         synchronized (mLock) {
229             sLatches[latchIndex] = new CountDownLatch(1);
230         }
231         return complete;
232     }
233 
waitForLatchCountdown(int latchIndex, long waitMs)234     public boolean waitForLatchCountdown(int latchIndex, long waitMs) {
235         boolean complete = false;
236         try {
237             CountDownLatch latch;
238             synchronized (mLock) {
239                 latch = sLatches[latchIndex];
240             }
241             complete = latch.await(waitMs, TimeUnit.MILLISECONDS);
242         } catch (InterruptedException e) {
243         }
244         synchronized (mLock) {
245             sLatches[latchIndex] = new CountDownLatch(1);
246         }
247         return complete;
248     }
249 
countDownLatch(int latchIndex)250     public void countDownLatch(int latchIndex) {
251         synchronized (mLock) {
252             sLatches[latchIndex].countDown();
253         }
254     }
255 
getNumPhysicalSlots()256     public int getNumPhysicalSlots() {
257         int numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MIN;
258         int resourceId =
259                 mContext.getResources()
260                         .getIdentifier(
261                                 "config_num_physical_slots", "integer", RESOURCE_PACKAGE_NAME);
262 
263         if (resourceId > 0) {
264             numPhysicalSlots = mContext.getResources().getInteger(resourceId);
265         } else {
266             Log.d(TAG, "Fail to get the resource Id, using default: " + numPhysicalSlots);
267         }
268 
269         if (numPhysicalSlots > MockSimService.MOCK_SIM_SLOT_MAX) {
270             Log.d(
271                     TAG,
272                     "Number of physical Slot ("
273                             + numPhysicalSlots
274                             + ") > mock sim slot support. Reset to max number supported ("
275                             + MockSimService.MOCK_SIM_SLOT_MAX
276                             + ").");
277             numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MAX;
278         } else if (numPhysicalSlots < MockSimService.MOCK_SIM_SLOT_MIN) {
279             Log.d(
280                     TAG,
281                     "Number of physical Slot ("
282                             + numPhysicalSlots
283                             + ") < mock sim slot support. Reset to min number supported ("
284                             + MockSimService.MOCK_SIM_SLOT_MIN
285                             + ").");
286             numPhysicalSlots = MockSimService.MOCK_SIM_SLOT_MIN;
287         }
288 
289         return numPhysicalSlots;
290     }
291 
makeSolRsp(int serial)292     public RadioResponseInfo makeSolRsp(int serial) {
293         RadioResponseInfo rspInfo = new RadioResponseInfo();
294         rspInfo.type = RadioResponseType.SOLICITED;
295         rspInfo.serial = serial;
296         rspInfo.error = RadioError.NONE;
297 
298         return rspInfo;
299     }
300 
makeSolRsp(int serial, int error)301     public RadioResponseInfo makeSolRsp(int serial, int error) {
302         RadioResponseInfo rspInfo = new RadioResponseInfo();
303         rspInfo.type = RadioResponseType.SOLICITED;
304         rspInfo.serial = serial;
305         rspInfo.error = error;
306 
307         return rspInfo;
308     }
309 
initialize(int[] simprofiles)310     public boolean initialize(int[] simprofiles) {
311         Log.d(TAG, "initialize for num of Sim = " + simprofiles.length);
312         boolean result = true;
313 
314         // Sync mock modem status between modules
315         for (int i = 0; i < mNumOfPhone; i++) {
316             // Set initial SIM profiles
317             if (simprofiles != null && i < simprofiles.length) {
318                 result = sMockModemConfigInterface.changeSimProfile(i, simprofiles[i], TAG);
319             } else {
320                 result =
321                         sMockModemConfigInterface.changeSimProfile(
322                                 i, MOCK_SIM_PROFILE_ID_DEFAULT, TAG);
323             }
324 
325             // Sync modem configurations to radio modules
326             sMockModemConfigInterface.notifyAllRegistrantNotifications();
327 
328             // Connect to telephony framework
329             sIRadioModemImpl[i].rilConnected();
330         }
331 
332         return result;
333     }
334 
getMockModemConfigInterface()335     public MockModemConfigInterface getMockModemConfigInterface() {
336         return sMockModemConfigInterface;
337     }
338 
getIRadioConfig()339     public IRadioConfigImpl getIRadioConfig() {
340         return sIRadioConfigImpl;
341     }
342 
getIRadioModem()343     public IRadioModemImpl getIRadioModem() {
344         return getIRadioModem(PHONE_ID_0);
345     }
346 
getIRadioModem(byte phoneId)347     public IRadioModemImpl getIRadioModem(byte phoneId) {
348         return sIRadioModemImpl[phoneId];
349     }
350 
getIRadioSim()351     public IRadioSimImpl getIRadioSim() {
352         return getIRadioSim(PHONE_ID_0);
353     }
354 
getIRadioSim(byte phoneId)355     public IRadioSimImpl getIRadioSim(byte phoneId) {
356         return sIRadioSimImpl[phoneId];
357     }
358 
getIRadioNetwork()359     public IRadioNetworkImpl getIRadioNetwork() {
360         return getIRadioNetwork(PHONE_ID_0);
361     }
362 
getIRadioNetwork(byte phoneId)363     public IRadioNetworkImpl getIRadioNetwork(byte phoneId) {
364         return sIRadioNetworkImpl[phoneId];
365     }
366 
getIRadioVoice()367     public IRadioVoiceImpl getIRadioVoice() {
368         return getIRadioVoice(PHONE_ID_0);
369     }
370 
getIRadioVoice(byte phoneId)371     public IRadioVoiceImpl getIRadioVoice(byte phoneId) {
372         return sIRadioVoiceImpl[phoneId];
373     }
374 
getIRadioMessaging()375     public IRadioMessagingImpl getIRadioMessaging() {
376         return getIRadioMessaging(PHONE_ID_0);
377     }
378 
getIRadioMessaging(byte phoneId)379     public IRadioMessagingImpl getIRadioMessaging(byte phoneId) {
380         return sIRadioMessagingImpl[phoneId];
381     }
382 
getIRadioData()383     public IRadioDataImpl getIRadioData() {
384         return getIRadioData(PHONE_ID_0);
385     }
386 
getIRadioData(byte phoneId)387     public IRadioDataImpl getIRadioData(byte phoneId) {
388         return sIRadioDataImpl[phoneId];
389     }
390 
getIRadioIms()391     public IRadioImsImpl getIRadioIms() {
392         return getIRadioIms(PHONE_ID_0);
393     }
394 
getIRadioIms(byte phoneId)395     public IRadioImsImpl getIRadioIms(byte phoneId) {
396         return sIRadioImsImpl[phoneId];
397     }
398 }
399