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