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