EuiccController.java revision 08d3d312d13c3194d8434aeb8c92ea220f4d0e2c
1277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson/* 2277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * Copyright (C) 2017 The Android Open Source Project 3277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * 4277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * Licensed under the Apache License, Version 2.0 (the "License"); 5277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * you may not use this file except in compliance with the License. 6277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * You may obtain a copy of the License at 7277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * 8277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * http://www.apache.org/licenses/LICENSE-2.0 9277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * 10277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * Unless required by applicable law or agreed to in writing, software 11277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * distributed under the License is distributed on an "AS IS" BASIS, 12277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * See the License for the specific language governing permissions and 14277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * limitations under the License. 15277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson */ 16277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonpackage com.android.internal.telephony.euicc; 17277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 18277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.Manifest; 19277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.annotation.Nullable; 2008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.app.AppOpsManager; 21277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.app.PendingIntent; 22277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.Context; 23277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.Intent; 2408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.content.pm.PackageInfo; 25277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.content.pm.PackageManager; 26277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.os.Binder; 27277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.os.ServiceManager; 28277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.service.euicc.DownloadResult; 29277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.service.euicc.GetDownloadableSubscriptionMetadataResult; 30277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.TelephonyManager; 3108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidsonimport android.telephony.UiccAccessRule; 32277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.euicc.DownloadableSubscription; 33277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.telephony.euicc.EuiccManager; 34277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport android.util.Log; 35277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 36277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport com.android.internal.annotations.VisibleForTesting; 37277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 38277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.io.FileDescriptor; 39277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.io.PrintWriter; 40277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.util.concurrent.CountDownLatch; 41277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonimport java.util.concurrent.atomic.AtomicReference; 42277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 43277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson/** Backing implementation of {@link android.telephony.euicc.EuiccManager}. */ 44277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidsonpublic class EuiccController extends IEuiccController.Stub { 45277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private static final String TAG = "EuiccController"; 46277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 4708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // Aliases so line lengths stay short. 4808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson private static final int OK = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK; 4908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson private static final int RESOLVABLE_ERROR = 5008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR; 5108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson private static final int GENERIC_ERROR = 5208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_GENERIC_ERROR; 5308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 54277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private static EuiccController sInstance; 55277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 56277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private final Context mContext; 57277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private final EuiccConnector mConnector; 5808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson private final AppOpsManager mAppOpsManager; 5908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson private final PackageManager mPackageManager; 60277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 61277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson /** Initialize the instance. Should only be called once. */ 62277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public static EuiccController init(Context context) { 63277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson synchronized (EuiccController.class) { 64277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson if (sInstance == null) { 65277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson sInstance = new EuiccController(context); 66277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } else { 67277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson Log.wtf(TAG, "init() called multiple times! sInstance = " + sInstance); 68277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 69277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 70277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson return sInstance; 71277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 72277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 73277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson /** Get an instance. Assumes one has already been initialized with {@link #init}. */ 74277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public static EuiccController get() { 75277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson if (sInstance == null) { 76277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson synchronized (EuiccController.class) { 77277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson if (sInstance == null) { 78277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson throw new IllegalStateException("get() called before init()"); 79277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 80277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 81277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 82277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson return sInstance; 83277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 84277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 85277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private EuiccController(Context context) { 86277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson this(context, new EuiccConnector(context)); 87277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson ServiceManager.addService("econtroller", this); 88277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 89277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 90277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson @VisibleForTesting 91277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public EuiccController(Context context, EuiccConnector connector) { 92277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson mContext = context; 93277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson mConnector = connector; 9408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 9508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mPackageManager = context.getPackageManager(); 96277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 97277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 98277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson /** 99277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * Return the EID. 100277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * 101277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load, 102277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * that IPC should generally be fast, and the EID shouldn't be needed in the normal course of 103277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * operation. 104277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson */ 105277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson @Override 106277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public String getEid() { 107277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson if (!callerCanReadPhoneStatePrivileged() 108277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson && !callerHasCarrierPrivilegesForActiveSubscription()) { 109277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson throw new SecurityException( 110277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson "Must have carrier privileges on active subscription to read EID"); 111277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 112277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson long token = Binder.clearCallingIdentity(); 113277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson try { 114277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson return blockingGetEidFromEuiccService(); 115277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } finally { 116277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson Binder.restoreCallingIdentity(token); 117277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 118277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 119277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 120277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson @Override 121277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription, 12208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson PendingIntent callbackIntent) { 123277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson if (!callerCanWriteEmbeddedSubscriptions()) { 124277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata"); 125277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 126277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson long token = Binder.clearCallingIdentity(); 127277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson try { 12808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mConnector.getDownloadableSubscriptionMetadata( 12908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson subscription, new GetMetadataCommandCallback(callbackIntent)); 130277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } finally { 131277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson Binder.restoreCallingIdentity(token); 132277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 133277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 134277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 13508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson class GetMetadataCommandCallback implements EuiccConnector.GetMetadataCommandCallback { 13608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson protected final PendingIntent mCallbackIntent; 13708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 13808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson GetMetadataCommandCallback(PendingIntent callbackIntent) { 13908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mCallbackIntent = callbackIntent; 14008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 14108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 14208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson @Override 14308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson public void onGetMetadataComplete( 14408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson GetDownloadableSubscriptionMetadataResult result) { 14508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson Intent extrasIntent = new Intent(); 14608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson final int resultCode; 14708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson switch (result.result) { 14808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson case GetDownloadableSubscriptionMetadataResult.RESULT_OK: 14908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson resultCode = OK; 15008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson extrasIntent.putExtra( 15108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION, 15208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson result.subscription); 15308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson break; 15408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson case GetDownloadableSubscriptionMetadataResult.RESULT_MUST_DEACTIVATE_REMOVABLE_SIM: 15508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson resultCode = RESOLVABLE_ERROR; 15608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // TODO(b/33075886): Pass through the PendingIntent for the 15708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // resolution action. 15808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson break; 15908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson case GetDownloadableSubscriptionMetadataResult.RESULT_GENERIC_ERROR: 16008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson resultCode = GENERIC_ERROR; 16108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson extrasIntent.putExtra( 16208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 16308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson result.detailedCode); 16408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson break; 16508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson default: 16608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson Log.wtf(TAG, "Unknown result: " + result.result); 16708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson resultCode = GENERIC_ERROR; 16808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson break; 16908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 17008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 17108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson sendResult(mCallbackIntent, resultCode, extrasIntent); 17208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 17308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 17408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson @Override 17508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson public void onEuiccServiceUnavailable() { 17608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson sendResult(mCallbackIntent, GENERIC_ERROR, null /* extrasIntent */); 17708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 17808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 17908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 180277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson @Override 181277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public void downloadSubscription(DownloadableSubscription subscription, 18208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson boolean switchAfterDownload, String callingPackage, PendingIntent callbackIntent) { 18308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); 18408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); 18508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 186277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson long token = Binder.clearCallingIdentity(); 187277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson try { 18808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson if (callerCanWriteEmbeddedSubscriptions) { 18908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // With WRITE_EMBEDDED_SUBSCRIPTIONS, we can skip profile-specific permission checks 19008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // and move straight to the profile download. 19108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson downloadSubscriptionPrivileged(subscription, switchAfterDownload, callbackIntent); 19208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson return; 19308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 19408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // Without WRITE_EMBEDDED_SUBSCRIPTIONS, the caller *must* be whitelisted per the 19508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // metadata of the profile to be downloaded, so check the metadata first. 19608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mConnector.getDownloadableSubscriptionMetadata(subscription, 19708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson new DownloadSubscriptionGetMetadataCommandCallback( 19808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson switchAfterDownload, callbackIntent, callingPackage)); 199277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } finally { 200277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson Binder.restoreCallingIdentity(token); 201277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 202277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 203277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 20408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson class DownloadSubscriptionGetMetadataCommandCallback extends GetMetadataCommandCallback { 20508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson private final boolean mSwitchAfterDownload; 20608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson private final String mCallingPackage; 20708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 20808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson DownloadSubscriptionGetMetadataCommandCallback( 20908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson boolean switchAfterDownload, PendingIntent callbackIntent, String callingPackage) { 21008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson super(callbackIntent); 21108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mSwitchAfterDownload = switchAfterDownload; 21208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mCallingPackage = callingPackage; 21308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 21408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 21508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson @Override 21608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson public void onGetMetadataComplete( 21708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson GetDownloadableSubscriptionMetadataResult result) { 21808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson if (result.result != GetDownloadableSubscriptionMetadataResult.RESULT_OK) { 21908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // Just propagate the error as normal. 22008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // TODO(b/33075886): Pass through the PendingIntent for the resolution action. We 22108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // want to retry the parent download operation after resolution, not the get 22208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // metadata call. 22308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson super.onGetMetadataComplete(result); 22408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson return; 22508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 22608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 22708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson DownloadableSubscription subscription = result.subscription; 22808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson UiccAccessRule[] rules = subscription.getAccessRules(); 22908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson if (rules == null) { 23008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson Log.e(TAG, "No access rules but caller is unprivileged"); 23108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson sendResult(mCallbackIntent, GENERIC_ERROR, null /* extrasIntent */); 23208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson return; 23308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 23408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 23508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson final PackageInfo info; 23608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson try { 23708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson info = mPackageManager.getPackageInfo( 23808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mCallingPackage, PackageManager.GET_SIGNATURES); 23908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } catch (PackageManager.NameNotFoundException e) { 24008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson Log.e(TAG, "Calling package valid but gone"); 24108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson sendResult(mCallbackIntent, GENERIC_ERROR, null /* extrasIntent */); 24208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson return; 24308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 24408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 24508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson for (int i = 0; i < rules.length; i++) { 24608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson if (rules[i].getCarrierPrivilegeStatus(info) 24708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 24808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // TODO(b/33075886): For consistency, this should check the privilege rules in 24908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // the metadata, not the profile itself. 25008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson TelephonyManager tm = 25108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 25208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson if (tm.checkCarrierPrivilegesForPackage(mCallingPackage) 25308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { 25408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // Permission verified - move on to the download. 25508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson downloadSubscriptionPrivileged( 25608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson subscription, mSwitchAfterDownload, mCallbackIntent); 25708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } else { 25808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // Switch might still be permitted, but the user must consent first. 25908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // TODO(b/33075886): Pass through the PendingIntent for the resolution 26008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // action. 26108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson sendResult(mCallbackIntent, RESOLVABLE_ERROR, null /* extrasIntent */); 26208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 26308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson return; 26408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 26508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 26608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson Log.e(TAG, "Caller is not permitted to download this profile"); 26708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson sendResult(mCallbackIntent, GENERIC_ERROR, null /* extrasIntent */); 26808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 26908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 27008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 27108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson private void downloadSubscriptionPrivileged(DownloadableSubscription subscription, 27208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson boolean switchAfterDownload, final PendingIntent callbackIntent) { 27308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson mConnector.downloadSubscription(subscription, switchAfterDownload, 27408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson new EuiccConnector.DownloadCommandCallback() { 27508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson @Override 27608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson public void onDownloadComplete(DownloadResult result) { 27708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson Intent extrasIntent = new Intent(); 27808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson final int resultCode; 27908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson switch (result.result) { 28008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson case DownloadResult.RESULT_OK: 28108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson resultCode = OK; 28208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson break; 28308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson case DownloadResult.RESULT_MUST_DEACTIVATE_REMOVABLE_SIM: 28408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson resultCode = RESOLVABLE_ERROR; 28508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // TODO(b/33075886): Pass through the PendingIntent for the 28608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson // resolution action. 28708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson break; 28808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson case DownloadResult.RESULT_GENERIC_ERROR: 28908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson resultCode = GENERIC_ERROR; 29008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson extrasIntent.putExtra( 29108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 29208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson result.detailedCode); 29308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson break; 29408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson default: 29508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson Log.wtf(TAG, "Unknown result: " + result.result); 29608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson resultCode = GENERIC_ERROR; 29708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson break; 29808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 29908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 30008d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson sendResult(callbackIntent, resultCode, extrasIntent); 30108d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 30208d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 30308d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson @Override 30408d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson public void onEuiccServiceUnavailable() { 30508d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson sendResult(callbackIntent, GENERIC_ERROR, null /* extrasIntent */); 30608d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 30708d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson }); 30808d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson } 30908d3d312d13c3194d8434aeb8c92ea220f4d0e2cJeff Davidson 310277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private void sendResult(PendingIntent callbackIntent, int resultCode, Intent extrasIntent) { 311277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson try { 312277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson callbackIntent.send(mContext, resultCode, extrasIntent); 313277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } catch (PendingIntent.CanceledException e) { 314277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson // Caller canceled the callback; do nothing. 315277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 316277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 317277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 318277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson @Override 319277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 320277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP"); 321277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson final long token = Binder.clearCallingIdentity(); 322277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson try { 323277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson mConnector.dump(fd, pw, args); 324277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } finally { 325277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson Binder.restoreCallingIdentity(token); 326277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 327277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 328277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 329277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson @Nullable 330277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private String blockingGetEidFromEuiccService() { 331277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson final CountDownLatch latch = new CountDownLatch(1); 332277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson final AtomicReference<String> eidRef = new AtomicReference<>(); 333277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson mConnector.getEid(new EuiccConnector.GetEidCommandCallback() { 334277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson @Override 335277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public void onGetEidComplete(String eid) { 336277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson eidRef.set(eid); 337277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson latch.countDown(); 338277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 339277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 340277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson @Override 341277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson public void onEuiccServiceUnavailable() { 342277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson latch.countDown(); 343277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 344277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson }); 345277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson try { 346277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson latch.await(); 347277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } catch (InterruptedException e) { 348277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson Thread.currentThread().interrupt(); 349277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 350277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson return eidRef.get(); 351277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 352277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 353277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private boolean callerCanReadPhoneStatePrivileged() { 354277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson return mContext.checkCallingPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) 355277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson == PackageManager.PERMISSION_GRANTED; 356277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 357277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 358277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private boolean callerCanWriteEmbeddedSubscriptions() { 359277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson return mContext.checkCallingPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) 360277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson == PackageManager.PERMISSION_GRANTED; 361277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 362277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson 363277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson /** 364277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson * Returns whether the caller has carrier privileges for the active mSubscription on this eUICC. 365277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson */ 366277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson private boolean callerHasCarrierPrivilegesForActiveSubscription() { 367277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson // TODO(b/36260308): We should plumb a slot ID through here for multi-SIM devices. 368277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson TelephonyManager tm = 369277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 370277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson return tm.hasCarrierPrivileges(); 371277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson } 372277a5a2aae73ef0233fffc350f3829aee779899fJeff Davidson} 373