EuiccController.java revision 80fc6417014d6a884b009557fd7d19861a1087ab
1c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh/* 2c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * Copyright (C) 2017 The Android Open Source Project 3c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * 4c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 5c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * you may not use this file except in compliance with the License. 6c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * You may obtain a copy of the License at 7c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * 8c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * http://www.apache.org/licenses/LICENSE-2.0 9c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * 10c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * Unless required by applicable law or agreed to in writing, software 11c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * distributed under the License is distributed on an "AS IS" BASIS, 12c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * See the License for the specific language governing permissions and 14c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * limitations under the License. 15c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh */ 16c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehpackage com.android.internal.telephony.euicc; 17c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 18c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.Manifest; 19c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.annotation.Nullable; 20c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.app.AppOpsManager; 21c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.app.PendingIntent; 227e8d4ba5887affda749978d787b898bf31fda729Colin Crossimport android.content.Context; 23c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.content.Intent; 24c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.content.pm.PackageInfo; 25c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.content.pm.PackageManager; 26c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.os.Binder; 27c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.os.Bundle; 282f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Caiimport android.os.ServiceManager; 292f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Caiimport android.provider.Settings; 30c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.service.euicc.EuiccService; 31c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.service.euicc.GetDefaultDownloadableSubscriptionListResult; 32c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.service.euicc.GetDownloadableSubscriptionMetadataResult; 33c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.service.euicc.GetEuiccProfileInfoListResult; 34c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.telephony.SubscriptionInfo; 35c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.telephony.SubscriptionManager; 36c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.telephony.TelephonyManager; 37c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.telephony.UiccAccessRule; 38c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.telephony.euicc.DownloadableSubscription; 39c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.telephony.euicc.EuiccInfo; 40c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.telephony.euicc.EuiccManager; 41c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport android.util.Log; 42c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 43c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport com.android.internal.annotations.VisibleForTesting; 44c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport com.android.internal.telephony.SubscriptionController; 45c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 46c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport java.io.FileDescriptor; 47c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport java.io.PrintWriter; 48c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport java.util.List; 49c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport java.util.concurrent.CountDownLatch; 50c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehimport java.util.concurrent.atomic.AtomicReference; 51c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 5255ec25693db12f8f342378aac1f6a55ec4dd4957Jiwen 'Steve' Cai/** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */ 53c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yehpublic class EuiccController extends IEuiccController.Stub { 54c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh private static final String TAG = "EuiccController"; 552f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai 562f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai /** Extra set on resolution intents containing the {@link EuiccOperation}. */ 572f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai @VisibleForTesting 58e31bc87213619054f18fcc8462641767e82a7eafJiwen 'Steve' Cai static final String EXTRA_OPERATION = "operation"; 592f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai 60c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh // Aliases so line lengths stay short. 61c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh private static final int OK = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK; 62c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh private static final int RESOLVABLE_ERROR = 63c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR; 64c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh private static final int ERROR = 65c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR; 66c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 67e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai private static EuiccController sInstance; 68c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 69e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai private final Context mContext; 70e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai private final EuiccConnector mConnector; 71c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh private final SubscriptionManager mSubscriptionManager; 72c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh private final AppOpsManager mAppOpsManager; 73c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh private final PackageManager mPackageManager; 74c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 75c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh /** Initialize the instance. Should only be called once. */ 76c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh public static EuiccController init(Context context) { 77c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh synchronized (EuiccController.class) { 78c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh if (sInstance == null) { 79c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh sInstance = new EuiccController(context); 80c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } else { 81c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance); 822f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai } 832f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai } 842f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai return sInstance; 852f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai } 86e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai 87c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh /** Get an instance. Assumes one has already been initialized with {@link #init}. */ 88b29fce7b7e2220e6d0feb3597a35216c89c9f412Yin-Chia Yeh public static EuiccController get() { 89e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai if (sInstance == null) { 90c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh synchronized (EuiccController.class) { 912f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai if (sInstance == null) { 922f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai throw new IllegalStateException("get() called before init()"); 93c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 94c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 95e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai } 96c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh return sInstance; 97c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 98c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 99e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai private EuiccController(Context context) { 100e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai this(context, new EuiccConnector(context)); 101c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh ServiceManager.addService("econtroller", this); 102c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 103c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 104e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai @VisibleForTesting 105c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh public EuiccController(Context context, EuiccConnector connector) { 106c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh mContext = context; 107c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh mConnector = connector; 108c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh mSubscriptionManager = (SubscriptionManager) 109c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 110c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 111c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh mPackageManager = context.getPackageManager(); 112c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 113c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 1142f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai /** 115c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * Continue an operation which failed with a user-resolvable error. 116c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * 117c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * <p>The implementation here makes a key assumption that the resolutionIntent has not been 118c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * tampered with. This is guaranteed because: 119e31bc87213619054f18fcc8462641767e82a7eafJiwen 'Steve' Cai * <UL> 120c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * <LI>The intent is wrapped in a PendingIntent created by the phone process which is created 1212f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai * with {@link #EXTRA_OPERATION} already present. This means that the operation cannot be 1222f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai * overridden on the PendingIntent - a caller can only add new extras. 123c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * <LI>The resolution activity is restricted by a privileged permission; unprivileged apps 124c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * cannot start it directly. So the PendingIntent is the only way to start it. 125c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh * </UL> 126c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh */ 127724e04107548bfdb67f4be5772c0f08a0bd65f3eChih-Hung Hsieh @Override 128c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) { 129c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh if (!callerCanWriteEmbeddedSubscriptions()) { 130c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh throw new SecurityException( 131c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to continue operation"); 132c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 133c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh long token = Binder.clearCallingIdentity(); 134c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh try { 135c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh EuiccOperation op = resolutionIntent.getParcelableExtra(EXTRA_OPERATION); 136c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh if (op == null) { 137c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh throw new IllegalArgumentException("Invalid resolution intent"); 138c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 139c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh 140e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai PendingIntent callbackIntent = 141e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai resolutionIntent.getParcelableExtra( 142e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT); 143e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai op.continueOperation(resolutionExtras, callbackIntent); 144e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai } finally { 145e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai Binder.restoreCallingIdentity(token); 146e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai } 147e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai } 148e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai 149e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai /** 150e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai * Return the EID. 151e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai * 152e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load, 153e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai * that IPC should generally be fast, and the EID shouldn't be needed in the normal course of 154e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai * operation. 155c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh */ 156c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh @Override 157e168996c51cbbc78790c2b3282c9455a5c7b667cJiwen 'Steve' Cai public String getEid() { 158c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh if (!callerCanReadPhoneStatePrivileged() 159c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh && !callerHasCarrierPrivilegesForActiveSubscription()) { 160c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh throw new SecurityException( 1612f1a4737c997d9589447a51974e3aaecafee2937Jiwen 'Steve' Cai "Must have carrier privileges on active subscription to read EID"); 162c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 163c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh long token = Binder.clearCallingIdentity(); 164c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh try { 165c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh return blockingGetEidFromEuiccService(); 166c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } finally { 167c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh Binder.restoreCallingIdentity(token); 168c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 169c360382bf257d815b2a411152485d3c3b37a9f46Yin-Chia Yeh } 170 171 @Override 172 public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, 173 String callingPackage, PendingIntent callbackIntent) { 174 getDownloadableSubscriptionMetadata( 175 subscription, false /* forceDeactivateSim */, callingPackage, callbackIntent); 176 } 177 178 void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, 179 boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) { 180 if (!callerCanWriteEmbeddedSubscriptions()) { 181 throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata"); 182 } 183 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 184 long token = Binder.clearCallingIdentity(); 185 try { 186 mConnector.getDownloadableSubscriptionMetadata( 187 subscription, forceDeactivateSim, 188 new GetMetadataCommandCallback( 189 token, subscription, callingPackage, callbackIntent)); 190 } finally { 191 Binder.restoreCallingIdentity(token); 192 } 193 } 194 195 class GetMetadataCommandCallback implements EuiccConnector.GetMetadataCommandCallback { 196 protected final long mCallingToken; 197 protected final DownloadableSubscription mSubscription; 198 protected final String mCallingPackage; 199 protected final PendingIntent mCallbackIntent; 200 201 GetMetadataCommandCallback( 202 long callingToken, 203 DownloadableSubscription subscription, 204 String callingPackage, 205 PendingIntent callbackIntent) { 206 mCallingToken = callingToken; 207 mSubscription = subscription; 208 mCallingPackage = callingPackage; 209 mCallbackIntent = callbackIntent; 210 } 211 212 @Override 213 public void onGetMetadataComplete( 214 GetDownloadableSubscriptionMetadataResult result) { 215 Intent extrasIntent = new Intent(); 216 final int resultCode; 217 switch (result.result) { 218 case EuiccService.RESULT_OK: 219 resultCode = OK; 220 extrasIntent.putExtra( 221 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION, 222 result.subscription); 223 break; 224 case EuiccService.RESULT_MUST_DEACTIVATE_SIM: 225 resultCode = RESOLVABLE_ERROR; 226 addResolutionIntent(extrasIntent, 227 EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, 228 mCallingPackage, 229 getOperationForDeactivateSim()); 230 break; 231 default: 232 resultCode = ERROR; 233 extrasIntent.putExtra( 234 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 235 result.result); 236 break; 237 } 238 239 sendResult(mCallbackIntent, resultCode, extrasIntent); 240 } 241 242 @Override 243 public void onEuiccServiceUnavailable() { 244 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 245 } 246 247 protected EuiccOperation getOperationForDeactivateSim() { 248 return EuiccOperation.forGetMetadataDeactivateSim( 249 mCallingToken, mSubscription, mCallingPackage); 250 } 251 } 252 253 @Override 254 public void downloadSubscription(DownloadableSubscription subscription, 255 boolean switchAfterDownload, String callingPackage, PendingIntent callbackIntent) { 256 downloadSubscription(subscription, switchAfterDownload, callingPackage, 257 false /* forceDeactivateSim */, callbackIntent); 258 } 259 260 void downloadSubscription(DownloadableSubscription subscription, 261 boolean switchAfterDownload, String callingPackage, boolean forceDeactivateSim, 262 PendingIntent callbackIntent) { 263 boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); 264 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 265 266 long token = Binder.clearCallingIdentity(); 267 try { 268 if (callerCanWriteEmbeddedSubscriptions) { 269 // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks 270 // and move straight to the profile download. 271 downloadSubscriptionPrivileged(token, subscription, switchAfterDownload, 272 forceDeactivateSim, callingPackage, callbackIntent); 273 return; 274 } 275 // Without WRITE_EMBEDDED_SUBSCRIPTIONS, the caller *must* be whitelisted per the 276 // metadata of the profile to be downloaded, so check the metadata first. 277 mConnector.getDownloadableSubscriptionMetadata(subscription, 278 forceDeactivateSim, 279 new DownloadSubscriptionGetMetadataCommandCallback(token, subscription, 280 switchAfterDownload, callingPackage, forceDeactivateSim, 281 callbackIntent)); 282 } finally { 283 Binder.restoreCallingIdentity(token); 284 } 285 } 286 287 class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback { 288 private final boolean mSwitchAfterDownload; 289 private final boolean mForceDeactivateSim; 290 291 DownloadSubscriptionGetMetadataCommandCallback(long callingToken, 292 DownloadableSubscription subscription, boolean switchAfterDownload, 293 String callingPackage, boolean forceDeactivateSim, 294 PendingIntent callbackIntent) { 295 super(callingToken, subscription, callingPackage, callbackIntent); 296 mSwitchAfterDownload = switchAfterDownload; 297 mForceDeactivateSim = forceDeactivateSim; 298 } 299 300 @Override 301 public void onGetMetadataComplete( 302 GetDownloadableSubscriptionMetadataResult result) { 303 if (result.result == EuiccService.RESULT_MUST_DEACTIVATE_SIM) { 304 // If we need to deactivate the current SIM to even check permissions, go ahead and 305 // require that the user resolve the stronger permission dialog. 306 Intent extrasIntent = new Intent(); 307 addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, 308 mCallingPackage, 309 EuiccOperation.forDownloadNoPrivileges( 310 mCallingToken, mSubscription, mSwitchAfterDownload, 311 mCallingPackage)); 312 sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent); 313 return; 314 } 315 316 if (result.result != EuiccService.RESULT_OK) { 317 // Just propagate the error as normal. 318 super.onGetMetadataComplete(result); 319 return; 320 } 321 322 DownloadableSubscription subscription = result.subscription; 323 UiccAccessRule[] rules = subscription.getAccessRules(); 324 if (rules == null) { 325 Log.e(TAG, "No access rules but caller is unprivileged"); 326 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 327 return; 328 } 329 330 final PackageInfo info; 331 try { 332 info = mPackageManager.getPackageInfo( 333 mCallingPackage, PackageManager.GET_SIGNATURES); 334 } catch (PackageManager.NameNotFoundException e) { 335 Log.e(TAG, "Calling package valid but gone"); 336 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 337 return; 338 } 339 340 for (int i = 0; i < rules.length; i++) { 341 if (rules[i].getCarrierPrivilegeStatus(info) 342 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 343 // Caller can download this profile. Now, determine whether the caller can also 344 // manage the current profile; if so, we can perform the download silently; if 345 // not, the user must provide consent. 346 if (canManageActiveSubscription(mCallingPackage)) { 347 downloadSubscriptionPrivileged( 348 mCallingToken, subscription, mSwitchAfterDownload, 349 mForceDeactivateSim, mCallingPackage, mCallbackIntent); 350 return; 351 } 352 353 // Switch might still be permitted, but the user must consent first. 354 Intent extrasIntent = new Intent(); 355 addResolutionIntent(extrasIntent, EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, 356 mCallingPackage, 357 EuiccOperation.forDownloadNoPrivileges( 358 mCallingToken, subscription, mSwitchAfterDownload, 359 mCallingPackage)); 360 sendResult(mCallbackIntent, RESOLVABLE_ERROR, extrasIntent); 361 return; 362 } 363 } 364 Log.e(TAG, "Caller is not permitted to download this profile"); 365 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 366 } 367 368 @Override 369 protected EuiccOperation getOperationForDeactivateSim() { 370 return EuiccOperation.forDownloadDeactivateSim( 371 mCallingToken, mSubscription, mSwitchAfterDownload, mCallingPackage); 372 } 373 } 374 375 void downloadSubscriptionPrivileged(final long callingToken, 376 DownloadableSubscription subscription, boolean switchAfterDownload, 377 boolean forceDeactivateSim, final String callingPackage, 378 final PendingIntent callbackIntent) { 379 mConnector.downloadSubscription( 380 subscription, 381 switchAfterDownload, 382 forceDeactivateSim, 383 new EuiccConnector.DownloadCommandCallback() { 384 @Override 385 public void onDownloadComplete(int result) { 386 Intent extrasIntent = new Intent(); 387 final int resultCode; 388 switch (result) { 389 case EuiccService.RESULT_OK: 390 resultCode = OK; 391 // Now that a profile has been successfully downloaded, mark the 392 // eUICC as provisioned so it appears in settings UI as appropriate. 393 Settings.Global.putInt( 394 mContext.getContentResolver(), 395 Settings.Global.EUICC_PROVISIONED, 396 1); 397 if (!switchAfterDownload) { 398 // Since we're not switching, nothing will trigger a 399 // subscription list refresh on its own, so request one here. 400 refreshSubscriptionsAndSendResult( 401 callbackIntent, resultCode, extrasIntent); 402 return; 403 } 404 break; 405 case EuiccService.RESULT_MUST_DEACTIVATE_SIM: 406 resultCode = RESOLVABLE_ERROR; 407 addResolutionIntent(extrasIntent, 408 EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, 409 callingPackage, 410 EuiccOperation.forDownloadDeactivateSim( 411 callingToken, subscription, switchAfterDownload, 412 callingPackage)); 413 break; 414 case EuiccService.RESULT_NEED_CONFIRMATION_CODE: 415 resultCode = RESOLVABLE_ERROR; 416 addResolutionIntent(extrasIntent, 417 EuiccService.ACTION_RESOLVE_CONFIRMATION_CODE, 418 callingPackage, 419 EuiccOperation.forDownloadConfirmationCode( 420 callingToken, subscription, switchAfterDownload, 421 callingPackage)); 422 break; 423 default: 424 resultCode = ERROR; 425 extrasIntent.putExtra( 426 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 427 result); 428 break; 429 } 430 431 sendResult(callbackIntent, resultCode, extrasIntent); 432 } 433 434 @Override 435 public void onEuiccServiceUnavailable() { 436 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 437 } 438 }); 439 } 440 441 /** 442 * Blocking call to {@link EuiccService#onGetEuiccProfileInfoList}. 443 * 444 * <p>Does not perform permission checks as this is not an exposed API and is only used within 445 * the phone process. 446 */ 447 public GetEuiccProfileInfoListResult blockingGetEuiccProfileInfoList() { 448 final CountDownLatch latch = new CountDownLatch(1); 449 final AtomicReference<GetEuiccProfileInfoListResult> resultRef = new AtomicReference<>(); 450 mConnector.getEuiccProfileInfoList( 451 new EuiccConnector.GetEuiccProfileInfoListCommandCallback() { 452 @Override 453 public void onListComplete(GetEuiccProfileInfoListResult result) { 454 resultRef.set(result); 455 latch.countDown(); 456 } 457 458 @Override 459 public void onEuiccServiceUnavailable() { 460 latch.countDown(); 461 } 462 }); 463 try { 464 latch.await(); 465 } catch (InterruptedException e) { 466 Thread.currentThread().interrupt(); 467 } 468 return resultRef.get(); 469 } 470 471 @Override 472 public void getDefaultDownloadableSubscriptionList( 473 String callingPackage, PendingIntent callbackIntent) { 474 getDefaultDownloadableSubscriptionList( 475 false /* forceDeactivateSim */, callingPackage, callbackIntent); 476 } 477 478 void getDefaultDownloadableSubscriptionList( 479 boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) { 480 if (!callerCanWriteEmbeddedSubscriptions()) { 481 throw new SecurityException( 482 "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get default list"); 483 } 484 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 485 long token = Binder.clearCallingIdentity(); 486 try { 487 mConnector.getDefaultDownloadableSubscriptionList( 488 forceDeactivateSim, new GetDefaultListCommandCallback( 489 token, callingPackage, callbackIntent)); 490 } finally { 491 Binder.restoreCallingIdentity(token); 492 } 493 } 494 495 class GetDefaultListCommandCallback implements EuiccConnector.GetDefaultListCommandCallback { 496 final long mCallingToken; 497 final String mCallingPackage; 498 final PendingIntent mCallbackIntent; 499 500 GetDefaultListCommandCallback(long callingToken, String callingPackage, 501 PendingIntent callbackIntent) { 502 mCallingToken = callingToken; 503 mCallingPackage = callingPackage; 504 mCallbackIntent = callbackIntent; 505 } 506 507 @Override 508 public void onGetDefaultListComplete(GetDefaultDownloadableSubscriptionListResult result) { 509 Intent extrasIntent = new Intent(); 510 final int resultCode; 511 switch (result.result) { 512 case EuiccService.RESULT_OK: 513 resultCode = OK; 514 extrasIntent.putExtra( 515 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS, 516 result.subscriptions); 517 break; 518 case EuiccService.RESULT_MUST_DEACTIVATE_SIM: 519 resultCode = RESOLVABLE_ERROR; 520 addResolutionIntent(extrasIntent, 521 EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, 522 mCallingPackage, 523 EuiccOperation.forGetDefaultListDeactivateSim( 524 mCallingToken, mCallingPackage)); 525 break; 526 default: 527 resultCode = ERROR; 528 extrasIntent.putExtra( 529 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 530 result.result); 531 break; 532 } 533 534 sendResult(mCallbackIntent, resultCode, extrasIntent); 535 } 536 537 @Override 538 public void onEuiccServiceUnavailable() { 539 sendResult(mCallbackIntent, ERROR, null /* extrasIntent */); 540 } 541 } 542 543 /** 544 * Return the {@link EuiccInfo}. 545 * 546 * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load, 547 * that IPC should generally be fast, and this info shouldn't be needed in the normal course of 548 * operation. 549 */ 550 @Override 551 public EuiccInfo getEuiccInfo() { 552 // No permissions required as EuiccInfo is not sensitive. 553 long token = Binder.clearCallingIdentity(); 554 try { 555 return blockingGetEuiccInfoFromEuiccService(); 556 } finally { 557 Binder.restoreCallingIdentity(token); 558 } 559 } 560 561 @Override 562 public void deleteSubscription(int subscriptionId, String callingPackage, 563 PendingIntent callbackIntent) { 564 boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); 565 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 566 567 long token = Binder.clearCallingIdentity(); 568 try { 569 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); 570 if (sub == null) { 571 Log.e(TAG, "Cannot delete nonexistent subscription: " + subscriptionId); 572 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 573 return; 574 } 575 576 if (!callerCanWriteEmbeddedSubscriptions 577 && !sub.canManageSubscription(mContext, callingPackage)) { 578 Log.e(TAG, "No permissions: " + subscriptionId); 579 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 580 return; 581 } 582 583 deleteSubscriptionPrivileged(sub.getIccId(), callbackIntent); 584 } finally { 585 Binder.restoreCallingIdentity(token); 586 } 587 } 588 589 void deleteSubscriptionPrivileged(String iccid, final PendingIntent callbackIntent) { 590 mConnector.deleteSubscription( 591 iccid, 592 new EuiccConnector.DeleteCommandCallback() { 593 @Override 594 public void onDeleteComplete(int result) { 595 Intent extrasIntent = new Intent(); 596 final int resultCode; 597 switch (result) { 598 case EuiccService.RESULT_OK: 599 resultCode = OK; 600 refreshSubscriptionsAndSendResult( 601 callbackIntent, resultCode, extrasIntent); 602 return; 603 default: 604 resultCode = ERROR; 605 extrasIntent.putExtra( 606 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 607 result); 608 break; 609 } 610 611 sendResult(callbackIntent, resultCode, extrasIntent); 612 } 613 614 @Override 615 public void onEuiccServiceUnavailable() { 616 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 617 } 618 }); 619 } 620 621 @Override 622 public void switchToSubscription(int subscriptionId, String callingPackage, 623 PendingIntent callbackIntent) { 624 switchToSubscription( 625 subscriptionId, false /* forceDeactivateSim */, callingPackage, callbackIntent); 626 } 627 628 void switchToSubscription(int subscriptionId, boolean forceDeactivateSim, String callingPackage, 629 PendingIntent callbackIntent) { 630 boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); 631 mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 632 633 long token = Binder.clearCallingIdentity(); 634 try { 635 if (callerCanWriteEmbeddedSubscriptions) { 636 // Assume that if a privileged caller is calling us, we don't need to prompt the 637 // user about changing carriers, because the caller would only be acting in response 638 // to user action. 639 forceDeactivateSim = true; 640 } 641 642 final String iccid; 643 if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 644 // Switch to "no" subscription. Only the system can do this. 645 if (!callerCanWriteEmbeddedSubscriptions) { 646 Log.e(TAG, "Not permitted to switch to empty subscription"); 647 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 648 return; 649 } 650 iccid = null; 651 } else { 652 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); 653 if (sub == null) { 654 Log.e(TAG, "Cannot switch to nonexistent subscription: " + subscriptionId); 655 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 656 return; 657 } 658 if (!callerCanWriteEmbeddedSubscriptions 659 && !sub.canManageSubscription(mContext, callingPackage)) { 660 Log.e(TAG, "Not permitted to switch to subscription: " + subscriptionId); 661 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 662 return; 663 } 664 iccid = sub.getIccId(); 665 } 666 667 if (!callerCanWriteEmbeddedSubscriptions 668 && !canManageActiveSubscription(callingPackage)) { 669 // Switch needs consent. 670 Intent extrasIntent = new Intent(); 671 addResolutionIntent(extrasIntent, 672 EuiccService.ACTION_RESOLVE_NO_PRIVILEGES, 673 callingPackage, 674 EuiccOperation.forSwitchNoPrivileges( 675 token, subscriptionId, callingPackage)); 676 sendResult(callbackIntent, RESOLVABLE_ERROR, extrasIntent); 677 return; 678 } 679 680 switchToSubscriptionPrivileged(token, subscriptionId, iccid, forceDeactivateSim, 681 callingPackage, callbackIntent); 682 } finally { 683 Binder.restoreCallingIdentity(token); 684 } 685 } 686 687 void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId, 688 boolean forceDeactivateSim, final String callingPackage, 689 final PendingIntent callbackIntent) { 690 String iccid = null; 691 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); 692 if (sub != null) { 693 iccid = sub.getIccId(); 694 } 695 switchToSubscriptionPrivileged(callingToken, subscriptionId, iccid, forceDeactivateSim, 696 callingPackage, callbackIntent); 697 } 698 699 void switchToSubscriptionPrivileged(final long callingToken, int subscriptionId, 700 @Nullable String iccid, boolean forceDeactivateSim, final String callingPackage, 701 final PendingIntent callbackIntent) { 702 mConnector.switchToSubscription( 703 iccid, 704 forceDeactivateSim, 705 new EuiccConnector.SwitchCommandCallback() { 706 @Override 707 public void onSwitchComplete(int result) { 708 Intent extrasIntent = new Intent(); 709 final int resultCode; 710 switch (result) { 711 case EuiccService.RESULT_OK: 712 resultCode = OK; 713 break; 714 case EuiccService.RESULT_MUST_DEACTIVATE_SIM: 715 resultCode = RESOLVABLE_ERROR; 716 addResolutionIntent(extrasIntent, 717 EuiccService.ACTION_RESOLVE_DEACTIVATE_SIM, 718 callingPackage, 719 EuiccOperation.forSwitchDeactivateSim( 720 callingToken, subscriptionId, callingPackage)); 721 break; 722 default: 723 resultCode = ERROR; 724 extrasIntent.putExtra( 725 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 726 result); 727 break; 728 } 729 730 sendResult(callbackIntent, resultCode, extrasIntent); 731 } 732 733 @Override 734 public void onEuiccServiceUnavailable() { 735 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 736 } 737 }); 738 } 739 740 @Override 741 public void updateSubscriptionNickname(int subscriptionId, String nickname, 742 PendingIntent callbackIntent) { 743 if (!callerCanWriteEmbeddedSubscriptions()) { 744 throw new SecurityException( 745 "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to update nickname"); 746 } 747 long token = Binder.clearCallingIdentity(); 748 try { 749 SubscriptionInfo sub = getSubscriptionForSubscriptionId(subscriptionId); 750 if (sub == null) { 751 Log.e(TAG, "Cannot update nickname to nonexistent subscription: " + subscriptionId); 752 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 753 return; 754 } 755 mConnector.updateSubscriptionNickname( 756 sub.getIccId(), nickname, 757 new EuiccConnector.UpdateNicknameCommandCallback() { 758 @Override 759 public void onUpdateNicknameComplete(int result) { 760 Intent extrasIntent = new Intent(); 761 final int resultCode; 762 switch (result) { 763 case EuiccService.RESULT_OK: 764 resultCode = OK; 765 break; 766 default: 767 resultCode = ERROR; 768 extrasIntent.putExtra( 769 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 770 result); 771 break; 772 } 773 774 sendResult(callbackIntent, resultCode, extrasIntent); 775 } 776 777 @Override 778 public void onEuiccServiceUnavailable() { 779 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 780 } 781 }); 782 } finally { 783 Binder.restoreCallingIdentity(token); 784 } 785 } 786 787 @Override 788 public void eraseSubscriptions(PendingIntent callbackIntent) { 789 if (!callerCanWriteEmbeddedSubscriptions()) { 790 throw new SecurityException( 791 "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to erase subscriptions"); 792 } 793 long token = Binder.clearCallingIdentity(); 794 try { 795 mConnector.eraseSubscriptions(new EuiccConnector.EraseCommandCallback() { 796 @Override 797 public void onEraseComplete(int result) { 798 Intent extrasIntent = new Intent(); 799 final int resultCode; 800 switch (result) { 801 case EuiccService.RESULT_OK: 802 resultCode = OK; 803 refreshSubscriptionsAndSendResult( 804 callbackIntent, resultCode, extrasIntent); 805 return; 806 default: 807 resultCode = ERROR; 808 extrasIntent.putExtra( 809 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 810 result); 811 break; 812 } 813 814 sendResult(callbackIntent, resultCode, extrasIntent); 815 } 816 817 @Override 818 public void onEuiccServiceUnavailable() { 819 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 820 } 821 }); 822 } finally { 823 Binder.restoreCallingIdentity(token); 824 } 825 } 826 827 @Override 828 public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) { 829 mContext.enforceCallingPermission(Manifest.permission.MASTER_CLEAR, 830 "Must have MASTER_CLEAR to retain subscriptions for factory reset"); 831 long token = Binder.clearCallingIdentity(); 832 try { 833 mConnector.retainSubscriptions( 834 new EuiccConnector.RetainSubscriptionsCommandCallback() { 835 @Override 836 public void onRetainSubscriptionsComplete(int result) { 837 Intent extrasIntent = new Intent(); 838 final int resultCode; 839 switch (result) { 840 case EuiccService.RESULT_OK: 841 resultCode = OK; 842 break; 843 default: 844 resultCode = ERROR; 845 extrasIntent.putExtra( 846 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 847 result); 848 break; 849 } 850 851 sendResult(callbackIntent, resultCode, extrasIntent); 852 } 853 854 @Override 855 public void onEuiccServiceUnavailable() { 856 sendResult(callbackIntent, ERROR, null /* extrasIntent */); 857 } 858 }); 859 } finally { 860 Binder.restoreCallingIdentity(token); 861 } 862 } 863 864 /** Refresh the embedded subscription list and dispatch the given result upon completion. */ 865 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 866 public void refreshSubscriptionsAndSendResult( 867 PendingIntent callbackIntent, int resultCode, Intent extrasIntent) { 868 SubscriptionController.getInstance() 869 .requestEmbeddedSubscriptionInfoListRefresh( 870 () -> sendResult(callbackIntent, resultCode, extrasIntent)); 871 } 872 873 /** Dispatch the given callback intent with the given result code and data. */ 874 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 875 public void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) { 876 try { 877 callbackIntent.send(mContext, resultCode, extrasIntent); 878 } catch (PendingIntent.CanceledException e) { 879 // Caller canceled the callback; do nothing. 880 } 881 } 882 883 /** Add a resolution intent to the given extras intent. */ 884 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 885 public void addResolutionIntent(Intent extrasIntent, String resolutionAction, 886 String callingPackage, EuiccOperation op) { 887 Intent intent = new Intent(EuiccManager.ACTION_RESOLVE_ERROR); 888 intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_ACTION, 889 resolutionAction); 890 intent.putExtra(EuiccService.EXTRA_RESOLUTION_CALLING_PACKAGE, callingPackage); 891 intent.putExtra(EXTRA_OPERATION, op); 892 PendingIntent resolutionIntent = PendingIntent.getActivity( 893 mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_ONE_SHOT); 894 extrasIntent.putExtra( 895 EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, resolutionIntent); 896 } 897 898 @Override 899 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 900 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP"); 901 final long token = Binder.clearCallingIdentity(); 902 try { 903 mConnector.dump(fd, pw, args); 904 } finally { 905 Binder.restoreCallingIdentity(token); 906 } 907 } 908 909 @Nullable 910 private SubscriptionInfo getSubscriptionForSubscriptionId(int subscriptionId) { 911 List<SubscriptionInfo> subs = mSubscriptionManager.getAvailableSubscriptionInfoList(); 912 int subCount = subs.size(); 913 for (int i = 0; i < subCount; i++) { 914 SubscriptionInfo sub = subs.get(i); 915 if (subscriptionId == sub.getSubscriptionId()) { 916 return sub; 917 } 918 } 919 return null; 920 } 921 922 @Nullable 923 private String blockingGetEidFromEuiccService() { 924 CountDownLatch latch = new CountDownLatch(1); 925 AtomicReference<String> eidRef = new AtomicReference<>(); 926 mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { 927 @Override 928 public void onGetEidComplete(String eid) { 929 eidRef.set(eid); 930 latch.countDown(); 931 } 932 933 @Override 934 public void onEuiccServiceUnavailable() { 935 latch.countDown(); 936 } 937 }); 938 return awaitResult(latch, eidRef); 939 } 940 941 @Nullable 942 private EuiccInfo blockingGetEuiccInfoFromEuiccService() { 943 CountDownLatch latch = new CountDownLatch(1); 944 AtomicReference<EuiccInfo> euiccInfoRef = new AtomicReference<>(); 945 mConnector.getEuiccInfo(new EuiccConnector.GetEuiccInfoCommandCallback() { 946 @Override 947 public void onGetEuiccInfoComplete(EuiccInfo euiccInfo) { 948 euiccInfoRef.set(euiccInfo); 949 latch.countDown(); 950 } 951 952 @Override 953 public void onEuiccServiceUnavailable() { 954 latch.countDown(); 955 } 956 }); 957 return awaitResult(latch, euiccInfoRef); 958 } 959 960 private static <T> T awaitResult(CountDownLatch latch, AtomicReference<T> resultRef) { 961 try { 962 latch.await(); 963 } catch (InterruptedException e) { 964 Thread.currentThread().interrupt(); 965 } 966 return resultRef.get(); 967 } 968 969 private boolean canManageActiveSubscription(String callingPackage) { 970 // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices. 971 List<SubscriptionInfo> subInfoList = mSubscriptionManager.getActiveSubscriptionInfoList(); 972 if (subInfoList == null) { 973 return false; 974 } 975 int size = subInfoList.size(); 976 for (int subIndex = 0; subIndex < size; subIndex++) { 977 SubscriptionInfo subInfo = subInfoList.get(subIndex); 978 if (subInfo.isEmbedded() && subInfo.canManageSubscription(mContext, callingPackage)) { 979 return true; 980 } 981 } 982 return false; 983 } 984 985 private boolean callerCanReadPhoneStatePrivileged() { 986 return mContext.checkCallingPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) 987 == PackageManager.PERMISSION_GRANTED; 988 } 989 990 private boolean callerCanWriteEmbeddedSubscriptions() { 991 return mContext.checkCallingPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) 992 == PackageManager.PERMISSION_GRANTED; 993 } 994 995 /** 996 * Returns whether the caller has carrier privileges for the active mSubscription on this eUICC. 997 */ 998 private boolean callerHasCarrierPrivilegesForActiveSubscription() { 999 // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices. 1000 TelephonyManager tm = 1001 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 1002 return tm.hasCarrierPrivileges(); 1003 } 1004} 1005