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