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 com.android.internal.telephony.uicc; 18 19 import android.annotation.NonNull; 20 import android.content.Context; 21 import android.os.IBinder; 22 import android.os.Message; 23 import android.os.RemoteException; 24 import android.telephony.SubscriptionInfo; 25 import android.util.IndentingPrintWriter; 26 27 import com.android.internal.annotations.GuardedBy; 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.internal.telephony.CommandsInterface; 30 import com.android.internal.telephony.IccLogicalChannelRequest; 31 import com.android.internal.telephony.TelephonyComponentFactory; 32 import com.android.telephony.Rlog; 33 34 import java.io.FileDescriptor; 35 import java.io.PrintWriter; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 public class UiccPort { 40 protected static final String LOG_TAG = "UiccPort"; 41 protected static final boolean DBG = true; 42 43 // The lock object is created by UiccSlot that owns this UiccCard - this is to share the lock 44 // between UiccSlot, UiccCard, EuiccCard, UiccPort, EuiccPort and UiccProfile for now. 45 protected final Object mLock; 46 47 private String mIccid; 48 protected String mCardId; 49 private Context mContext; 50 private CommandsInterface mCi; 51 private UiccProfile mUiccProfile; 52 53 private final int mPhoneId; 54 private int mPortIdx; 55 private int mPhysicalSlotIndex; 56 57 // The list of the opened logical channel record. The channels will be closed by us when 58 // detecting client died without closing them in advance. 59 @GuardedBy("mOpenChannelRecords") 60 private final List<OpenLogicalChannelRecord> mOpenChannelRecords = new ArrayList<>(); 61 UiccPort(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, UiccCard uiccCard)62 public UiccPort(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, 63 UiccCard uiccCard) { 64 if (DBG) log("Creating"); 65 mPhoneId = phoneId; 66 mLock = lock; 67 update(c, ci, ics, uiccCard); 68 } 69 70 /** 71 * Update port. The main trigger for this is a change in the ICC Card status. 72 */ update(Context c, CommandsInterface ci, IccCardStatus ics, UiccCard uiccCard)73 public void update(Context c, CommandsInterface ci, IccCardStatus ics, UiccCard uiccCard) { 74 synchronized (mLock) { 75 mContext = c; 76 mCi = ci; 77 mIccid = ics.iccid; 78 mPortIdx = ics.mSlotPortMapping.mPortIndex; 79 mPhysicalSlotIndex = ics.mSlotPortMapping.mPhysicalSlotIndex; 80 if (mUiccProfile == null) { 81 mUiccProfile = TelephonyComponentFactory.getInstance() 82 .inject(UiccProfile.class.getName()).makeUiccProfile( 83 mContext, mCi, ics, mPhoneId, uiccCard, mLock); 84 } else { 85 mUiccProfile.update(mContext, mCi, ics); 86 } 87 } 88 } 89 90 /** 91 * Dispose the port and its related Uicc profiles. 92 */ dispose()93 public void dispose() { 94 synchronized (mLock) { 95 if (DBG) log("Disposing Port"); 96 if (mUiccProfile != null) { 97 mUiccProfile.dispose(); 98 } 99 mUiccProfile = null; 100 } 101 } 102 103 @Override finalize()104 protected void finalize() { 105 if (DBG) log("UiccPort finalized"); 106 } 107 108 /** 109 * @deprecated Please use 110 * {@link UiccProfile#isApplicationOnIcc(IccCardApplicationStatus.AppType)} instead. 111 */ 112 @Deprecated isApplicationOnIcc(IccCardApplicationStatus.AppType type)113 public boolean isApplicationOnIcc(IccCardApplicationStatus.AppType type) { 114 synchronized (mLock) { 115 if (mUiccProfile != null) { 116 return mUiccProfile.isApplicationOnIcc(type); 117 } else { 118 return false; 119 } 120 } 121 } 122 123 /** 124 * @deprecated Please use {@link UiccProfile#getUniversalPinState()} instead. 125 */ 126 @Deprecated getUniversalPinState()127 public IccCardStatus.PinState getUniversalPinState() { 128 synchronized (mLock) { 129 if (mUiccProfile != null) { 130 return mUiccProfile.getUniversalPinState(); 131 } else { 132 return IccCardStatus.PinState.PINSTATE_UNKNOWN; 133 } 134 } 135 } 136 137 /** 138 * @deprecated Please use {@link UiccProfile#getApplication(int)} instead. 139 */ 140 @Deprecated getApplication(int family)141 public UiccCardApplication getApplication(int family) { 142 synchronized (mLock) { 143 if (mUiccProfile != null) { 144 return mUiccProfile.getApplication(family); 145 } else { 146 return null; 147 } 148 } 149 } 150 151 /** 152 * @deprecated Please use {@link UiccProfile#getApplicationIndex(int)} instead. 153 */ 154 @Deprecated getApplicationIndex(int index)155 public UiccCardApplication getApplicationIndex(int index) { 156 synchronized (mLock) { 157 if (mUiccProfile != null) { 158 return mUiccProfile.getApplicationIndex(index); 159 } else { 160 return null; 161 } 162 } 163 } 164 165 /** 166 * Returns the SIM application of the specified type. 167 * 168 * @param type ICC application type 169 * (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx) 170 * @return application corresponding to type or a null if no match found 171 * 172 * @deprecated Please use {@link UiccProfile#getApplicationByType(int)} instead. 173 */ 174 @Deprecated getApplicationByType(int type)175 public UiccCardApplication getApplicationByType(int type) { 176 synchronized (mLock) { 177 if (mUiccProfile != null) { 178 return mUiccProfile.getApplicationByType(type); 179 } else { 180 return null; 181 } 182 } 183 } 184 185 /** 186 * Resets the application with the input AID. Returns true if any changes were made. 187 * 188 * A null aid implies a card level reset - all applications must be reset. 189 * 190 * @deprecated Please use {@link UiccProfile#resetAppWithAid(String, boolean)} instead. 191 */ 192 @Deprecated resetAppWithAid(String aid, boolean reset)193 public boolean resetAppWithAid(String aid, boolean reset) { 194 synchronized (mLock) { 195 if (mUiccProfile != null) { 196 return mUiccProfile.resetAppWithAid(aid, reset); 197 } else { 198 return false; 199 } 200 } 201 } 202 203 /** 204 * Exposes {@link CommandsInterface#iccOpenLogicalChannel} 205 * @deprecated Please use 206 * {@link UiccProfile#iccOpenLogicalChannel(String, int, Message)} instead. 207 */ 208 @Deprecated iccOpenLogicalChannel(String AID, int p2, Message response)209 public void iccOpenLogicalChannel(String AID, int p2, Message response) { 210 if (mUiccProfile != null) { 211 mUiccProfile.iccOpenLogicalChannel(AID, p2, response); 212 } else { 213 loge("iccOpenLogicalChannel Failed!"); 214 } 215 } 216 217 /** 218 * Exposes {@link CommandsInterface#iccCloseLogicalChannel} 219 * @deprecated Please use 220 * {@link UiccProfile#iccCloseLogicalChannel(int, boolean, Message)} instead. 221 */ 222 @Deprecated iccCloseLogicalChannel(int channel, Message response)223 public void iccCloseLogicalChannel(int channel, Message response) { 224 if (mUiccProfile != null) { 225 mUiccProfile.iccCloseLogicalChannel(channel, false /*isEs10*/, response); 226 } else { 227 loge("iccCloseLogicalChannel Failed!"); 228 } 229 } 230 231 /** 232 * Exposes {@link CommandsInterface#iccTransmitApduLogicalChannel} 233 * @deprecated Please use {@link 234 * UiccProfile#iccTransmitApduLogicalChannel(int, int, int, int, int, int, String, 235 * boolean, Message)} instead. 236 */ 237 @Deprecated iccTransmitApduLogicalChannel(int channel, int cla, int command, int p1, int p2, int p3, String data, Message response)238 public void iccTransmitApduLogicalChannel(int channel, int cla, int command, 239 int p1, int p2, int p3, String data, Message response) { 240 if (mUiccProfile != null) { 241 mUiccProfile.iccTransmitApduLogicalChannel(channel, cla, command, p1, p2, p3, 242 data, false /*isEs10Command*/, response); 243 } else { 244 loge("iccTransmitApduLogicalChannel Failed!"); 245 } 246 } 247 248 /** 249 * Exposes {@link CommandsInterface#iccTransmitApduBasicChannel} 250 * @deprecated Please use 251 * {@link UiccProfile#iccTransmitApduBasicChannel(int, int, int, int, int, String, Message)} 252 * instead. 253 */ 254 @Deprecated iccTransmitApduBasicChannel(int cla, int command, int p1, int p2, int p3, String data, Message response)255 public void iccTransmitApduBasicChannel(int cla, int command, 256 int p1, int p2, int p3, String data, Message response) { 257 if (mUiccProfile != null) { 258 mUiccProfile.iccTransmitApduBasicChannel(cla, command, p1, p2, p3, data, response); 259 } else { 260 loge("iccTransmitApduBasicChannel Failed!"); 261 } 262 } 263 264 /** 265 * Exposes {@link CommandsInterface#iccIO} 266 * @deprecated Please use 267 * {@link UiccProfile#iccExchangeSimIO(int, int, int, int, int, String, Message)} instead. 268 */ 269 @Deprecated iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, String pathID, Message response)270 public void iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3, 271 String pathID, Message response) { 272 if (mUiccProfile != null) { 273 mUiccProfile.iccExchangeSimIO(fileID, command, p1, p2, p3, pathID, response); 274 } else { 275 loge("iccExchangeSimIO Failed!"); 276 } 277 } 278 279 /** 280 * Exposes {@link CommandsInterface#sendEnvelopeWithStatus} 281 * @deprecated Please use {@link UiccProfile#sendEnvelopeWithStatus(String, Message)} instead. 282 */ 283 @Deprecated sendEnvelopeWithStatus(String contents, Message response)284 public void sendEnvelopeWithStatus(String contents, Message response) { 285 if (mUiccProfile != null) { 286 mUiccProfile.sendEnvelopeWithStatus(contents, response); 287 } else { 288 loge("sendEnvelopeWithStatus Failed!"); 289 } 290 } 291 292 /** 293 * Returns number of applications on this card 294 * @deprecated Please use {@link UiccProfile#getNumApplications()} instead. 295 */ 296 @Deprecated getNumApplications()297 public int getNumApplications() { 298 if (mUiccProfile != null) { 299 return mUiccProfile.getNumApplications(); 300 } else { 301 return 0; 302 } 303 } 304 getPhoneId()305 public int getPhoneId() { 306 return mPhoneId; 307 } 308 getPortIdx()309 public int getPortIdx() { 310 return mPortIdx; 311 } 312 getUiccProfile()313 public UiccProfile getUiccProfile() { 314 return mUiccProfile; 315 } 316 317 /** 318 * @deprecated Please use {@link UiccProfile#setOperatorBrandOverride(String)} instead. 319 */ 320 @Deprecated setOperatorBrandOverride(String brand)321 public boolean setOperatorBrandOverride(String brand) { 322 if (mUiccProfile != null) { 323 return mUiccProfile.setOperatorBrandOverride(brand); 324 } else { 325 return false; 326 } 327 } 328 329 /** 330 * @deprecated Please use {@link UiccProfile#getOperatorBrandOverride()} instead. 331 */ 332 @Deprecated getOperatorBrandOverride()333 public String getOperatorBrandOverride() { 334 if (mUiccProfile != null) { 335 return mUiccProfile.getOperatorBrandOverride(); 336 } else { 337 return null; 338 } 339 } 340 341 /** 342 * Return the IccId corresponding to the port. 343 */ getIccId()344 public String getIccId() { 345 if (mIccid != null) { 346 return mIccid; 347 } else if (mUiccProfile != null) { 348 return mUiccProfile.getIccId(); 349 } else { 350 return null; 351 } 352 } 353 log(String msg)354 private void log(String msg) { 355 Rlog.d(LOG_TAG, msg); 356 } 357 loge(String msg)358 private void loge(String msg) { 359 Rlog.e(LOG_TAG, msg); 360 } 361 dump(FileDescriptor fd, PrintWriter printWriter, String[] args)362 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 363 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 364 pw.println("UiccPort:"); 365 pw.increaseIndent(); 366 pw.println("mPortIdx=" + mPortIdx); 367 pw.println("mCi=" + mCi); 368 pw.println("mIccid=" + SubscriptionInfo.getPrintableId(mIccid)); 369 pw.println("mPhoneId=" + mPhoneId); 370 pw.println("mPhysicalSlotIndex=" + mPhysicalSlotIndex); 371 synchronized (mOpenChannelRecords) { 372 pw.println("mOpenChannelRecords=" + mOpenChannelRecords); 373 } 374 pw.println("mUiccProfile"); 375 if (mUiccProfile != null) { 376 mUiccProfile.dump(fd, pw, args); 377 } 378 } 379 380 /** 381 * Informed that a logical channel has been successfully opened. 382 * 383 * @param request the original request to open the channel, with channel id attached. 384 * @hide 385 */ onLogicalChannelOpened(@onNull IccLogicalChannelRequest request)386 public void onLogicalChannelOpened(@NonNull IccLogicalChannelRequest request) { 387 OpenLogicalChannelRecord record = new OpenLogicalChannelRecord(request); 388 try { 389 request.binder.linkToDeath(record, /*flags=*/ 0); 390 addOpenLogicalChannelRecord(record); 391 if (DBG) log("onLogicalChannelOpened: monitoring client " + record); 392 } catch (RemoteException | NullPointerException ex) { 393 loge("IccOpenLogicChannel client has died, clean up manually"); 394 record.binderDied(); 395 } 396 } 397 398 /** 399 * Informed that a logical channel has been successfully closed. 400 * 401 * @param channelId the channel id of the logical channel that was just closed. 402 * @hide 403 */ onLogicalChannelClosed(int channelId)404 public void onLogicalChannelClosed(int channelId) { 405 OpenLogicalChannelRecord record = getOpenLogicalChannelRecord(channelId); 406 if (record != null && record.mRequest != null && record.mRequest.binder != null) { 407 if (DBG) log("onLogicalChannelClosed: stop monitoring client " + record); 408 record.mRequest.binder.unlinkToDeath(record, /*flags=*/ 0); 409 removeOpenLogicalChannelRecord(record); 410 record.mRequest.binder = null; 411 } 412 } 413 414 /** Get the OpenLogicalChannelRecord matching the channel id. */ 415 @VisibleForTesting getOpenLogicalChannelRecord(int channelId)416 public OpenLogicalChannelRecord getOpenLogicalChannelRecord(int channelId) { 417 synchronized (mOpenChannelRecords) { 418 for (OpenLogicalChannelRecord channelRecord : mOpenChannelRecords) { 419 if (channelRecord.mRequest != null 420 && channelRecord.mRequest.channel == channelId) { 421 return channelRecord; 422 } 423 } 424 } 425 return null; 426 } 427 addOpenLogicalChannelRecord(OpenLogicalChannelRecord record)428 private void addOpenLogicalChannelRecord(OpenLogicalChannelRecord record) { 429 synchronized (mOpenChannelRecords) { 430 mOpenChannelRecords.add(record); 431 } 432 } 433 removeOpenLogicalChannelRecord(OpenLogicalChannelRecord record)434 private void removeOpenLogicalChannelRecord(OpenLogicalChannelRecord record) { 435 synchronized (mOpenChannelRecords) { 436 mOpenChannelRecords.remove(record); 437 } 438 } 439 440 /** Record to keep open logical channel info. */ 441 @VisibleForTesting 442 public class OpenLogicalChannelRecord implements IBinder.DeathRecipient { 443 IccLogicalChannelRequest mRequest; 444 OpenLogicalChannelRecord(IccLogicalChannelRequest request)445 OpenLogicalChannelRecord(IccLogicalChannelRequest request) { 446 this.mRequest = request; 447 } 448 449 @Override binderDied()450 public void binderDied() { 451 loge("IccOpenLogicalChannelRecord: client died, close channel in record " + this); 452 iccCloseLogicalChannel(mRequest.channel, /* response= */ null); 453 onLogicalChannelClosed(mRequest.channel); 454 } 455 456 @Override toString()457 public String toString() { 458 StringBuilder sb = new StringBuilder("OpenLogicalChannelRecord {"); 459 sb.append(" mRequest=" + mRequest).append("}"); 460 return sb.toString(); 461 } 462 } 463 } 464