1 /* 2 * Copyright (C) 2006, 2012 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.compat.annotation.UnsupportedAppUsage; 20 import android.content.Context; 21 import android.os.Build; 22 import android.telephony.TelephonyManager; 23 import android.text.TextUtils; 24 import android.util.IndentingPrintWriter; 25 26 import com.android.internal.telephony.CommandsInterface; 27 import com.android.internal.telephony.uicc.IccCardStatus.CardState; 28 import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; 29 import com.android.internal.telephony.uicc.euicc.EuiccCard; 30 import com.android.internal.telephony.uicc.euicc.EuiccPort; 31 import com.android.internal.telephony.util.TelephonyUtils; 32 import com.android.telephony.Rlog; 33 34 import java.io.FileDescriptor; 35 import java.io.PrintWriter; 36 import java.util.HashMap; 37 import java.util.LinkedHashMap; 38 39 /** 40 * {@hide} 41 */ 42 public class UiccCard { 43 protected static final String LOG_TAG = "UiccCard"; 44 protected static final boolean DBG = true; 45 46 public static final String EXTRA_ICC_CARD_ADDED = 47 "com.android.internal.telephony.uicc.ICC_CARD_ADDED"; 48 49 // The lock object is created by UiccSlot that owns this UiccCard - this is to share the lock 50 // between UiccSlot, UiccCard, EuiccCard, UiccPort, EuiccPort and UiccProfile for now. 51 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 52 protected final Object mLock; 53 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 54 private CardState mCardState; 55 protected String mCardId; 56 protected MultipleEnabledProfilesMode mSupportedMepMode; 57 58 protected LinkedHashMap<Integer, UiccPort> mUiccPorts = new LinkedHashMap<>(); 59 private HashMap<Integer, Integer> mPhoneIdToPortIdx = new HashMap<>(); 60 UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, MultipleEnabledProfilesMode supportedMepMode)61 public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, 62 MultipleEnabledProfilesMode supportedMepMode) { 63 if (DBG) log("Creating"); 64 mCardState = ics.mCardState; 65 mLock = lock; 66 mSupportedMepMode = supportedMepMode; 67 update(c, ci, ics, phoneId); 68 } 69 70 /** 71 * Dispose the card and its related UiccPort objects. 72 */ dispose()73 public void dispose() { 74 synchronized (mLock) { 75 if (DBG) log("Disposing card"); 76 for (UiccPort uiccPort : mUiccPorts.values()) { 77 if (uiccPort != null) { 78 uiccPort.dispose(); 79 } 80 } 81 mUiccPorts.clear(); 82 mUiccPorts = null; 83 mPhoneIdToPortIdx.clear(); 84 mPhoneIdToPortIdx = null; 85 } 86 } 87 88 /** 89 * Dispose the port corresponding to the port index. 90 */ disposePort(int portIndex)91 public void disposePort(int portIndex) { 92 synchronized (mLock) { 93 if (DBG) log("Disposing port for index " + portIndex); 94 UiccPort port = getUiccPort(portIndex); 95 if (port != null) { 96 mPhoneIdToPortIdx.remove(port.getPhoneId()); 97 port.dispose(); 98 } 99 mUiccPorts.remove(portIndex); 100 } 101 } 102 103 /** 104 * Update card. The main trigger for this is a change in the ICC Card status. 105 */ update(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId)106 public void update(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) { 107 synchronized (mLock) { 108 mCardState = ics.mCardState; 109 updateCardId(ics.iccid); 110 if (mCardState != CardState.CARDSTATE_ABSENT) { 111 int portIdx = ics.mSlotPortMapping.mPortIndex; 112 UiccPort port = mUiccPorts.get(portIdx); 113 if (port == null) { 114 if (this instanceof EuiccCard) { 115 port = new EuiccPort(c, ci, ics, phoneId, mLock, this, 116 mSupportedMepMode); // eSim 117 } else { 118 port = new UiccPort(c, ci, ics, phoneId, mLock, this); // pSim 119 } 120 mUiccPorts.put(portIdx, port); 121 } else { 122 port.update(c, ci, ics, this); 123 } 124 mPhoneIdToPortIdx.put(phoneId, portIdx); 125 } else { 126 throw new RuntimeException("Card state is absent when updating!"); 127 } 128 } 129 } 130 131 @Override finalize()132 protected void finalize() { 133 if (DBG) log("UiccCard finalized"); 134 } 135 136 /** 137 * Updates the ID of the SIM card. 138 * 139 * <p>Whenever the {@link UiccCard#update(Context, CommandsInterface, IccCardStatus, int)} 140 * is called, this function needs to be called to update the card ID. Subclasses of 141 * {@link UiccCard} could override this function to set the {@link UiccCard#mCardId} to be 142 * something else instead of setting iccId.</p> 143 */ updateCardId(String iccId)144 protected void updateCardId(String iccId) { 145 mCardId = iccId; 146 } 147 148 149 /** 150 * Updates MEP(Multiple Enabled Profile) supported mode flag. 151 * 152 * <p>If IccSlotStatus comes later, the number of ports reported is only known after the 153 * UiccCard creation which will impact UICC MEP capability. 154 */ updateSupportedMepMode(MultipleEnabledProfilesMode supportedMepMode)155 public void updateSupportedMepMode(MultipleEnabledProfilesMode supportedMepMode) { 156 mSupportedMepMode = supportedMepMode; 157 } 158 159 @UnsupportedAppUsage getCardState()160 public CardState getCardState() { 161 synchronized (mLock) { 162 return mCardState; 163 } 164 } 165 166 /** 167 * Returns the ID of this SIM card, it is the ICCID of the active profile on the card for a UICC 168 * card or the EID of the card for an eUICC card. 169 */ getCardId()170 public String getCardId() { 171 if (!TextUtils.isEmpty(mCardId)) { 172 return mCardId; 173 } else { 174 UiccPort uiccPort = mUiccPorts.get(TelephonyManager.DEFAULT_PORT_INDEX); 175 if (uiccPort == null) { 176 return null; 177 } 178 UiccProfile uiccProfile = uiccPort.getUiccProfile(); 179 return uiccProfile == null ? null : uiccProfile.getIccId(); 180 } 181 } 182 183 /** 184 * Returns all the UiccPorts associated with the card. 185 */ getUiccPortList()186 public UiccPort[] getUiccPortList() { 187 synchronized (mLock) { 188 return mUiccPorts.values().stream().toArray(UiccPort[]::new); 189 } 190 } 191 192 /** 193 * Returns the UiccPort associated with the given phoneId 194 */ getUiccPortForPhone(int phoneId)195 public UiccPort getUiccPortForPhone(int phoneId) { 196 synchronized (mLock) { 197 return mUiccPorts.get(mPhoneIdToPortIdx.get(phoneId)); 198 } 199 } 200 201 /** 202 * Returns the UiccPort associated with the given port index. 203 */ getUiccPort(int portIdx)204 public UiccPort getUiccPort(int portIdx) { 205 synchronized (mLock) { 206 return mUiccPorts.get(portIdx); 207 } 208 } 209 210 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) log(String msg)211 private void log(String msg) { 212 Rlog.d(LOG_TAG, msg); 213 } 214 215 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) loge(String msg)216 private void loge(String msg) { 217 Rlog.e(LOG_TAG, msg); 218 } 219 dump(FileDescriptor fd, PrintWriter printWriter, String[] args)220 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 221 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 222 pw.println("UiccCard:"); 223 pw.increaseIndent(); 224 pw.println("mCardState=" + mCardState); 225 pw.println("mCardId=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mCardId)); 226 pw.println("mNumberOfPorts=" + mUiccPorts.size()); 227 pw.println("mSupportedMepMode=" + mSupportedMepMode); 228 pw.println("mUiccPorts= size=" + mUiccPorts.size()); 229 pw.increaseIndent(); 230 for (UiccPort uiccPort : mUiccPorts.values()) { 231 uiccPort.dump(fd, pw, args); 232 } 233 pw.decreaseIndent(); 234 pw.decreaseIndent(); 235 } 236 } 237