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

Commit 05ce703c authored by Ying Xu's avatar Ying Xu Committed by Android (Google) Code Review
Browse files

Merge "Add flag to wipe eUICC data" into oc-dr1-dev

parents c84cd09d f4f9cec2
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -55,7 +55,6 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract.Directory;
import android.provider.Settings;
import android.security.Credentials;
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
@@ -3133,6 +3132,14 @@ public class DevicePolicyManager {
     */
    public static final int WIPE_RESET_PROTECTION_DATA = 0x0002;

    /**
     * Flag for {@link #wipeData(int)}: also erase the device's eUICC data.
     *
     * TODO(b/35851809): make this public.
     * @hide
     */
    public static final int WIPE_EUICC = 0x0004;

    /**
     * Ask that all user data be wiped. If called as a secondary user, the user will be removed and
     * other users will remain unaffected. Calling from the primary user will cause the device to
+89 −10
Original line number Diff line number Diff line
@@ -22,20 +22,26 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

import com.android.internal.logging.MetricsLogger;

import libcore.io.Streams;

import java.io.ByteArrayInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -46,22 +52,19 @@ import java.io.InputStream;
import java.io.RandomAccessFile;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import com.android.internal.logging.MetricsLogger;

import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;

@@ -84,11 +87,19 @@ public class RecoverySystem {
    /** Send progress to listeners no more often than this (in ms). */
    private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;

    private static final long DEFAULT_EUICC_WIPING_TIMEOUT_MILLIS = 30000L; // 30 s

    private static final long MIN_EUICC_WIPING_TIMEOUT_MILLIS = 5000L; // 5 s

    private static final long MAX_EUICC_WIPING_TIMEOUT_MILLIS = 60000L; // 60 s

    /** Used to communicate with recovery.  See bootable/recovery/recovery.cpp. */
    private static final File RECOVERY_DIR = new File("/cache/recovery");
    private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
    private static final File LAST_INSTALL_FILE = new File(RECOVERY_DIR, "last_install");
    private static final String LAST_PREFIX = "last_";
    private static final String ACTION_WIPE_EUICC_DATA =
            "com.android.internal.action.WIPE_EUICC_DATA";

    /**
     * The recovery image uses this file to identify the location (i.e. blocks)
@@ -673,18 +684,26 @@ public class RecoverySystem {
     */
    public static void rebootWipeUserData(Context context) throws IOException {
        rebootWipeUserData(context, false /* shutdown */, context.getPackageName(),
                false /* force */);
                false /* force */, false /* wipeEuicc */);
    }

    /** {@hide} */
    public static void rebootWipeUserData(Context context, String reason) throws IOException {
        rebootWipeUserData(context, false /* shutdown */, reason, false /* force */);
        rebootWipeUserData(context, false /* shutdown */, reason, false /* force */,
                false /* wipeEuicc */);
    }

    /** {@hide} */
    public static void rebootWipeUserData(Context context, boolean shutdown)
            throws IOException {
        rebootWipeUserData(context, shutdown, context.getPackageName(), false /* force */);
        rebootWipeUserData(context, shutdown, context.getPackageName(), false /* force */,
                false /* wipeEuicc */);
    }

    /** {@hide} */
    public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
            boolean force) throws IOException {
        rebootWipeUserData(context, shutdown, reason, force, false /* wipeEuicc */);
    }

    /**
@@ -701,6 +720,7 @@ public class RecoverySystem {
     * @param reason    the reason for the wipe that is visible in the logs
     * @param force     whether the {@link UserManager.DISALLOW_FACTORY_RESET} user restriction
     *                  should be ignored
     * @param wipeEuicc whether wipe the euicc data
     *
     * @throws IOException  if writing the recovery command file
     * fails, or if the reboot itself fails.
@@ -709,7 +729,7 @@ public class RecoverySystem {
     * @hide
     */
    public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
            boolean force) throws IOException {
            boolean force, boolean wipeEuicc) throws IOException {
        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
        if (!force && um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
            throw new SecurityException("Wiping data is not allowed for this user.");
@@ -731,6 +751,10 @@ public class RecoverySystem {
        // Block until the ordered broadcast has completed.
        condition.block();

        if (wipeEuicc) {
            wipeEuiccData(context);
        }

        String shutdownArg = null;
        if (shutdown) {
            shutdownArg = "--shutdown_after";
@@ -745,6 +769,61 @@ public class RecoverySystem {
        bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
    }

    private static void wipeEuiccData(Context context) {
        EuiccManager euiccManager = (EuiccManager) context.getSystemService(
                Context.EUICC_SERVICE);
        if (euiccManager != null && euiccManager.isEnabled()) {
            CountDownLatch euiccFactoryResetLatch = new CountDownLatch(1);

            BroadcastReceiver euiccWipeFinishReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (ACTION_WIPE_EUICC_DATA.equals(intent.getAction())) {
                        if (getResultCode() != EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) {
                            int detailedCode = intent.getIntExtra(
                                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0);
                            Log.e(TAG, "Error wiping euicc data, Detailed code = "
                                    + detailedCode);
                        } else {
                            Log.d(TAG, "Successfully wiped euicc data.");
                        }
                        euiccFactoryResetLatch.countDown();
                    }
                }
            };

            Intent intent = new Intent(ACTION_WIPE_EUICC_DATA);
            intent.setPackage("android");
            PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser(
                    context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM);
            IntentFilter filterConsent = new IntentFilter();
            filterConsent.addAction(ACTION_WIPE_EUICC_DATA);
            HandlerThread euiccHandlerThread = new HandlerThread("euiccWipeFinishReceiverThread");
            euiccHandlerThread.start();
            Handler euiccHandler = new Handler(euiccHandlerThread.getLooper());
            context.registerReceiver(euiccWipeFinishReceiver, filterConsent, null, euiccHandler);
            euiccManager.eraseSubscriptions(callbackIntent);
            try {
                long waitingTimeMillis = Settings.Global.getLong(
                        context.getContentResolver(),
                        Settings.Global.EUICC_WIPING_TIMEOUT_MILLIS,
                        DEFAULT_EUICC_WIPING_TIMEOUT_MILLIS);
                if (waitingTimeMillis < MIN_EUICC_WIPING_TIMEOUT_MILLIS) {
                    waitingTimeMillis = MIN_EUICC_WIPING_TIMEOUT_MILLIS;
                } else if (waitingTimeMillis > MAX_EUICC_WIPING_TIMEOUT_MILLIS) {
                    waitingTimeMillis = MAX_EUICC_WIPING_TIMEOUT_MILLIS;
                }
                if (!euiccFactoryResetLatch.await(waitingTimeMillis, TimeUnit.MILLISECONDS)) {
                    Log.e(TAG, "Timeout wiping eUICC data.");
                }
                context.unregisterReceiver(euiccWipeFinishReceiver);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                Log.e(TAG, "Wiping eUICC data interrupted", e);
            }
        }
    }

    /** {@hide} */
    public static void rebootPromptAndWipeUserData(Context context, String reason)
            throws IOException {
+1 −0
Original line number Diff line number Diff line
@@ -302,6 +302,7 @@
    <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
    <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
    <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
    <protected-broadcast android:name="com.android.server.action.WIPE_EUICC_DATA" />
    <protected-broadcast android:name="com.android.server.usb.ACTION_OPEN_IN_APPS" />
    <protected-broadcast android:name="com.android.server.am.DELETE_DUMPHEAP" />
    <protected-broadcast android:name="com.android.server.net.action.SNOOZE_WARNING" />
+7 −6
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
@@ -1691,9 +1692,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            mContext.getSystemService(PowerManager.class).reboot(reason);
        }

        void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force)
                throws IOException {
            RecoverySystem.rebootWipeUserData(mContext, shutdown, reason, force);
        void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force,
                boolean wipeEuicc) throws IOException {
            RecoverySystem.rebootWipeUserData(mContext, shutdown, reason, force, wipeEuicc);
        }

        boolean systemPropertiesGetBoolean(String key, boolean def) {
@@ -5302,7 +5303,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }

    private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason) {
    private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason, boolean wipeEuicc) {
        wtfIfInLock();

        if (wipeExtRequested) {
@@ -5312,7 +5313,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
        try {
            mInjector.recoverySystemRebootWipeUserData(
                    /*shutdown=*/ false, reason, /*force=*/ true);
                    /*shutdown=*/ false, reason, /*force=*/ true, /*wipeEuicc=*/ wipeEuicc);
        } catch (IOException | SecurityException e) {
            Slog.w(LOG_TAG, "Failed requesting data wipe", e);
        }
@@ -5389,7 +5390,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            // removes that user (but still clears FRP...)
            if (userId == UserHandle.USER_SYSTEM) {
                forceWipeDeviceNoLock(/*wipeExtRequested=*/ (flags & WIPE_EXTERNAL_STORAGE) != 0,
                        reason);
                        reason, /*wipeEuicc=*/ (flags & WIPE_EUICC) != 0);
            } else {
                forceWipeUser(userId);
            }
+3 −3
Original line number Diff line number Diff line
@@ -269,9 +269,9 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
        }

        @Override
        void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force)
                throws IOException {
            services.recoverySystem.rebootWipeUserData(shutdown, reason, force);
        void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force,
                boolean wipeEuicc) throws IOException {
            services.recoverySystem.rebootWipeUserData(shutdown, reason, force, wipeEuicc);
        }

        @Override
Loading