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