1 /*
2  * Copyright (C) 2017 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 package com.android.internal.telephony.euicc;
17 
18 import static android.telephony.euicc.EuiccCardManager.ResetOption;
19 
20 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
21 
22 import android.Manifest;
23 import android.annotation.Nullable;
24 import android.content.BroadcastReceiver;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.ServiceConnection;
30 import android.content.pm.ActivityInfo;
31 import android.content.pm.ComponentInfo;
32 import android.content.pm.PackageManager;
33 import android.content.pm.ResolveInfo;
34 import android.content.pm.ServiceInfo;
35 import android.os.Bundle;
36 import android.os.IBinder;
37 import android.os.Looper;
38 import android.os.Message;
39 import android.os.RemoteException;
40 import android.service.euicc.DownloadSubscriptionResult;
41 import android.service.euicc.EuiccService;
42 import android.service.euicc.GetDefaultDownloadableSubscriptionListResult;
43 import android.service.euicc.GetDownloadableSubscriptionMetadataResult;
44 import android.service.euicc.GetEuiccProfileInfoListResult;
45 import android.service.euicc.IDeleteSubscriptionCallback;
46 import android.service.euicc.IDownloadSubscriptionCallback;
47 import android.service.euicc.IEraseSubscriptionsCallback;
48 import android.service.euicc.IEuiccService;
49 import android.service.euicc.IEuiccServiceDumpResultCallback;
50 import android.service.euicc.IGetAvailableMemoryInBytesCallback;
51 import android.service.euicc.IGetDefaultDownloadableSubscriptionListCallback;
52 import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback;
53 import android.service.euicc.IGetEidCallback;
54 import android.service.euicc.IGetEuiccInfoCallback;
55 import android.service.euicc.IGetEuiccProfileInfoListCallback;
56 import android.service.euicc.IGetOtaStatusCallback;
57 import android.service.euicc.IOtaStatusChangedCallback;
58 import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback;
59 import android.service.euicc.ISwitchToSubscriptionCallback;
60 import android.service.euicc.IUpdateSubscriptionNicknameCallback;
61 import android.telephony.AnomalyReporter;
62 import android.telephony.SubscriptionManager;
63 import android.telephony.TelephonyManager;
64 import android.telephony.UiccCardInfo;
65 import android.telephony.UiccSlotInfo;
66 import android.telephony.euicc.DownloadableSubscription;
67 import android.telephony.euicc.EuiccInfo;
68 import android.telephony.euicc.EuiccManager;
69 import android.telephony.euicc.EuiccManager.OtaStatus;
70 import android.text.TextUtils;
71 import android.util.ArraySet;
72 import android.util.Log;
73 
74 import com.android.internal.annotations.VisibleForTesting;
75 import com.android.internal.telephony.PackageChangeReceiver;
76 import com.android.internal.telephony.uicc.IccUtils;
77 import com.android.internal.telephony.uicc.UiccController;
78 import com.android.internal.telephony.util.TelephonyUtils;
79 import com.android.internal.util.IState;
80 import com.android.internal.util.State;
81 import com.android.internal.util.StateMachine;
82 
83 import java.io.FileDescriptor;
84 import java.io.PrintWriter;
85 import java.util.List;
86 import java.util.Objects;
87 import java.util.Set;
88 import java.util.UUID;
89 
90 /**
91  * State machine which maintains the binding to the EuiccService implementation and issues commands.
92  *
93  * <p>Keeps track of the highest-priority EuiccService implementation to use. When a command comes
94  * in, brings up a binding to that service, issues the command, and lingers the binding as long as
95  * more commands are coming in. The binding is dropped after an idle timeout.
96  */
97 public class EuiccConnector extends StateMachine implements ServiceConnection {
98     private static final String TAG = "EuiccConnector";
99 
100     /**
101      * Maximum amount of time to wait for a connection to be established after bindService returns
102      * true or onServiceDisconnected is called (and no package change has occurred which should
103      * force us to reestablish the binding).
104      */
105     @VisibleForTesting
106     static final int BIND_TIMEOUT_MILLIS = 30000;
107 
108     /**
109      * Maximum amount of idle time to hold the binding while in {@link ConnectedState}. After this,
110      * the binding is dropped to free up memory as the EuiccService is not expected to be used
111      * frequently as part of ongoing device operation.
112      */
113     @VisibleForTesting
114     static final int LINGER_TIMEOUT_MILLIS = 60000;
115 
116     /**
117      * Command indicating that a package change has occurred.
118      *
119      * <p>{@link Message#obj} is an optional package name. If set, this package has changed in a
120      * way that will permanently sever any open bindings, and if we're bound to it, the binding must
121      * be forcefully reestablished.
122      */
123     private static final int CMD_PACKAGE_CHANGE = 1;
124     /** Command indicating that {@link #BIND_TIMEOUT_MILLIS} has been reached. */
125     private static final int CMD_CONNECT_TIMEOUT = 2;
126     /** Command indicating that {@link #LINGER_TIMEOUT_MILLIS} has been reached. */
127     private static final int CMD_LINGER_TIMEOUT = 3;
128     /**
129      * Command indicating that the service has connected.
130      *
131      * <p>{@link Message#obj} is the connected {@link IEuiccService} implementation.
132      */
133     private static final int CMD_SERVICE_CONNECTED = 4;
134     /** Command indicating that the service has disconnected. */
135     private static final int CMD_SERVICE_DISCONNECTED = 5;
136     /**
137      * Command indicating that a command has completed and the callback should be executed.
138      *
139      * <p>{@link Message#obj} is a {@link Runnable} which will trigger the callback.
140      */
141     private static final int CMD_COMMAND_COMPLETE = 6;
142 
143     // Commands corresponding with EuiccService APIs. Keep isEuiccCommand in sync with any changes.
144     private static final int CMD_GET_EID = 100;
145     private static final int CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA = 101;
146     private static final int CMD_DOWNLOAD_SUBSCRIPTION = 102;
147     private static final int CMD_GET_EUICC_PROFILE_INFO_LIST = 103;
148     private static final int CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST = 104;
149     private static final int CMD_GET_EUICC_INFO = 105;
150     private static final int CMD_DELETE_SUBSCRIPTION = 106;
151     private static final int CMD_SWITCH_TO_SUBSCRIPTION = 107;
152     private static final int CMD_UPDATE_SUBSCRIPTION_NICKNAME = 108;
153     private static final int CMD_ERASE_SUBSCRIPTIONS = 109;
154     private static final int CMD_RETAIN_SUBSCRIPTIONS = 110;
155     private static final int CMD_GET_OTA_STATUS = 111;
156     private static final int CMD_START_OTA_IF_NECESSARY = 112;
157     private static final int CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS = 113;
158     private static final int CMD_DUMP_EUICC_SERVICE = 114;
159     private static final int CMD_GET_AVAILABLE_MEMORY_IN_BYTES = 115;
160 
isEuiccCommand(int what)161     private static boolean isEuiccCommand(int what) {
162         return what >= CMD_GET_EID;
163     }
164 
165     /** Flags to use when querying PackageManager for Euicc component implementations. */
166     private static final int EUICC_QUERY_FLAGS =
167             PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_AUTO
168                     | PackageManager.GET_RESOLVED_FILTER;
169 
170     /**
171      * Return the activity info of the activity to start for the given intent, or null if none
172      * was found.
173      */
findBestActivity(PackageManager packageManager, Intent intent)174     public static ActivityInfo findBestActivity(PackageManager packageManager, Intent intent) {
175         List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent,
176                 EUICC_QUERY_FLAGS);
177         ActivityInfo bestComponent =
178                 (ActivityInfo) findBestComponent(packageManager, resolveInfoList);
179         if (bestComponent == null) {
180             Log.w(TAG, "No valid component found for intent: " + intent);
181         }
182         return bestComponent;
183     }
184 
185     /**
186      * Return the component info of the EuiccService to bind to, or null if none were found.
187      */
findBestComponent(PackageManager packageManager)188     public static ComponentInfo findBestComponent(PackageManager packageManager) {
189         Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE);
190         List<ResolveInfo> resolveInfoList =
191                 packageManager.queryIntentServices(intent, EUICC_QUERY_FLAGS);
192         ComponentInfo bestComponent = findBestComponent(packageManager, resolveInfoList);
193         if (bestComponent == null) {
194             Log.w(TAG, "No valid EuiccService implementation found");
195         }
196         return bestComponent;
197     }
198 
199     /** Base class for all command callbacks. */
200     @VisibleForTesting(visibility = PACKAGE)
201     public interface BaseEuiccCommandCallback {
202         /** Called when a command fails because the service is or became unavailable. */
onEuiccServiceUnavailable()203         void onEuiccServiceUnavailable();
204     }
205 
206     /** Callback class for {@link #getEid}. */
207     @VisibleForTesting(visibility = PACKAGE)
208     public interface GetEidCommandCallback extends BaseEuiccCommandCallback {
209         /** Called when the EID lookup has completed. */
onGetEidComplete(String eid)210         void onGetEidComplete(String eid);
211     }
212 
213     /** Callback class for {@link #getAvailableMemoryInBytes}. */
214     @VisibleForTesting(visibility = PACKAGE)
215     public interface GetAvailableMemoryInBytesCommandCallback extends BaseEuiccCommandCallback {
216         /** Called when the available memory in bytes lookup has completed. */
onGetAvailableMemoryInBytesComplete(long availableMemoryInBytes)217         void onGetAvailableMemoryInBytesComplete(long availableMemoryInBytes);
218         /**
219          * Called when the connected LPA does not implement
220          * EuiccService#onGetAvailableMemoryInBytes(int).
221          */
onUnsupportedOperationExceptionComplete(String message)222         void onUnsupportedOperationExceptionComplete(String message);
223     }
224 
225     /** Callback class for {@link #getOtaStatus}. */
226     @VisibleForTesting(visibility = PACKAGE)
227     public interface GetOtaStatusCommandCallback extends BaseEuiccCommandCallback {
228         /** Called when the getting OTA status lookup has completed. */
onGetOtaStatusComplete(@taStatus int status)229         void onGetOtaStatusComplete(@OtaStatus int status);
230     }
231 
232     /** Callback class for {@link #startOtaIfNecessary}. */
233     @VisibleForTesting(visibility = PACKAGE)
234     public interface OtaStatusChangedCallback extends BaseEuiccCommandCallback {
235         /**
236          * Called when OTA status is changed to {@link EuiccM}. */
onOtaStatusChanged(int status)237         void onOtaStatusChanged(int status);
238     }
239 
240     static class GetMetadataRequest {
241         DownloadableSubscription mSubscription;
242         boolean mForceDeactivateSim;
243         boolean mSwitchAfterDownload;
244         int mPortIndex;
245         GetMetadataCommandCallback mCallback;
246     }
247 
248     /** Callback class for {@link #getDownloadableSubscriptionMetadata}. */
249     @VisibleForTesting(visibility = PACKAGE)
250     public interface GetMetadataCommandCallback extends BaseEuiccCommandCallback {
251         /** Called when the metadata lookup has completed (though it may have failed). */
onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result)252         void onGetMetadataComplete(int cardId, GetDownloadableSubscriptionMetadataResult result);
253     }
254 
255     static class DownloadRequest {
256         DownloadableSubscription mSubscription;
257         boolean mSwitchAfterDownload;
258         boolean mForceDeactivateSim;
259         DownloadCommandCallback mCallback;
260         int mPortIndex;
261         Bundle mResolvedBundle;
262     }
263 
264     /** Callback class for {@link #downloadSubscription}. */
265     @VisibleForTesting(visibility = PACKAGE)
266     public interface DownloadCommandCallback extends BaseEuiccCommandCallback {
267         /** Called when the download has completed (though it may have failed). */
onDownloadComplete(DownloadSubscriptionResult result)268         void onDownloadComplete(DownloadSubscriptionResult result);
269     }
270 
271     interface GetEuiccProfileInfoListCommandCallback extends BaseEuiccCommandCallback {
272         /** Called when the list has completed (though it may have failed). */
onListComplete(GetEuiccProfileInfoListResult result)273         void onListComplete(GetEuiccProfileInfoListResult result);
274     }
275 
276     static class GetDefaultListRequest {
277         boolean mForceDeactivateSim;
278         GetDefaultListCommandCallback mCallback;
279     }
280 
281     /** Callback class for {@link #getDefaultDownloadableSubscriptionList}. */
282     @VisibleForTesting(visibility = PACKAGE)
283     public interface GetDefaultListCommandCallback extends BaseEuiccCommandCallback {
284         /** Called when the list has completed (though it may have failed). */
onGetDefaultListComplete(int cardId, GetDefaultDownloadableSubscriptionListResult result)285         void onGetDefaultListComplete(int cardId,
286                 GetDefaultDownloadableSubscriptionListResult result);
287     }
288 
289     /** Callback class for {@link #getEuiccInfo}. */
290     @VisibleForTesting(visibility = PACKAGE)
291     public interface GetEuiccInfoCommandCallback extends BaseEuiccCommandCallback {
292         /** Called when the EuiccInfo lookup has completed. */
onGetEuiccInfoComplete(EuiccInfo euiccInfo)293         void onGetEuiccInfoComplete(EuiccInfo euiccInfo);
294     }
295 
296     static class DeleteRequest {
297         String mIccid;
298         DeleteCommandCallback mCallback;
299     }
300 
301     /** Callback class for {@link #deleteSubscription}. */
302     @VisibleForTesting(visibility = PACKAGE)
303     public interface DeleteCommandCallback extends BaseEuiccCommandCallback {
304         /** Called when the delete has completed (though it may have failed). */
onDeleteComplete(int result)305         void onDeleteComplete(int result);
306     }
307 
308     static class SwitchRequest {
309         @Nullable String mIccid;
310         boolean mForceDeactivateSim;
311         SwitchCommandCallback mCallback;
312         boolean mUsePortIndex;
313     }
314 
315     /** Callback class for {@link #switchToSubscription}. */
316     @VisibleForTesting(visibility = PACKAGE)
317     public interface SwitchCommandCallback extends BaseEuiccCommandCallback {
318         /** Called when the switch has completed (though it may have failed). */
onSwitchComplete(int result)319         void onSwitchComplete(int result);
320     }
321 
322     static class UpdateNicknameRequest {
323         String mIccid;
324         String mNickname;
325         UpdateNicknameCommandCallback mCallback;
326     }
327 
328     /** Callback class for {@link #updateSubscriptionNickname}. */
329     @VisibleForTesting(visibility = PACKAGE)
330     public interface UpdateNicknameCommandCallback extends BaseEuiccCommandCallback {
331         /** Called when the update has completed (though it may have failed). */
onUpdateNicknameComplete(int result)332         void onUpdateNicknameComplete(int result);
333     }
334 
335     /**
336      * Callback class for {@link #eraseSubscriptions} and {@link #eraseSubscriptionsWithOptions}.
337      */
338     @VisibleForTesting(visibility = PACKAGE)
339     public interface EraseCommandCallback extends BaseEuiccCommandCallback {
340         /** Called when the erase has completed (though it may have failed). */
onEraseComplete(int result)341         void onEraseComplete(int result);
342     }
343 
344     /** Callback class for {@link #retainSubscriptions}. */
345     @VisibleForTesting(visibility = PACKAGE)
346     public interface RetainSubscriptionsCommandCallback extends BaseEuiccCommandCallback {
347         /** Called when the retain command has completed (though it may have failed). */
onRetainSubscriptionsComplete(int result)348         void onRetainSubscriptionsComplete(int result);
349     }
350 
351     /** Callback class for {@link #dumpEuiccService(DumpEuiccCommandCallback)}   }*/
352     @VisibleForTesting(visibility = PACKAGE)
353     public interface DumpEuiccServiceCommandCallback extends BaseEuiccCommandCallback {
354         /** Called when the retain command has completed (though it may have failed). */
onDumpEuiccServiceComplete(String logs)355         void onDumpEuiccServiceComplete(String logs);
356     }
357 
358     private Context mContext;
359     private PackageManager mPm;
360     private TelephonyManager mTm;
361     private SubscriptionManager mSm;
362 
363     private final PackageChangeReceiver mPackageMonitor = new EuiccPackageMonitor();
364     private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() {
365         @Override
366         public void onReceive(Context context, Intent intent) {
367             if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
368                 // On user unlock, new components might become available, so rebind if needed. This
369                 // can never make a component unavailable so there's never a need to force a
370                 // rebind.
371                 sendMessage(CMD_PACKAGE_CHANGE);
372             }
373         }
374     };
375 
376     /** Set to the current component we should bind to except in {@link UnavailableState}. */
377     private @Nullable ServiceInfo mSelectedComponent;
378 
379     /** Set to the currently connected EuiccService implementation in {@link ConnectedState}. */
380     private @Nullable IEuiccService mEuiccService;
381 
382     /** The callbacks for all (asynchronous) commands which are currently in flight. */
383     private Set<BaseEuiccCommandCallback> mActiveCommandCallbacks = new ArraySet<>();
384 
385     @VisibleForTesting(visibility = PACKAGE) public UnavailableState mUnavailableState;
386     @VisibleForTesting(visibility = PACKAGE) public AvailableState mAvailableState;
387     @VisibleForTesting(visibility = PACKAGE) public BindingState mBindingState;
388     @VisibleForTesting(visibility = PACKAGE) public DisconnectedState mDisconnectedState;
389     @VisibleForTesting(visibility = PACKAGE) public ConnectedState mConnectedState;
390 
EuiccConnector(Context context)391     EuiccConnector(Context context) {
392         super(TAG);
393         init(context);
394     }
395 
396     @VisibleForTesting(visibility = PACKAGE)
EuiccConnector(Context context, Looper looper)397     public EuiccConnector(Context context, Looper looper) {
398         super(TAG, looper);
399         init(context);
400     }
401 
init(Context context)402     private void init(Context context) {
403         mContext = context;
404         mPm = context.getPackageManager();
405         mTm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
406         mSm = (SubscriptionManager)
407                 context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
408 
409         // TODO(b/239277548): Disable debug logging after analysing this bug.
410         setDbg(true);
411 
412         // Unavailable/Available both monitor for package changes and update mSelectedComponent but
413         // do not need to adjust the binding.
414         mUnavailableState = new UnavailableState();
415         addState(mUnavailableState);
416         mAvailableState = new AvailableState();
417         addState(mAvailableState, mUnavailableState);
418 
419         mBindingState = new BindingState();
420         addState(mBindingState);
421 
422         // Disconnected/Connected both monitor for package changes and reestablish the active
423         // binding if necessary.
424         mDisconnectedState = new DisconnectedState();
425         addState(mDisconnectedState);
426         mConnectedState = new ConnectedState();
427         addState(mConnectedState, mDisconnectedState);
428 
429         mSelectedComponent = findBestComponent();
430         setInitialState(mSelectedComponent != null ? mAvailableState : mUnavailableState);
431 
432         start();
433 
434         // All app package changes could trigger the package monitor receiver. It is not limited to
435         // apps extended from EuiccService.
436         mPackageMonitor.register(mContext, null /* thread */, null /* user */);
437         mContext.registerReceiver(
438                 mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
439     }
440 
441     @Override
onHalting()442     public void onHalting() {
443         mPackageMonitor.unregister();
444         mContext.unregisterReceiver(mUserUnlockedReceiver);
445     }
446 
447     /** Asynchronously fetch the EID. */
448     @VisibleForTesting(visibility = PACKAGE)
getEid(int cardId, GetEidCommandCallback callback)449     public void getEid(int cardId, GetEidCommandCallback callback) {
450         sendMessage(CMD_GET_EID, cardId, 0 /* arg2 */, callback);
451     }
452 
453     /** Asynchronously fetch the available memory in bytes. */
454     @VisibleForTesting(visibility = PACKAGE)
getAvailableMemoryInBytes( int cardId, GetAvailableMemoryInBytesCommandCallback callback)455     public void getAvailableMemoryInBytes(
456             int cardId, GetAvailableMemoryInBytesCommandCallback callback) {
457         sendMessage(CMD_GET_AVAILABLE_MEMORY_IN_BYTES, cardId, 0 /* arg2 */, callback);
458     }
459 
460     /** Asynchronously get OTA status. */
461     @VisibleForTesting(visibility = PACKAGE)
getOtaStatus(int cardId, GetOtaStatusCommandCallback callback)462     public void getOtaStatus(int cardId, GetOtaStatusCommandCallback callback) {
463         sendMessage(CMD_GET_OTA_STATUS, cardId, 0 /* arg2 */, callback);
464     }
465 
466     /** Asynchronously perform OTA update. */
467     @VisibleForTesting(visibility = PACKAGE)
startOtaIfNecessary(int cardId, OtaStatusChangedCallback callback)468     public void startOtaIfNecessary(int cardId, OtaStatusChangedCallback callback) {
469         sendMessage(CMD_START_OTA_IF_NECESSARY, cardId, 0 /* arg2 */, callback);
470     }
471 
472     /** Asynchronously fetch metadata for the given downloadable subscription. */
473     @VisibleForTesting(visibility = PACKAGE)
getDownloadableSubscriptionMetadata(int cardId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, GetMetadataCommandCallback callback)474     public void getDownloadableSubscriptionMetadata(int cardId, int portIndex,
475             DownloadableSubscription subscription, boolean switchAfterDownload,
476             boolean forceDeactivateSim, GetMetadataCommandCallback callback) {
477         GetMetadataRequest request =
478                 new GetMetadataRequest();
479         request.mSubscription = subscription;
480         request.mForceDeactivateSim = forceDeactivateSim;
481         request.mSwitchAfterDownload = switchAfterDownload;
482         request.mPortIndex = portIndex;
483         request.mCallback = callback;
484         sendMessage(CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA, cardId, 0 /* arg2 */, request);
485     }
486 
487     /** Asynchronously download the given subscription. */
488     @VisibleForTesting(visibility = PACKAGE)
downloadSubscription(int cardId, int portIndex, DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, Bundle resolvedBundle, DownloadCommandCallback callback)489     public void downloadSubscription(int cardId, int portIndex,
490             DownloadableSubscription subscription, boolean switchAfterDownload,
491             boolean forceDeactivateSim, Bundle resolvedBundle, DownloadCommandCallback callback) {
492         DownloadRequest request = new DownloadRequest();
493         request.mSubscription = subscription;
494         request.mSwitchAfterDownload = switchAfterDownload;
495         request.mForceDeactivateSim = forceDeactivateSim;
496         request.mResolvedBundle = resolvedBundle;
497         request.mCallback = callback;
498         request.mPortIndex = portIndex;
499         sendMessage(CMD_DOWNLOAD_SUBSCRIPTION, cardId, 0 /* arg2 */, request);
500     }
501 
getEuiccProfileInfoList(int cardId, GetEuiccProfileInfoListCommandCallback callback)502     void getEuiccProfileInfoList(int cardId, GetEuiccProfileInfoListCommandCallback callback) {
503         sendMessage(CMD_GET_EUICC_PROFILE_INFO_LIST, cardId, 0 /* arg2 */, callback);
504     }
505 
506     /** Asynchronously fetch the default downloadable subscription list. */
507     @VisibleForTesting(visibility = PACKAGE)
getDefaultDownloadableSubscriptionList(int cardId, boolean forceDeactivateSim, GetDefaultListCommandCallback callback)508     public void getDefaultDownloadableSubscriptionList(int cardId,
509             boolean forceDeactivateSim, GetDefaultListCommandCallback callback) {
510         GetDefaultListRequest request = new GetDefaultListRequest();
511         request.mForceDeactivateSim = forceDeactivateSim;
512         request.mCallback = callback;
513         sendMessage(CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST, cardId, 0 /* arg2 */, request);
514     }
515 
516     /** Asynchronously fetch the {@link EuiccInfo}. */
517     @VisibleForTesting(visibility = PACKAGE)
getEuiccInfo(int cardId, GetEuiccInfoCommandCallback callback)518     public void getEuiccInfo(int cardId, GetEuiccInfoCommandCallback callback) {
519         sendMessage(CMD_GET_EUICC_INFO, cardId, 0 /* arg2 */, callback);
520     }
521 
522     /** Asynchronously delete the given subscription. */
523     @VisibleForTesting(visibility = PACKAGE)
deleteSubscription(int cardId, String iccid, DeleteCommandCallback callback)524     public void deleteSubscription(int cardId, String iccid, DeleteCommandCallback callback) {
525         DeleteRequest request = new DeleteRequest();
526         request.mIccid = iccid;
527         request.mCallback = callback;
528         sendMessage(CMD_DELETE_SUBSCRIPTION, cardId, 0 /* arg2 */, request);
529     }
530 
531     /** Asynchronously switch to the given subscription. */
532     @VisibleForTesting(visibility = PACKAGE)
switchToSubscription(int cardId, int portIndex, @Nullable String iccid, boolean forceDeactivateSim, SwitchCommandCallback callback, boolean usePortIndex)533     public void switchToSubscription(int cardId, int portIndex, @Nullable String iccid,
534             boolean forceDeactivateSim, SwitchCommandCallback callback, boolean usePortIndex) {
535         SwitchRequest request = new SwitchRequest();
536         request.mIccid = iccid;
537         request.mForceDeactivateSim = forceDeactivateSim;
538         request.mCallback = callback;
539         request.mUsePortIndex = usePortIndex;
540         sendMessage(CMD_SWITCH_TO_SUBSCRIPTION, cardId, portIndex, request);
541     }
542 
543     /** Asynchronously update the nickname of the given subscription. */
544     @VisibleForTesting(visibility = PACKAGE)
updateSubscriptionNickname(int cardId, String iccid, String nickname, UpdateNicknameCommandCallback callback)545     public void updateSubscriptionNickname(int cardId,
546             String iccid, String nickname, UpdateNicknameCommandCallback callback) {
547         UpdateNicknameRequest request = new UpdateNicknameRequest();
548         request.mIccid = iccid;
549         request.mNickname = nickname;
550         request.mCallback = callback;
551         sendMessage(CMD_UPDATE_SUBSCRIPTION_NICKNAME, cardId, 0 /* arg2 */, request);
552     }
553 
554     /** Asynchronously erase operational profiles on the eUICC. */
555     @VisibleForTesting(visibility = PACKAGE)
eraseSubscriptions(int cardId, EraseCommandCallback callback)556     public void eraseSubscriptions(int cardId, EraseCommandCallback callback) {
557         sendMessage(CMD_ERASE_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback);
558     }
559 
560     /** Asynchronously erase specific profiles on the eUICC. */
561     @VisibleForTesting(visibility = PACKAGE)
eraseSubscriptionsWithOptions( int cardId, @ResetOption int options, EraseCommandCallback callback)562     public void eraseSubscriptionsWithOptions(
563             int cardId, @ResetOption int options, EraseCommandCallback callback) {
564         sendMessage(CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS, cardId, options, callback);
565     }
566 
567     /** Asynchronously ensure that all profiles will be retained on the next factory reset. */
568     @VisibleForTesting(visibility = PACKAGE)
retainSubscriptions(int cardId, RetainSubscriptionsCommandCallback callback)569     public void retainSubscriptions(int cardId, RetainSubscriptionsCommandCallback callback) {
570         sendMessage(CMD_RETAIN_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback);
571     }
572 
573     /** Asynchronously calls the currently bound EuiccService implementation to dump its states */
574     @VisibleForTesting(visibility = PACKAGE)
dumpEuiccService(DumpEuiccServiceCommandCallback callback)575     public void dumpEuiccService(DumpEuiccServiceCommandCallback callback) {
576         sendMessage(CMD_DUMP_EUICC_SERVICE, TelephonyManager.UNSUPPORTED_CARD_ID /* ignored */,
577                 0 /* arg2 */,
578                 callback);
579     }
580 
581     @VisibleForTesting
getBinder()582     public final IEuiccService getBinder() {
583         return mEuiccService;
584     }
585 
586     /**
587      * State in which no EuiccService is available.
588      *
589      * <p>All incoming commands will be rejected through
590      * {@link BaseEuiccCommandCallback#onEuiccServiceUnavailable()}.
591      *
592      * <p>Package state changes will lead to transitions between {@link UnavailableState} and
593      * {@link AvailableState} depending on whether an EuiccService becomes unavailable or
594      * available.
595      */
596     private class UnavailableState extends State {
597         @Override
processMessage(Message message)598         public boolean processMessage(Message message) {
599             if (message.what == CMD_PACKAGE_CHANGE) {
600                 mSelectedComponent = findBestComponent();
601                 if (mSelectedComponent != null) {
602                     transitionTo(mAvailableState);
603                     updateSubscriptionInfoListForAllAccessibleEuiccs();
604                 } else if (getCurrentState() != mUnavailableState) {
605                     transitionTo(mUnavailableState);
606                 }
607                 return HANDLED;
608             } else if (isEuiccCommand(message.what)) {
609                 BaseEuiccCommandCallback callback = getCallback(message);
610                 callback.onEuiccServiceUnavailable();
611                 return HANDLED;
612             }
613 
614             return NOT_HANDLED;
615         }
616     }
617 
618     /**
619      * State in which a EuiccService is available, but no binding is established or in the process
620      * of being established.
621      *
622      * <p>If a command is received, this state will defer the message and enter {@link BindingState}
623      * to bring up the binding.
624      */
625     private class AvailableState extends State {
626         @Override
processMessage(Message message)627         public boolean processMessage(Message message) {
628             if (isEuiccCommand(message.what)) {
629                 deferMessage(message);
630                 transitionTo(mBindingState);
631                 return HANDLED;
632             }
633 
634             return NOT_HANDLED;
635         }
636     }
637 
638     /**
639      * State in which we are binding to the current EuiccService.
640      *
641      * <p>This is a transient state. If bindService returns true, we enter {@link DisconnectedState}
642      * while waiting for the binding to be established. If it returns false, we move back to
643      * {@link AvailableState}.
644      *
645      * <p>Any received messages will be deferred.
646      */
647     private class BindingState extends State {
648         @Override
enter()649         public void enter() {
650             if (createBinding()) {
651                 transitionTo(mDisconnectedState);
652             } else {
653                 // createBinding() should generally not return false since we've already performed
654                 // Intent resolution, but it's always possible that the package state changes
655                 // asynchronously. Transition to available for now, and if the package state has
656                 // changed, we'll process that event and move to mUnavailableState as needed.
657                 transitionTo(mAvailableState);
658             }
659         }
660 
661         @Override
processMessage(Message message)662         public boolean processMessage(Message message) {
663             deferMessage(message);
664             return HANDLED;
665         }
666     }
667 
668     /**
669      * State in which a binding is established, but not currently connected.
670      *
671      * <p>We wait up to {@link #BIND_TIMEOUT_MILLIS} for the binding to establish. If it doesn't,
672      * we go back to {@link AvailableState} to try again.
673      *
674      * <p>Package state changes will cause us to unbind and move to {@link BindingState} to
675      * reestablish the binding if the selected component has changed or if a forced rebind is
676      * necessary.
677      *
678      * <p>Any received commands will be deferred.
679      */
680     private class DisconnectedState extends State {
681         @Override
enter()682         public void enter() {
683             sendMessageDelayed(CMD_CONNECT_TIMEOUT, BIND_TIMEOUT_MILLIS);
684         }
685 
686         @Override
processMessage(Message message)687         public boolean processMessage(Message message) {
688             if (message.what == CMD_SERVICE_CONNECTED) {
689                 mEuiccService = (IEuiccService) message.obj;
690                 transitionTo(mConnectedState);
691                 return HANDLED;
692             } else if (message.what == CMD_PACKAGE_CHANGE) {
693                 ServiceInfo bestComponent = findBestComponent();
694                 String affectedPackage = (String) message.obj;
695                 boolean isSameComponent;
696                 if (bestComponent == null) {
697                     isSameComponent = mSelectedComponent != null;
698                 } else {
699                     // Checks whether the bound component is the same as the best component. If it
700                     // is not, set isSameComponent to false and the connector will bind the best
701                     // component instead.
702                     isSameComponent = mSelectedComponent == null
703                             || Objects.equals(new ComponentName(bestComponent.packageName,
704                             bestComponent.name),
705                         new ComponentName(mSelectedComponent.packageName, mSelectedComponent.name));
706                 }
707                 // Checks whether the bound component is impacted by the package changes. If it is,
708                 // change the forceRebind to true so the connector will re-bind the component.
709                 boolean forceRebind = bestComponent != null
710                         && Objects.equals(bestComponent.packageName, affectedPackage);
711                 if (!isSameComponent || forceRebind) {
712                     unbind();
713                     mSelectedComponent = bestComponent;
714                     if (mSelectedComponent == null) {
715                         transitionTo(mUnavailableState);
716                     } else {
717                         transitionTo(mBindingState);
718                     }
719                     updateSubscriptionInfoListForAllAccessibleEuiccs();
720                 }
721                 return HANDLED;
722             } else if (message.what == CMD_CONNECT_TIMEOUT) {
723                 unbind();
724                 transitionTo(mAvailableState);
725                 return HANDLED;
726             } else if (isEuiccCommand(message.what)) {
727                 deferMessage(message);
728                 return HANDLED;
729             }
730 
731             return NOT_HANDLED;
732         }
733     }
734 
735     /**
736      * State in which the binding is connected.
737      *
738      * <p>Commands will be processed as long as we're in this state. We wait up to
739      * {@link #LINGER_TIMEOUT_MILLIS} between commands; if this timeout is reached, we will drop the
740      * binding until the next command is received.
741      */
742     private class ConnectedState extends State {
743         @Override
enter()744         public void enter() {
745             removeMessages(CMD_CONNECT_TIMEOUT);
746             sendMessageDelayed(CMD_LINGER_TIMEOUT, LINGER_TIMEOUT_MILLIS);
747         }
748 
749         @Override
processMessage(Message message)750         public boolean processMessage(Message message) {
751             if (message.what == CMD_SERVICE_DISCONNECTED) {
752                 mEuiccService = null;
753                 transitionTo(mDisconnectedState);
754                 return HANDLED;
755             } else if (message.what == CMD_LINGER_TIMEOUT) {
756                 unbind();
757                 transitionTo(mAvailableState);
758                 return HANDLED;
759             } else if (message.what == CMD_COMMAND_COMPLETE) {
760                 Runnable runnable = (Runnable) message.obj;
761                 runnable.run();
762                 return HANDLED;
763             } else if (isEuiccCommand(message.what)) {
764                 final BaseEuiccCommandCallback callback = getCallback(message);
765                 onCommandStart(callback);
766                 final int cardId = message.arg1;
767                 final int slotId = getSlotIdFromCardId(cardId);
768                 try {
769                     switch (message.what) {
770                         case CMD_GET_EID: {
771                             mEuiccService.getEid(slotId,
772                                     new IGetEidCallback.Stub() {
773                                         @Override
774                                         public void onSuccess(String eid) {
775                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
776                                                 ((GetEidCommandCallback) callback)
777                                                         .onGetEidComplete(eid);
778                                                 onCommandEnd(callback);
779                                             });
780                                         }
781                                     });
782                             break;
783                         }
784                         case CMD_GET_AVAILABLE_MEMORY_IN_BYTES: {
785                             mEuiccService.getAvailableMemoryInBytes(slotId,
786                                     new IGetAvailableMemoryInBytesCallback.Stub() {
787                                         @Override
788                                         public void onSuccess(long availableMemoryInBytes) {
789                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
790                                                 ((GetAvailableMemoryInBytesCommandCallback)
791                                                         callback)
792                                                         .onGetAvailableMemoryInBytesComplete(
793                                                                 availableMemoryInBytes);
794                                                 onCommandEnd(callback);
795                                             });
796                                         }
797 
798                                         @Override
799                                         public void onUnsupportedOperationException(
800                                                 String message) {
801                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
802                                                 ((GetAvailableMemoryInBytesCommandCallback)
803                                                         callback)
804                                                         .onUnsupportedOperationExceptionComplete(
805                                                             message);
806                                                 onCommandEnd(callback);
807                                             });
808                                         }
809                                     });
810                             break;
811                         }
812                         case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA: {
813                             GetMetadataRequest request = (GetMetadataRequest) message.obj;
814                             mEuiccService.getDownloadableSubscriptionMetadata(slotId,
815                                     request.mPortIndex,
816                                     request.mSubscription,
817                                     request.mSwitchAfterDownload,
818                                     request.mForceDeactivateSim,
819                                     new IGetDownloadableSubscriptionMetadataCallback.Stub() {
820                                         @Override
821                                         public void onComplete(
822                                                 GetDownloadableSubscriptionMetadataResult result) {
823                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
824                                                 ((GetMetadataCommandCallback) callback)
825                                                         .onGetMetadataComplete(cardId, result);
826                                                 onCommandEnd(callback);
827                                             });
828                                         }
829                                     });
830                             break;
831                         }
832                         case CMD_DOWNLOAD_SUBSCRIPTION: {
833                             DownloadRequest request = (DownloadRequest) message.obj;
834                             mEuiccService.downloadSubscription(slotId,
835                                     request.mPortIndex,
836                                     request.mSubscription,
837                                     request.mSwitchAfterDownload,
838                                     request.mForceDeactivateSim,
839                                     request.mResolvedBundle,
840                                     new IDownloadSubscriptionCallback.Stub() {
841                                         @Override
842                                         public void onComplete(DownloadSubscriptionResult result) {
843                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
844                                                 ((DownloadCommandCallback) callback)
845                                                     .onDownloadComplete(result);
846                                                 onCommandEnd(callback);
847                                             });
848                                         }
849                                     });
850                             break;
851                         }
852                         case CMD_GET_EUICC_PROFILE_INFO_LIST: {
853                             mEuiccService.getEuiccProfileInfoList(slotId,
854                                     new IGetEuiccProfileInfoListCallback.Stub() {
855                                         @Override
856                                         public void onComplete(
857                                                 GetEuiccProfileInfoListResult result) {
858                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
859                                                 ((GetEuiccProfileInfoListCommandCallback) callback)
860                                                         .onListComplete(result);
861                                                 onCommandEnd(callback);
862                                             });
863                                         }
864                                     });
865                             break;
866                         }
867                         case CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST: {
868                             GetDefaultListRequest request = (GetDefaultListRequest) message.obj;
869                             mEuiccService.getDefaultDownloadableSubscriptionList(slotId,
870                                     request.mForceDeactivateSim,
871                                     new IGetDefaultDownloadableSubscriptionListCallback.Stub() {
872                                         @Override
873                                         public void onComplete(
874                                                 GetDefaultDownloadableSubscriptionListResult result
875                                         ) {
876                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
877                                                 ((GetDefaultListCommandCallback) callback)
878                                                         .onGetDefaultListComplete(cardId, result);
879                                                 onCommandEnd(callback);
880                                             });
881                                         }
882                                     });
883                             break;
884                         }
885                         case CMD_GET_EUICC_INFO: {
886                             mEuiccService.getEuiccInfo(slotId,
887                                     new IGetEuiccInfoCallback.Stub() {
888                                         @Override
889                                         public void onSuccess(EuiccInfo euiccInfo) {
890                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
891                                                 ((GetEuiccInfoCommandCallback) callback)
892                                                         .onGetEuiccInfoComplete(euiccInfo);
893                                                 onCommandEnd(callback);
894                                             });
895                                         }
896                                     });
897                             break;
898                         }
899                         case CMD_DELETE_SUBSCRIPTION: {
900                             DeleteRequest request = (DeleteRequest) message.obj;
901                             mEuiccService.deleteSubscription(slotId, request.mIccid,
902                                     new IDeleteSubscriptionCallback.Stub() {
903                                         @Override
904                                         public void onComplete(int result) {
905                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
906                                                 ((DeleteCommandCallback) callback)
907                                                         .onDeleteComplete(result);
908                                                 onCommandEnd(callback);
909                                             });
910                                         }
911                                     });
912                             break;
913                         }
914                         case CMD_SWITCH_TO_SUBSCRIPTION: {
915                             SwitchRequest request = (SwitchRequest) message.obj;
916                             final int portIndex = message.arg2;
917                             mEuiccService.switchToSubscription(slotId, portIndex,
918                                     request.mIccid,
919                                     request.mForceDeactivateSim,
920                                     new ISwitchToSubscriptionCallback.Stub() {
921                                         @Override
922                                         public void onComplete(int result) {
923                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
924                                                 ((SwitchCommandCallback) callback)
925                                                         .onSwitchComplete(result);
926                                                 onCommandEnd(callback);
927                                             });
928                                         }
929                                     },
930                                     request.mUsePortIndex);
931                             break;
932                         }
933                         case CMD_UPDATE_SUBSCRIPTION_NICKNAME: {
934                             UpdateNicknameRequest request = (UpdateNicknameRequest) message.obj;
935                             mEuiccService.updateSubscriptionNickname(slotId, request.mIccid,
936                                     request.mNickname,
937                                     new IUpdateSubscriptionNicknameCallback.Stub() {
938                                         @Override
939                                         public void onComplete(int result) {
940                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
941                                                 ((UpdateNicknameCommandCallback) callback)
942                                                         .onUpdateNicknameComplete(result);
943                                                 onCommandEnd(callback);
944                                             });
945                                         }
946                                     });
947                             break;
948                         }
949                         case CMD_ERASE_SUBSCRIPTIONS: {
950                             mEuiccService.eraseSubscriptions(slotId,
951                                     new IEraseSubscriptionsCallback.Stub() {
952                                         @Override
953                                         public void onComplete(int result) {
954                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
955                                                 ((EraseCommandCallback) callback)
956                                                         .onEraseComplete(result);
957                                                 onCommandEnd(callback);
958                                             });
959                                         }
960                                     });
961                             break;
962                         }
963                         case CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS: {
964                             mEuiccService.eraseSubscriptionsWithOptions(slotId,
965                                     message.arg2 /* options */,
966                                     new IEraseSubscriptionsCallback.Stub() {
967                                         @Override
968                                         public void onComplete(int result) {
969                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
970                                                 ((EraseCommandCallback) callback)
971                                                         .onEraseComplete(result);
972                                                 onCommandEnd(callback);
973                                             });
974                                         }
975                                     });
976                             break;
977                         }
978                         case CMD_RETAIN_SUBSCRIPTIONS: {
979                             mEuiccService.retainSubscriptionsForFactoryReset(slotId,
980                                     new IRetainSubscriptionsForFactoryResetCallback.Stub() {
981                                         @Override
982                                         public void onComplete(int result) {
983                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
984                                                 ((RetainSubscriptionsCommandCallback) callback)
985                                                         .onRetainSubscriptionsComplete(result);
986                                                 onCommandEnd(callback);
987                                             });
988                                         }
989                                     });
990                             break;
991                         }
992                         case CMD_GET_OTA_STATUS: {
993                             mEuiccService.getOtaStatus(slotId,
994                                     new IGetOtaStatusCallback.Stub() {
995                                         @Override
996                                         public void onSuccess(@OtaStatus int status) {
997                                             sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
998                                                 ((GetOtaStatusCommandCallback) callback)
999                                                         .onGetOtaStatusComplete(status);
1000                                                 onCommandEnd(callback);
1001                                             });
1002                                         }
1003                                     });
1004                             break;
1005                         }
1006                         case CMD_START_OTA_IF_NECESSARY: {
1007                             mEuiccService.startOtaIfNecessary(slotId,
1008                                     new IOtaStatusChangedCallback.Stub() {
1009                                         @Override
1010                                         public void onOtaStatusChanged(int status)
1011                                                 throws RemoteException {
1012                                             if (status == EuiccManager.EUICC_OTA_IN_PROGRESS) {
1013                                                 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
1014                                                     ((OtaStatusChangedCallback) callback)
1015                                                             .onOtaStatusChanged(status);
1016                                                 });
1017                                             } else {
1018                                                 sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
1019                                                     ((OtaStatusChangedCallback) callback)
1020                                                             .onOtaStatusChanged(status);
1021                                                     onCommandEnd(callback);
1022                                                 });
1023                                             }
1024                                         }
1025                                     });
1026                             break;
1027                         }
1028                         case CMD_DUMP_EUICC_SERVICE: {
1029                             mEuiccService.dump(new IEuiccServiceDumpResultCallback.Stub() {
1030                                 @Override
1031                                 public void onComplete(String logs)
1032                                         throws RemoteException {
1033                                     sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
1034                                         ((DumpEuiccServiceCommandCallback) callback)
1035                                                 .onDumpEuiccServiceComplete(logs);
1036                                         onCommandEnd(callback);
1037                                     });
1038                                 }
1039                             });
1040                             break;
1041                         }
1042                         default: {
1043                             Log.wtf(TAG, "Unimplemented eUICC command: " + message.what);
1044                             callback.onEuiccServiceUnavailable();
1045                             onCommandEnd(callback);
1046                             return HANDLED;
1047                         }
1048                     }
1049                 } catch (Exception e) {
1050                     // If this is a RemoteException, we expect to be disconnected soon. For other
1051                     // exceptions, this is a bug in the EuiccService implementation, but we must
1052                     // not let it crash the phone process.
1053                     Log.w(TAG, "Exception making binder call to EuiccService", e);
1054                     callback.onEuiccServiceUnavailable();
1055                     onCommandEnd(callback);
1056                 }
1057 
1058                 return HANDLED;
1059             }
1060 
1061             return NOT_HANDLED;
1062         }
1063 
1064         @Override
exit()1065         public void exit() {
1066             removeMessages(CMD_LINGER_TIMEOUT);
1067             // Dispatch callbacks for all in-flight commands; they will no longer succeed. (The
1068             // remote process cannot possibly trigger a callback at this stage because the
1069             // connection has dropped).
1070             for (BaseEuiccCommandCallback callback : mActiveCommandCallbacks) {
1071                 callback.onEuiccServiceUnavailable();
1072             }
1073             mActiveCommandCallbacks.clear();
1074         }
1075     }
1076 
getCallback(Message message)1077     private static BaseEuiccCommandCallback getCallback(Message message) {
1078         switch (message.what) {
1079             case CMD_GET_EID:
1080             case CMD_GET_EUICC_PROFILE_INFO_LIST:
1081             case CMD_GET_EUICC_INFO:
1082             case CMD_ERASE_SUBSCRIPTIONS:
1083             case CMD_ERASE_SUBSCRIPTIONS_WITH_OPTIONS:
1084             case CMD_RETAIN_SUBSCRIPTIONS:
1085             case CMD_GET_OTA_STATUS:
1086             case CMD_START_OTA_IF_NECESSARY:
1087             case CMD_DUMP_EUICC_SERVICE:
1088             case CMD_GET_AVAILABLE_MEMORY_IN_BYTES:
1089                 return (BaseEuiccCommandCallback) message.obj;
1090             case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA:
1091                 return ((GetMetadataRequest) message.obj).mCallback;
1092             case CMD_DOWNLOAD_SUBSCRIPTION:
1093                 return ((DownloadRequest) message.obj).mCallback;
1094             case CMD_GET_DEFAULT_DOWNLOADABLE_SUBSCRIPTION_LIST:
1095                 return ((GetDefaultListRequest) message.obj).mCallback;
1096             case CMD_DELETE_SUBSCRIPTION:
1097                 return ((DeleteRequest) message.obj).mCallback;
1098             case CMD_SWITCH_TO_SUBSCRIPTION:
1099                 return ((SwitchRequest) message.obj).mCallback;
1100             case CMD_UPDATE_SUBSCRIPTION_NICKNAME:
1101                 return ((UpdateNicknameRequest) message.obj).mCallback;
1102             default:
1103                 throw new IllegalArgumentException("Unsupported message: " + message.what);
1104         }
1105     }
1106 
1107     /**
1108      * Gets the slot ID from the card ID.
1109      */
getSlotIdFromCardId(int cardId)1110     private int getSlotIdFromCardId(int cardId) {
1111         if (cardId == TelephonyManager.UNSUPPORTED_CARD_ID
1112                 || cardId == TelephonyManager.UNINITIALIZED_CARD_ID) {
1113             return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
1114         }
1115         TelephonyManager tm = (TelephonyManager)
1116                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1117         UiccSlotInfo[] slotInfos = tm.getUiccSlotsInfo();
1118         if (slotInfos == null || slotInfos.length == 0) {
1119             Log.e(TAG, "UiccSlotInfo is null or empty");
1120             return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
1121         }
1122         String cardIdString = UiccController.getInstance().convertToCardString(cardId);
1123         for (int slotIndex = 0; slotIndex < slotInfos.length; slotIndex++) {
1124             // Report Anomaly in case UiccSlotInfo is not.
1125             if (slotInfos[slotIndex] == null) {
1126                 Log.i(TAG, "No UiccSlotInfo found for slotIndex: " + slotIndex);
1127                 return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
1128             }
1129             String retrievedCardId = slotInfos[slotIndex] != null
1130                     ? slotInfos[slotIndex].getCardId() : null;
1131             if (IccUtils.compareIgnoreTrailingFs(cardIdString, retrievedCardId)) {
1132                 return slotIndex;
1133             }
1134         }
1135         Log.i(TAG, "No UiccSlotInfo found for cardId: " + cardId);
1136         return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
1137     }
1138 
1139     /** Call this at the beginning of the execution of any command. */
onCommandStart(BaseEuiccCommandCallback callback)1140     private void onCommandStart(BaseEuiccCommandCallback callback) {
1141         mActiveCommandCallbacks.add(callback);
1142         removeMessages(CMD_LINGER_TIMEOUT);
1143     }
1144 
1145     /** Call this at the end of execution of any command (whether or not it succeeded). */
onCommandEnd(BaseEuiccCommandCallback callback)1146     private void onCommandEnd(BaseEuiccCommandCallback callback) {
1147         if (!mActiveCommandCallbacks.remove(callback)) {
1148             Log.wtf(TAG, "Callback already removed from mActiveCommandCallbacks");
1149         }
1150         if (mActiveCommandCallbacks.isEmpty()) {
1151             sendMessageDelayed(CMD_LINGER_TIMEOUT, LINGER_TIMEOUT_MILLIS);
1152         }
1153     }
1154 
1155     /** Return the service info of the EuiccService to bind to, or null if none were found. */
1156     @Nullable
findBestComponent()1157     private ServiceInfo findBestComponent() {
1158         return (ServiceInfo) findBestComponent(mPm);
1159     }
1160 
1161     /**
1162      * Bring up a binding to the currently-selected component.
1163      *
1164      * <p>Returns true if we've successfully bound to the service.
1165      */
createBinding()1166     private boolean createBinding() {
1167         if (mSelectedComponent == null) {
1168             Log.wtf(TAG, "Attempting to create binding but no component is selected");
1169             return false;
1170         }
1171         Intent intent = new Intent(EuiccService.EUICC_SERVICE_INTERFACE);
1172         intent.setComponent(new ComponentName(mSelectedComponent.packageName,
1173             mSelectedComponent.name));
1174         // We bind this as a foreground service because it is operating directly on the SIM, and we
1175         // do not want it subjected to power-savings restrictions while doing so.
1176         return mContext.bindService(intent, this,
1177                 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE);
1178     }
1179 
unbind()1180     private void unbind() {
1181         mEuiccService = null;
1182         mContext.unbindService(this);
1183     }
1184 
findBestComponent( PackageManager packageManager, List<ResolveInfo> resolveInfoList)1185     private static ComponentInfo findBestComponent(
1186             PackageManager packageManager, List<ResolveInfo> resolveInfoList) {
1187         int bestPriority = Integer.MIN_VALUE;
1188         ComponentInfo bestComponent = null;
1189         if (resolveInfoList != null) {
1190             for (ResolveInfo resolveInfo : resolveInfoList) {
1191                 if (!isValidEuiccComponent(packageManager, resolveInfo)) {
1192                     continue;
1193                 }
1194 
1195                 if (resolveInfo.filter.getPriority() > bestPriority) {
1196                     bestPriority = resolveInfo.filter.getPriority();
1197                     bestComponent = TelephonyUtils.getComponentInfo(resolveInfo);
1198                 }
1199             }
1200         }
1201 
1202         return bestComponent;
1203     }
1204 
isValidEuiccComponent( PackageManager packageManager, ResolveInfo resolveInfo)1205     private static boolean isValidEuiccComponent(
1206             PackageManager packageManager, ResolveInfo resolveInfo) {
1207         ComponentInfo componentInfo = TelephonyUtils.getComponentInfo(resolveInfo);
1208         String packageName = new ComponentName(componentInfo.packageName, componentInfo.name)
1209             .getPackageName();
1210 
1211         // Verify that the app is privileged (via granting of a privileged permission).
1212         if (packageManager.checkPermission(
1213                 Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, packageName)
1214                         != PackageManager.PERMISSION_GRANTED) {
1215             Log.wtf(TAG, "Package " + packageName
1216                     + " does not declare WRITE_EMBEDDED_SUBSCRIPTIONS");
1217             return false;
1218         }
1219 
1220         // Verify that only the system can access the component.
1221         final String permission;
1222         if (componentInfo instanceof ServiceInfo) {
1223             permission = ((ServiceInfo) componentInfo).permission;
1224         } else if (componentInfo instanceof ActivityInfo) {
1225             permission = ((ActivityInfo) componentInfo).permission;
1226         } else {
1227             throw new IllegalArgumentException("Can only verify services/activities");
1228         }
1229         if (!TextUtils.equals(permission, Manifest.permission.BIND_EUICC_SERVICE)) {
1230             Log.wtf(TAG, "Package " + packageName
1231                     + " does not require the BIND_EUICC_SERVICE permission");
1232             return false;
1233         }
1234 
1235         // Verify that the component declares a priority.
1236         if (resolveInfo.filter == null || resolveInfo.filter.getPriority() == 0) {
1237             Log.wtf(TAG, "Package " + packageName + " does not specify a priority");
1238             return false;
1239         }
1240         return true;
1241     }
1242 
1243     @Override
onServiceConnected(ComponentName name, IBinder service)1244     public void onServiceConnected(ComponentName name, IBinder service) {
1245         IEuiccService euiccService = IEuiccService.Stub.asInterface(service);
1246         sendMessage(CMD_SERVICE_CONNECTED, euiccService);
1247     }
1248 
1249     @Override
onServiceDisconnected(ComponentName name)1250     public void onServiceDisconnected(ComponentName name) {
1251         sendMessage(CMD_SERVICE_DISCONNECTED);
1252     }
1253 
1254     private class EuiccPackageMonitor extends PackageChangeReceiver {
1255         @Override
onPackageAdded(String packageName)1256         public void onPackageAdded(String packageName) {
1257             sendPackageChange(packageName, true /* forceUnbindForThisPackage */);
1258         }
1259 
1260         @Override
onPackageRemoved(String packageName)1261         public void onPackageRemoved(String packageName) {
1262             sendPackageChange(packageName, true /* forceUnbindForThisPackage */);
1263         }
1264 
1265         @Override
onPackageUpdateFinished(String packageName)1266         public void onPackageUpdateFinished(String packageName) {
1267             sendPackageChange(packageName, true /* forceUnbindForThisPackage */);
1268         }
1269 
1270         @Override
onPackageModified(String packageName)1271         public void onPackageModified(String packageName) {
1272             sendPackageChange(packageName, false /* forceUnbindForThisPackage */);
1273         }
1274 
1275         @Override
onHandleForceStop(String[] packages, boolean doit)1276         public void onHandleForceStop(String[] packages, boolean doit) {
1277             if (doit) {
1278                 for (String packageName : packages) {
1279                     sendPackageChange(packageName, true /* forceUnbindForThisPackage */);
1280                 }
1281             }
1282         }
1283 
sendPackageChange(String packageName, boolean forceUnbindForThisPackage)1284         private void sendPackageChange(String packageName, boolean forceUnbindForThisPackage) {
1285             sendMessage(CMD_PACKAGE_CHANGE, forceUnbindForThisPackage ? packageName : null);
1286         }
1287     }
1288 
1289     @Override
unhandledMessage(Message msg)1290     protected void unhandledMessage(Message msg) {
1291         IState state = getCurrentState();
1292         Log.wtf(TAG, "Unhandled message " + msg.what + " in state "
1293                 + (state == null ? "null" : state.getName()));
1294         AnomalyReporter.reportAnomaly(
1295                 UUID.fromString("0db20514-5fa1-4e62-a7b7-2acf5f92c957"),
1296                 "EuiccConnector: Found unhandledMessage " + String.valueOf(msg.what));
1297     }
1298 
1299     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1300     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1301         super.dump(fd, pw, args);
1302         pw.println("mSelectedComponent=" + mSelectedComponent);
1303         pw.println("mEuiccService=" + mEuiccService);
1304         pw.println("mActiveCommandCount=" + mActiveCommandCallbacks.size());
1305     }
1306 
updateSubscriptionInfoListForAllAccessibleEuiccs()1307     private void updateSubscriptionInfoListForAllAccessibleEuiccs() {
1308         if (mTm.getCardIdForDefaultEuicc() == TelephonyManager.UNSUPPORTED_CARD_ID) {
1309             // Device does not support card ID
1310             mSm.requestEmbeddedSubscriptionInfoListRefresh();
1311         } else {
1312             for (UiccCardInfo cardInfo : mTm.getUiccCardsInfo()) {
1313                 if (cardInfo.isEuicc()) {
1314                     mSm.requestEmbeddedSubscriptionInfoListRefresh(cardInfo.getCardId());
1315                 }
1316             }
1317         }
1318     }
1319 }
1320