Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1fd1a12 authored by Qingxi Li's avatar Qingxi Li Committed by Android (Google) Code Review
Browse files

Merge "Add API to get eUICC's OTA status"

parents c3eae59f ebbbe7bd
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -46,12 +46,14 @@ import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback;
import android.service.euicc.IGetEidCallback;
import android.service.euicc.IGetEuiccInfoCallback;
import android.service.euicc.IGetEuiccProfileInfoListCallback;
import android.service.euicc.IGetOtaStatusCallback;
import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback;
import android.service.euicc.ISwitchToSubscriptionCallback;
import android.service.euicc.IUpdateSubscriptionNicknameCallback;
import android.telephony.SubscriptionManager;
import android.telephony.euicc.DownloadableSubscription;
import android.telephony.euicc.EuiccInfo;
import android.telephony.euicc.EuiccManager.OtaStatus;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -132,6 +134,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection {
    private static final int CMD_UPDATE_SUBSCRIPTION_NICKNAME = 108;
    private static final int CMD_ERASE_SUBSCRIPTIONS = 109;
    private static final int CMD_RETAIN_SUBSCRIPTIONS = 110;
    private static final int CMD_GET_OTA_STATUS = 111;

    private static boolean isEuiccCommand(int what) {
        return what >= CMD_GET_EID;
@@ -185,6 +188,13 @@ public class EuiccConnector extends StateMachine implements ServiceConnection {
        void onGetEidComplete(String eid);
    }

    /** Callback class for {@link #getOtaStatus}. */
    @VisibleForTesting(visibility = PACKAGE)
    public interface GetOtaStatusCommandCallback extends BaseEuiccCommandCallback {
        /** Called when the getting OTA status lookup has completed. */
        void onGetOtaStatusComplete(@OtaStatus int status);
    }

    static class GetMetadataRequest {
        DownloadableSubscription mSubscription;
        boolean mForceDeactivateSim;
@@ -373,6 +383,12 @@ public class EuiccConnector extends StateMachine implements ServiceConnection {
        sendMessage(CMD_GET_EID, callback);
    }

    /** Asynchronously get OTA status. */
    @VisibleForTesting(visibility = PACKAGE)
    public void getOtaStatus(GetOtaStatusCommandCallback callback) {
        sendMessage(CMD_GET_OTA_STATUS, callback);
    }

    /** Asynchronously fetch metadata for the given downloadable subscription. */
    @VisibleForTesting(visibility = PACKAGE)
    public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
@@ -809,6 +825,20 @@ public class EuiccConnector extends StateMachine implements ServiceConnection {
                                    });
                            break;
                        }
                        case CMD_GET_OTA_STATUS: {
                            mEuiccService.getOtaStatus(slotId,
                                    new IGetOtaStatusCallback.Stub() {
                                        @Override
                                        public void onSuccess(@OtaStatus int status) {
                                            sendMessage(CMD_COMMAND_COMPLETE, (Runnable) () -> {
                                                ((GetOtaStatusCommandCallback) callback)
                                                        .onGetOtaStatusComplete(status);
                                                onCommandEnd(callback);
                                            });
                                        }
                                    });
                            break;
                        }
                        default: {
                            Log.wtf(TAG, "Unimplemented eUICC command: " + message.what);
                            callback.onEuiccServiceUnavailable();
@@ -851,6 +881,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection {
            case CMD_GET_EUICC_INFO:
            case CMD_ERASE_SUBSCRIPTIONS:
            case CMD_RETAIN_SUBSCRIPTIONS:
            case CMD_GET_OTA_STATUS:
                return (BaseEuiccCommandCallback) message.obj;
            case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA:
                return ((GetMetadataRequest) message.obj).mCallback;
+41 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
package com.android.internal.telephony.euicc;

import static android.telephony.euicc.EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE;

import android.Manifest;
import android.annotation.Nullable;
import android.app.AppOpsManager;
@@ -38,6 +40,7 @@ import android.telephony.UiccAccessRule;
import android.telephony.euicc.DownloadableSubscription;
import android.telephony.euicc.EuiccInfo;
import android.telephony.euicc.EuiccManager;
import android.telephony.euicc.EuiccManager.OtaStatus;
import android.text.TextUtils;
import android.util.Log;

@@ -169,6 +172,25 @@ public class EuiccController extends IEuiccController.Stub {
        }
    }

    /**
     * Return the current status of OTA update.
     *
     * <p>For API simplicity, this call blocks until completion; while it requires an IPC to load,
     * that IPC should generally be fast.
     */
    @Override
    public @OtaStatus int getOtaStatus() {
        if (!callerCanWriteEmbeddedSubscriptions()) {
            throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get OTA status");
        }
        long token = Binder.clearCallingIdentity();
        try {
            return blockingGetOtaStatusFromEuiccService();
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public void getDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
            String callingPackage, PendingIntent callbackIntent) {
@@ -953,6 +975,25 @@ public class EuiccController extends IEuiccController.Stub {
        return awaitResult(latch, eidRef);
    }

    private @OtaStatus int blockingGetOtaStatusFromEuiccService() {
        CountDownLatch latch = new CountDownLatch(1);
        AtomicReference<Integer> statusRef =
                new AtomicReference<>(EUICC_OTA_STATUS_UNAVAILABLE);
        mConnector.getOtaStatus(new EuiccConnector.GetOtaStatusCommandCallback() {
            @Override
            public void onGetOtaStatusComplete(@OtaStatus int status) {
                statusRef.set(status);
                latch.countDown();
            }

            @Override
            public void onEuiccServiceUnavailable() {
                latch.countDown();
            }
        });
        return awaitResult(latch, statusRef);
    }

    @Nullable
    private EuiccInfo blockingGetEuiccInfoFromEuiccService() {
        CountDownLatch latch = new CountDownLatch(1);
+39 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
package com.android.internal.telephony.euicc;

import static android.telephony.euicc.EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -56,6 +58,7 @@ import android.telephony.euicc.EuiccInfo;
import android.telephony.euicc.EuiccManager;

import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.euicc.EuiccConnector.GetOtaStatusCommandCallback;

import org.junit.After;
import org.junit.Before;
@@ -203,6 +206,26 @@ public class EuiccControllerTest extends TelephonyTest {
        assertNull(callGetEid(true /* success */, null /* eid */));
    }

    @Test(expected = SecurityException.class)
    public void testGetOtaStatus_noPrivileges() {
        setHasWriteEmbeddedPermission(false /* hasPermission */);
        callGetOtaStatus(true /* success */, 1 /* status */);
    }

    @Test
    public void testGetOtaStatus_withWriteEmbeddedPermission() {
        setHasWriteEmbeddedPermission(true /* hasPermission */);
        assertEquals(1, callGetOtaStatus(true /* success */, 1 /* status */));
    }

    @Test
    public void testGetOtaStatus_failure() {
        setHasWriteEmbeddedPermission(true /* hasPermission */);
        assertEquals(
                EUICC_OTA_STATUS_UNAVAILABLE,
                callGetOtaStatus(false /* success */, 1 /* status */));
    }

    @Test
    public void testGetEuiccInfo_success() {
        assertEquals(OS_VERSION, callGetEuiccInfo(true /* success */, EUICC_INFO).osVersion);
@@ -806,6 +829,22 @@ public class EuiccControllerTest extends TelephonyTest {
        return mController.getEid();
    }

    private int callGetOtaStatus(final boolean success, final int status) {
        doAnswer(new Answer<Void>() {
            @Override
            public Void answer(InvocationOnMock invocation) throws Exception {
                GetOtaStatusCommandCallback cb = invocation.getArgument(0);
                if (success) {
                    cb.onGetOtaStatusComplete(status);
                } else {
                    cb.onEuiccServiceUnavailable();
                }
                return null;
            }
        }).when(mMockConnector).getOtaStatus(Mockito.<GetOtaStatusCommandCallback>any());
        return mController.getOtaStatus();
    }

    private EuiccInfo callGetEuiccInfo(final boolean success, final @Nullable EuiccInfo euiccInfo) {
        doAnswer(new Answer<Void>() {
            @Override