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.hardware.radio.RadioError; 20 import android.hardware.radio.RadioIndicationType; 21 import android.hardware.radio.RadioResponseInfo; 22 import android.hardware.radio.config.IRadioConfig; 23 import android.hardware.radio.config.IRadioConfigIndication; 24 import android.hardware.radio.config.IRadioConfigResponse; 25 import android.hardware.radio.config.PhoneCapability; 26 import android.hardware.radio.config.SimSlotStatus; 27 import android.hardware.radio.config.SimType; 28 import android.hardware.radio.config.SimTypeInfo; 29 import android.hardware.radio.config.SlotPortMapping; 30 import android.os.AsyncResult; 31 import android.os.Build; 32 import android.os.Handler; 33 import android.os.Message; 34 import android.os.RemoteException; 35 import android.util.Log; 36 37 public class IRadioConfigImpl extends IRadioConfig.Stub { 38 private static final String TAG = "MRCFG"; 39 40 private final MockModemService mService; 41 private IRadioConfigResponse mRadioConfigResponse; 42 private IRadioConfigIndication mRadioConfigIndication; 43 private MockModemConfigInterface mMockModemConfigInterface; 44 private final Object mCacheUpdateMutex; 45 private final Handler mHandler; 46 private int mSubId; 47 private String mTag; 48 49 // ***** Events 50 static final int EVENT_NUM_OF_LIVE_MODEM_CHANGED = 1; 51 static final int EVENT_PHONE_CAPABILITY_CHANGED = 2; 52 static final int EVENT_SIM_SLOT_STATUS_CHANGED = 3; 53 static final int EVENT_SIMULTANEOUS_CALLING_SUPPORT_CHANGED = 4; 54 55 // ***** Cache of modem attributes/status 56 private int mSlotNum = 1; 57 private byte mNumOfLiveModems = 1; 58 private PhoneCapability mPhoneCapability = new PhoneCapability(); 59 private SimSlotStatus[] mSimSlotStatus; 60 private int[] mEnabledLogicalSlots = {}; 61 private SimTypeInfo[] mSimTypeInfos; 62 63 MockCentralizedNetworkAgent mMockCentralizedNetworkAgent; 64 IRadioConfigImpl( MockModemService service, MockModemConfigInterface configInterface, MockCentralizedNetworkAgent centralizedNetworkAgent, int instanceId)65 public IRadioConfigImpl( 66 MockModemService service, MockModemConfigInterface configInterface, 67 MockCentralizedNetworkAgent centralizedNetworkAgent, int instanceId) { 68 mTag = TAG + "-" + instanceId; 69 Log.d(mTag, "Instantiated"); 70 71 this.mService = service; 72 mMockModemConfigInterface = configInterface; 73 mSlotNum = mService.getNumPhysicalSlots(); 74 mSimSlotStatus = new SimSlotStatus[mSlotNum]; 75 mCacheUpdateMutex = new Object(); 76 mHandler = new IRadioConfigHandler(); 77 mSubId = instanceId; 78 mMockCentralizedNetworkAgent = centralizedNetworkAgent; 79 mSimTypeInfos = new SimTypeInfo[mSlotNum]; 80 81 // Register events 82 mMockModemConfigInterface.registerForNumOfLiveModemChanged( 83 mSubId, mHandler, EVENT_NUM_OF_LIVE_MODEM_CHANGED, null); 84 mMockModemConfigInterface.registerForPhoneCapabilityChanged( 85 mSubId, mHandler, EVENT_PHONE_CAPABILITY_CHANGED, null); 86 mMockModemConfigInterface.registerForSimSlotStatusChanged( 87 mSubId, mHandler, EVENT_SIM_SLOT_STATUS_CHANGED, null); 88 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { 89 mMockModemConfigInterface.registerForSimultaneousCallingSupportStatusChanged( 90 mSubId, mHandler, EVENT_SIMULTANEOUS_CALLING_SUPPORT_CHANGED, null); 91 } 92 } 93 94 /** Handler class to handle callbacks */ 95 private final class IRadioConfigHandler extends Handler { 96 @Override handleMessage(Message msg)97 public void handleMessage(Message msg) { 98 AsyncResult ar; 99 synchronized (mCacheUpdateMutex) { 100 switch (msg.what) { 101 case EVENT_NUM_OF_LIVE_MODEM_CHANGED: 102 Log.d(mTag, "Received EVENT_NUM_OF_LIVE_MODEM_CHANGED"); 103 ar = (AsyncResult) msg.obj; 104 if (ar != null && ar.exception == null) { 105 mNumOfLiveModems = (byte) ar.result; 106 Log.i(mTag, "Number of live modem: " + mNumOfLiveModems); 107 } else { 108 Log.e(mTag, msg.what + " failure. Exception: " + ar.exception); 109 } 110 break; 111 case EVENT_PHONE_CAPABILITY_CHANGED: 112 Log.d(mTag, "Received EVENT_PHONE_CAPABILITY_CHANGED"); 113 ar = (AsyncResult) msg.obj; 114 if (ar != null && ar.exception == null) { 115 mPhoneCapability = (PhoneCapability) ar.result; 116 Log.i(mTag, "Phone capability: " + mPhoneCapability); 117 } else { 118 Log.e(mTag, msg.what + " failure. Exception: " + ar.exception); 119 } 120 break; 121 case EVENT_SIM_SLOT_STATUS_CHANGED: 122 Log.d(mTag, "Received EVENT_SIM_SLOT_STATUS_CHANGED"); 123 ar = (AsyncResult) msg.obj; 124 if (ar != null && ar.exception == null) { 125 mSimSlotStatus = (SimSlotStatus[]) ar.result; 126 for (int i = 0; i < mSlotNum; i++) { 127 Log.i(mTag, "Sim slot status: " + mSimSlotStatus[i]); 128 } 129 unsolSimSlotsStatusChanged(); 130 } else { 131 Log.e(mTag, msg.what + " failure. Exception: " + ar.exception); 132 } 133 break; 134 case EVENT_SIMULTANEOUS_CALLING_SUPPORT_CHANGED: 135 Log.i(mTag, "Received EVENT_SIMULTANEOUS_CALLING_SUPPORT_CHANGED"); 136 ar = (AsyncResult) msg.obj; 137 if (ar != null && ar.exception == null) { 138 mEnabledLogicalSlots = (int[]) ar.result; 139 if (mEnabledLogicalSlots != null) { 140 for (int enabledLogicalSlot : mEnabledLogicalSlots) { 141 Log.i(mTag, "Enabled logical slot = " 142 + enabledLogicalSlot); 143 } 144 } else { 145 Log.i(mTag, "mEnabledLogicalSlots is null"); 146 } 147 unsolSimultaneousCallingSupportChanged(); 148 } else { 149 Log.e(mTag, msg.what + " failure. Exception: " + ar.exception); 150 } 151 break; 152 } 153 } 154 } 155 } 156 157 // Implementation of IRadioConfig functions 158 @Override getHalDeviceCapabilities(int serial)159 public void getHalDeviceCapabilities(int serial) { 160 Log.d(mTag, "getHalDeviceCapabilities"); 161 162 boolean modemReducedFeatureSet1 = false; 163 164 RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED); 165 try { 166 mRadioConfigResponse.getHalDeviceCapabilitiesResponse(rsp, modemReducedFeatureSet1); 167 } catch (RemoteException ex) { 168 Log.e( 169 mTag, 170 "Failed to invoke getHalDeviceCapabilitiesResponse from AIDL. Exception" + ex); 171 } 172 } 173 174 @Override getNumOfLiveModems(int serial)175 public void getNumOfLiveModems(int serial) { 176 Log.d(mTag, "getNumOfLiveModems"); 177 byte numoflivemodem; 178 179 synchronized (mCacheUpdateMutex) { 180 numoflivemodem = mNumOfLiveModems; 181 } 182 183 RadioResponseInfo rsp = mService.makeSolRsp(serial); 184 try { 185 mRadioConfigResponse.getNumOfLiveModemsResponse(rsp, numoflivemodem); 186 } catch (RemoteException ex) { 187 Log.e(mTag, "Failed to invoke getNumOfLiveModemsResponse from AIDL. Exception" + ex); 188 } 189 } 190 191 @Override getPhoneCapability(int serial)192 public void getPhoneCapability(int serial) { 193 Log.d(mTag, "getPhoneCapability"); 194 PhoneCapability phoneCapability; 195 196 synchronized (mCacheUpdateMutex) { 197 phoneCapability = mPhoneCapability; 198 } 199 200 RadioResponseInfo rsp = mService.makeSolRsp(serial); 201 try { 202 mRadioConfigResponse.getPhoneCapabilityResponse(rsp, phoneCapability); 203 } catch (RemoteException ex) { 204 Log.e(mTag, "Failed to invoke getPhoneCapabilityResponse from AIDL. Exception" + ex); 205 } 206 } 207 208 @Override getSimultaneousCallingSupport(int serial)209 public void getSimultaneousCallingSupport(int serial) { 210 Log.d(mTag, "getSimultaneousCallingSupport"); 211 int[] enabledLogicalSlots; 212 213 synchronized (mCacheUpdateMutex) { 214 enabledLogicalSlots = mEnabledLogicalSlots; 215 } 216 217 RadioResponseInfo rsp = mService.makeSolRsp(serial); 218 try { 219 mRadioConfigResponse.getSimultaneousCallingSupportResponse(rsp, enabledLogicalSlots); 220 } catch (RemoteException ex) { 221 Log.e(mTag, "Failed to invoke getSimultaneousCallingSupportResponse from AIDL. " 222 + "Exception" + ex); 223 } 224 } 225 226 @Override getSimSlotsStatus(int serial)227 public void getSimSlotsStatus(int serial) { 228 Log.d(mTag, "getSimSlotsStatus"); 229 SimSlotStatus[] slotStatus; 230 231 synchronized (mCacheUpdateMutex) { 232 if (mSlotNum < 1) { 233 Log.d(mTag, "No slot information is retured."); 234 slotStatus = null; 235 } else { 236 slotStatus = mSimSlotStatus; 237 } 238 } 239 240 RadioResponseInfo rsp = mService.makeSolRsp(serial); 241 try { 242 mRadioConfigResponse.getSimSlotsStatusResponse(rsp, slotStatus); 243 } catch (RemoteException ex) { 244 Log.e(mTag, "Failed to invoke getSimSlotsStatusResponse from AIDL. Exception" + ex); 245 } 246 } 247 248 @Override setNumOfLiveModems(int serial, byte numOfLiveModems)249 public void setNumOfLiveModems(int serial, byte numOfLiveModems) { 250 Log.d(mTag, "setNumOfLiveModems"); 251 // TODO: cache value 252 253 RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED); 254 try { 255 mRadioConfigResponse.setNumOfLiveModemsResponse(rsp); 256 } catch (RemoteException ex) { 257 Log.e(mTag, "Failed to invoke setNumOfLiveModemsResponse from AIDL. Exception" + ex); 258 } 259 } 260 261 @Override setPreferredDataModem(int serial, byte modemId)262 public void setPreferredDataModem(int serial, byte modemId) { 263 Log.d(mTag, "setPreferredDataModem"); 264 // TODO: cache value 265 266 RadioResponseInfo rsp = mService.makeSolRsp(serial); 267 try { 268 mMockCentralizedNetworkAgent.setPreferredDataPhone((int) modemId); 269 mRadioConfigResponse.setPreferredDataModemResponse(rsp); 270 } catch (RemoteException ex) { 271 Log.e(mTag, "Failed to invoke setPreferredDataModemResponse from AIDL. Exception" + ex); 272 } 273 } 274 275 @Override setResponseFunctions( IRadioConfigResponse radioConfigResponse, IRadioConfigIndication radioConfigIndication)276 public void setResponseFunctions( 277 IRadioConfigResponse radioConfigResponse, 278 IRadioConfigIndication radioConfigIndication) { 279 Log.d(mTag, "setResponseFunctions"); 280 mRadioConfigResponse = radioConfigResponse; 281 mRadioConfigIndication = radioConfigIndication; 282 mService.countDownLatch(MockModemService.LATCH_RADIO_INTERFACES_READY); 283 } 284 285 @Override setSimSlotsMapping(int serial, SlotPortMapping[] slotMap)286 public void setSimSlotsMapping(int serial, SlotPortMapping[] slotMap) { 287 Log.d(mTag, "setSimSlotsMapping"); 288 // TODO: cache value 289 290 RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED); 291 try { 292 mRadioConfigResponse.setSimSlotsMappingResponse(rsp); 293 } catch (RemoteException ex) { 294 Log.e(mTag, "Failed to invoke setSimSlotsMappingResponse from AIDL. Exception" + ex); 295 } 296 } 297 298 @Override getSimTypeInfo(int serial)299 public void getSimTypeInfo(int serial) { 300 Log.d(mTag, "getSimTypeInfo"); 301 SimTypeInfo[] simTypeInfos; 302 303 synchronized (mCacheUpdateMutex) { 304 simTypeInfos = mSimTypeInfos; 305 } 306 307 RadioResponseInfo rsp = mService.makeSolRsp(serial); 308 try { 309 mRadioConfigResponse.getSimTypeInfoResponse(rsp, simTypeInfos); 310 } catch (RemoteException ex) { 311 Log.e(mTag, "Failed to invoke getSimTypeInfoResponse from AIDL. " 312 + "Exception" + ex); 313 } 314 } 315 316 @Override setSimType(int serial, @SimType int[] simTypes)317 public void setSimType(int serial, @SimType int[] simTypes) { 318 Log.d(mTag, "setSimType"); 319 RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED); 320 try { 321 mRadioConfigResponse.setSimTypeResponse(rsp); 322 } catch (RemoteException ex) { 323 Log.e(mTag, "Failed to invoke setSimTypeResponse from AIDL. " 324 + "Exception" + ex); 325 } 326 } 327 unsolSimSlotsStatusChanged()328 public void unsolSimSlotsStatusChanged() { 329 Log.d(mTag, "unsolSimSlotsStatusChanged"); 330 SimSlotStatus[] slotStatus; 331 332 if (mRadioConfigIndication != null) { 333 synchronized (mCacheUpdateMutex) { 334 if (mSlotNum < 1) { 335 Log.d(mTag, "No slot information is retured."); 336 slotStatus = null; 337 } else { 338 slotStatus = mSimSlotStatus; 339 } 340 } 341 342 try { 343 mRadioConfigIndication.simSlotsStatusChanged( 344 RadioIndicationType.UNSOLICITED, slotStatus); 345 } catch (RemoteException ex) { 346 Log.e(mTag, "Failed to invoke simSlotsStatusChanged from AIDL. Exception" + ex); 347 } 348 } else { 349 Log.e(mTag, "null mRadioConfigIndication"); 350 } 351 } 352 unsolSimultaneousCallingSupportChanged()353 public void unsolSimultaneousCallingSupportChanged() { 354 Log.d(mTag, "unsolSimultaneousCallingSupportChanged"); 355 int[] enabledLogicalSlots; 356 357 if (mRadioConfigIndication != null) { 358 synchronized (mCacheUpdateMutex) { 359 if (mSlotNum < 1) { 360 Log.d(mTag, "No slot information is retured."); 361 enabledLogicalSlots = null; 362 } else { 363 enabledLogicalSlots = mEnabledLogicalSlots; 364 } 365 } 366 367 try { 368 mRadioConfigIndication.onSimultaneousCallingSupportChanged(enabledLogicalSlots); 369 } catch (RemoteException ex) { 370 Log.e(mTag, "Failed to invoke onSimultaneousCallingSupportChanged from AIDL." 371 + " Exception" + ex); 372 } 373 } else { 374 Log.e(mTag, "null mRadioConfigIndication"); 375 } 376 } 377 378 @Override getInterfaceHash()379 public String getInterfaceHash() { 380 return IRadioConfig.HASH; 381 } 382 383 @Override getInterfaceVersion()384 public int getInterfaceVersion() { 385 return IRadioConfig.VERSION; 386 } 387 } 388