diff --git a/Android.mk b/Android.mk index 933ac6200a3e7..55ea69a7b437f 100644 --- a/Android.mk +++ b/Android.mk @@ -292,6 +292,7 @@ LOCAL_SRC_FILES += \ core/java/android/service/euicc/IGetEidCallback.aidl \ core/java/android/service/euicc/IGetEuiccInfoCallback.aidl \ core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl \ + core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl \ core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl \ core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl \ core/java/android/service/gatekeeper/IGateKeeperService.aidl \ diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java index 26f85288699a0..0c2e4b7ada261 100644 --- a/core/java/android/service/euicc/EuiccService.java +++ b/core/java/android/service/euicc/EuiccService.java @@ -316,6 +316,21 @@ public abstract class EuiccService extends Service { */ public abstract int onEraseSubscriptions(int slotId); + /** + * Ensure that subscriptions will be retained on the next factory reset. + * + *
Called directly before a factory reset. Assumes that a normal factory reset will lead to + * profiles being erased on first boot (to cover fastboot/recovery wipes), so the implementation + * should persist some bit that will remain accessible after the factory reset to bypass this + * flow when this method is called. + * + * @param slotId ID of the SIM slot to use for the operation. This is currently not populated + * but is here to future-proof the APIs. + * @return the result of the operation. May be one of the predefined {@code RESULT_} constants + * or any implementation-specific code starting with {@link #RESULT_FIRST_USER}. + */ + public abstract int onRetainSubscriptionsForFactoryReset(int slotId); + /** * Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}. */ @@ -488,5 +503,21 @@ public abstract class EuiccService extends Service { } }); } + + @Override + public void retainSubscriptionsForFactoryReset(int slotId, + IRetainSubscriptionsForFactoryResetCallback callback) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + int result = EuiccService.this.onRetainSubscriptionsForFactoryReset(slotId); + try { + callback.onComplete(result); + } catch (RemoteException e) { + // Can't communicate with the phone process; ignore. + } + } + }); + } } } diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl index 18ea915d5dc7c..e10dd8cdf616e 100644 --- a/core/java/android/service/euicc/IEuiccService.aidl +++ b/core/java/android/service/euicc/IEuiccService.aidl @@ -24,6 +24,7 @@ import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback; import android.service.euicc.IGetEidCallback; import android.service.euicc.IGetEuiccInfoCallback; import android.service.euicc.IGetEuiccProfileInfoListCallback; +import android.service.euicc.IRetainSubscriptionsForFactoryResetCallback; import android.service.euicc.ISwitchToSubscriptionCallback; import android.service.euicc.IUpdateSubscriptionNicknameCallback; import android.telephony.euicc.DownloadableSubscription; @@ -46,4 +47,6 @@ oneway interface IEuiccService { void updateSubscriptionNickname(int slotId, String iccid, String nickname, in IUpdateSubscriptionNicknameCallback callback); void eraseSubscriptions(int slotId, in IEraseSubscriptionsCallback callback); + void retainSubscriptionsForFactoryReset( + int slotId, in IRetainSubscriptionsForFactoryResetCallback callback); } \ No newline at end of file diff --git a/core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl b/core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl new file mode 100644 index 0000000000000..127683059c021 --- /dev/null +++ b/core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.euicc; + +/** @hide */ +oneway interface IRetainSubscriptionsForFactoryResetCallback { + void onComplete(int result); +} \ No newline at end of file diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index f22a6327c80f4..8304d84d8a2b8 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -475,6 +475,36 @@ public class EuiccManager { } } + /** + * Ensure that subscriptions will be retained on the next factory reset. + * + *
By default, all subscriptions on the eUICC are erased the first time a device boots (ever + * and after factory resets). This ensures that the data is wiped after a factory reset is + * performed via fastboot or recovery mode, as these modes do not support the necessary radio + * communication needed to wipe the eSIM. + * + *
However, this method may be called right before a factory reset issued via settings when + * the user elects to retain subscriptions. Doing so will mark them for retention so that they + * are not cleared after the ensuing reset. + * + *
Requires that the calling app has the {@link android.Manifest.permission#MASTER_CLEAR} + * permission. This is for internal system use only. + * + * @param callbackIntent a PendingIntent to launch when the operation completes. + * @hide + */ + public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) { + if (!isEnabled()) { + sendUnavailableError(callbackIntent); + return; + } + try { + mController.retainSubscriptionsForFactoryReset(callbackIntent); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private static void sendUnavailableError(PendingIntent callbackIntent) { try { callbackIntent.send(EMBEDDED_SUBSCRIPTION_RESULT_ERROR); diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl index fa43631cee9e2..b3fc90db75d3b 100644 --- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl @@ -40,4 +40,5 @@ interface IEuiccController { oneway void updateSubscriptionNickname(int subscriptionId, String nickname, in PendingIntent callbackIntent); oneway void eraseSubscriptions(in PendingIntent callbackIntent); + oneway void retainSubscriptionsForFactoryReset(in PendingIntent callbackIntent); } \ No newline at end of file