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