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