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