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