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

Commit 61c21e7e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Persist delayed calls to factory reset..."

parents be815f05 09919468
Loading
Loading
Loading
Loading
+61 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.devicepolicy;

import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManager;
@@ -24,6 +25,7 @@ import android.os.FileUtils;
import android.os.PersistableBundle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.TypedXmlPullParser;
@@ -85,6 +87,15 @@ class DevicePolicyData {
    static final String NEW_USER_DISCLAIMER_NOT_NEEDED = "not_needed";
    static final String NEW_USER_DISCLAIMER_NEEDED = "needed";

    private static final String ATTR_FACTORY_RESET_FLAGS = "factory-reset-flags";
    private static final String ATTR_FACTORY_RESET_REASON = "factory-reset-reason";

    // NOTE: must be public because of DebugUtils.flagsToString()
    public static final int FACTORY_RESET_FLAG_ON_BOOT = 1;
    public static final int FACTORY_RESET_FLAG_WIPE_EXTERNAL_STORAGE = 2;
    public static final int FACTORY_RESET_FLAG_WIPE_EUICC = 4;
    public static final int FACTORY_RESET_FLAG_WIPE_FACTORY_RESET_PROTECTION = 8;

    private static final String TAG = DevicePolicyManagerService.LOG_TAG;
    private static final boolean VERBOSE_LOG = false; // DO NOT SUBMIT WITH TRUE

@@ -99,6 +110,9 @@ class DevicePolicyData {
    int mUserProvisioningState;
    int mPermissionPolicy;

    int mFactoryResetFlags;
    String mFactoryResetReason;

    boolean mDeviceProvisioningConfigApplied = false;

    final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>();
@@ -200,6 +214,17 @@ class DevicePolicyData {
                out.attribute(null, ATTR_NEW_USER_DISCLAIMER, policyData.mNewUserDisclaimer);
            }

            if (policyData.mFactoryResetFlags != 0) {
                if (VERBOSE_LOG) {
                    Slog.v(TAG, "Storing factory reset flags for user " + policyData.mUserId + ": "
                            + factoryResetFlagsToString(policyData.mFactoryResetFlags));
                }
                out.attributeInt(null, ATTR_FACTORY_RESET_FLAGS, policyData.mFactoryResetFlags);
            }
            if (policyData.mFactoryResetReason != null) {
                out.attribute(null, ATTR_FACTORY_RESET_REASON, policyData.mFactoryResetReason);
            }

            // Serialize delegations.
            for (int i = 0; i < policyData.mDelegationMap.size(); ++i) {
                final String delegatePackage = policyData.mDelegationMap.keyAt(i);
@@ -427,6 +452,13 @@ class DevicePolicyData {
            }
            policy.mNewUserDisclaimer = parser.getAttributeValue(null, ATTR_NEW_USER_DISCLAIMER);

            policy.mFactoryResetFlags = parser.getAttributeInt(null, ATTR_FACTORY_RESET_FLAGS, 0);
            if (VERBOSE_LOG) {
                Slog.v(TAG, "Restored factory reset flags for user " + policy.mUserId + ": "
                        + factoryResetFlagsToString(policy.mFactoryResetFlags));
            }
            policy.mFactoryResetReason = parser.getAttributeValue(null, ATTR_FACTORY_RESET_REASON);

            int outerDepth = parser.getDepth();
            policy.mLockTaskPackages.clear();
            policy.mAdminList.clear();
@@ -572,6 +604,22 @@ class DevicePolicyData {
        }
    }

    void setDelayedFactoryReset(@NonNull String reason, boolean wipeExtRequested, boolean wipeEuicc,
            boolean wipeResetProtectionData) {
        mFactoryResetReason = reason;

        mFactoryResetFlags = FACTORY_RESET_FLAG_ON_BOOT;
        if (wipeExtRequested) {
            mFactoryResetFlags |= FACTORY_RESET_FLAG_WIPE_EXTERNAL_STORAGE;
        }
        if (wipeEuicc) {
            mFactoryResetFlags |= FACTORY_RESET_FLAG_WIPE_EUICC;
        }
        if (wipeResetProtectionData) {
            mFactoryResetFlags |= FACTORY_RESET_FLAG_WIPE_FACTORY_RESET_PROTECTION;
        }
    }

    void dump(IndentingPrintWriter pw) {
        pw.println();
        pw.println("Enabled Device Admins (User " + mUserId + ", provisioningState: "
@@ -603,6 +651,19 @@ class DevicePolicyData {
        pw.print("mUserSetupComplete="); pw.println(mUserSetupComplete);
        pw.print("mAffiliationIds="); pw.println(mAffiliationIds);
        pw.print("mNewUserDisclaimer="); pw.println(mNewUserDisclaimer);
        if (mFactoryResetFlags != 0) {
            pw.print("mFactoryResetFlags="); pw.print(mFactoryResetFlags);
            pw.print(" (");
            pw.print(factoryResetFlagsToString(mFactoryResetFlags));
            pw.println(')');
        }
        if (mFactoryResetReason != null) {
            pw.print("mFactoryResetReason="); pw.println(mFactoryResetReason);
        }
        pw.decreaseIndent();
    }

    static String factoryResetFlagsToString(int flags) {
        return DebugUtils.flagsToString(DevicePolicyData.class, "FACTORY_RESET_FLAG_", flags);
    }
}
+56 −5
Original line number Diff line number Diff line
@@ -1320,12 +1320,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            mContext.getSystemService(PowerManager.class).reboot(reason);
        }
        void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force,
        boolean recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force,
                boolean wipeEuicc, boolean wipeExtRequested, boolean wipeResetProtectionData)
                        throws IOException {
            FactoryResetter.newBuilder(mContext).setSafetyChecker(mSafetyChecker)
                    .setReason(reason).setShutdown(shutdown)
                    .setForce(force).setWipeEuicc(wipeEuicc)
            return FactoryResetter.newBuilder(mContext).setSafetyChecker(mSafetyChecker)
                    .setReason(reason).setShutdown(shutdown).setForce(force).setWipeEuicc(wipeEuicc)
                    .setWipeAdoptableStorage(wipeExtRequested)
                    .setWipeFactoryResetProtection(wipeResetProtectionData)
                    .build().factoryReset();
@@ -2787,6 +2786,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                maybeStartSecurityLogMonitorOnActivityManagerReady();
                break;
            case SystemService.PHASE_BOOT_COMPLETED:
                // Ideally it should be done earlier, but currently it relies on RecoverySystem,
                // which would hang on earlier phases
                factoryResetIfDelayedEarlier();
                ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this.
                break;
        }
@@ -6261,10 +6264,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            boolean wipeResetProtectionData) {
        wtfIfInLock();
        boolean success = false;
        try {
            mInjector.recoverySystemRebootWipeUserData(
            boolean delayed = !mInjector.recoverySystemRebootWipeUserData(
                    /* shutdown= */ false, reason, /* force= */ true, /* wipeEuicc= */ wipeEuicc,
                    wipeExtRequested, wipeResetProtectionData);
            if (delayed) {
                // Persist the request so the device is automatically factory-reset on next start if
                // the system crashes or reboots before the {@code DevicePolicySafetyChecker} calls
                // its callback.
                Slog.i(LOG_TAG, String.format("Persisting factory reset request as it could be "
                        + "delayed by %s", mSafetyChecker));
                synchronized (getLockObject()) {
                    DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
                    policy.setDelayedFactoryReset(reason, wipeExtRequested, wipeEuicc,
                            wipeResetProtectionData);
                    saveSettingsLocked(UserHandle.USER_SYSTEM);
                }
            }
            success = true;
        } catch (IOException | SecurityException e) {
            Slog.w(LOG_TAG, "Failed requesting data wipe", e);
@@ -6273,6 +6290,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    private void factoryResetIfDelayedEarlier() {
        synchronized (getLockObject()) {
            DevicePolicyData policy = getUserData(UserHandle.USER_SYSTEM);
            if (policy.mFactoryResetFlags == 0) return;
            if (policy.mFactoryResetReason == null) {
                // Shouldn't happen.
                Slog.e(LOG_TAG, "no persisted reason for factory resetting");
                policy.mFactoryResetReason = "requested before boot";
            }
            FactoryResetter factoryResetter = FactoryResetter.newBuilder(mContext)
                    .setReason(policy.mFactoryResetReason).setForce(true)
                    .setWipeEuicc((policy.mFactoryResetFlags & DevicePolicyData
                            .FACTORY_RESET_FLAG_WIPE_EUICC) != 0)
                    .setWipeAdoptableStorage((policy.mFactoryResetFlags & DevicePolicyData
                            .FACTORY_RESET_FLAG_WIPE_EXTERNAL_STORAGE) != 0)
                    .setWipeFactoryResetProtection((policy.mFactoryResetFlags & DevicePolicyData
                            .FACTORY_RESET_FLAG_WIPE_FACTORY_RESET_PROTECTION) != 0)
                    .build();
            Slog.i(LOG_TAG, "Factory resetting on boot using " + factoryResetter);
            try {
                if (!factoryResetter.factoryReset()) {
                    // Shouldn't happen because FactoryResetter was created without a
                    // DevicePolicySafetyChecker.
                    Slog.wtf(LOG_TAG, "Factory reset using " + factoryResetter + " failed.");
                }
            } catch (IOException e) {
                // Shouldn't happen.
                Slog.wtf(LOG_TAG, "Could not factory reset using " + factoryResetter, e);
            }
        }
    }
    private void forceWipeUser(int userId, String wipeReasonForUser, boolean wipeSilently) {
        boolean success = false;
        try {
+35 −2
Original line number Diff line number Diff line
@@ -52,14 +52,17 @@ public final class FactoryResetter {

    /**
     * Factory reset the device according to the builder's arguments.
     *
     * @return {@code true} if device was factory reset, or {@code false} if it was delayed by the
     * {@link DevicePolicySafetyChecker}.
     */
    public void factoryReset() throws IOException {
    public boolean factoryReset() throws IOException {
        Preconditions.checkCallAuthorization(mContext.checkCallingOrSelfPermission(
                android.Manifest.permission.MASTER_CLEAR) == PackageManager.PERMISSION_GRANTED);

        if (mSafetyChecker == null) {
            factoryResetInternalUnchecked();
            return;
            return true;
        }

        IResultReceiver receiver = new IResultReceiver.Stub() {
@@ -77,6 +80,36 @@ public final class FactoryResetter {
        };
        Slog.i(TAG, String.format("Delaying factory reset until %s confirms", mSafetyChecker));
        mSafetyChecker.onFactoryReset(receiver);
        return false;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("FactoryResetter[");
        if (mReason == null) {
            builder.append("no_reason");
        } else {
            builder.append("reason='").append(mReason).append("'");
        }
        if (mSafetyChecker != null) {
            builder.append(",hasSafetyChecker");
        }
        if (mShutdown) {
            builder.append(",shutdown");
        }
        if (mForce) {
            builder.append(",force");
        }
        if (mWipeEuicc) {
            builder.append(",wipeEuicc");
        }
        if (mWipeAdoptableStorage) {
            builder.append(",wipeAdoptableStorage");
        }
        if (mWipeFactoryResetProtection) {
            builder.append(",ipeFactoryResetProtection");
        }
        return builder.append(']').toString();
    }

    private void factoryResetInternalUnchecked() throws IOException {
+13 −6
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.never;
@@ -158,10 +160,11 @@ public final class FactoryResetterTest {
    public void testFactoryReset_storageOnly() throws Exception {
        allowFactoryReset();

        FactoryResetter.newBuilder(mContext)
        boolean success = FactoryResetter.newBuilder(mContext)
                .setWipeAdoptableStorage(true).build()
                .factoryReset();

        assertThat(success).isTrue();
        verifyWipeAdoptableStorageCalled();
        verifyWipeFactoryResetProtectionNotCalled();
        verifyRebootWipeUserDataMinimumArgsCalled();
@@ -171,10 +174,11 @@ public final class FactoryResetterTest {
    public void testFactoryReset_frpOnly() throws Exception {
        allowFactoryReset();

        FactoryResetter.newBuilder(mContext)
        boolean success = FactoryResetter.newBuilder(mContext)
                .setWipeFactoryResetProtection(true)
                .build().factoryReset();

        assertThat(success).isTrue();
        verifyWipeAdoptableStorageNotCalled();
        verifyWipeFactoryResetProtectionCalled();
        verifyRebootWipeUserDataMinimumArgsCalled();
@@ -184,7 +188,7 @@ public final class FactoryResetterTest {
    public void testFactoryReset_allArgs() throws Exception {
        allowFactoryReset();

        FactoryResetter.newBuilder(mContext)
        boolean success = FactoryResetter.newBuilder(mContext)
                .setReason(REASON)
                .setForce(true)
                .setShutdown(true)
@@ -193,6 +197,7 @@ public final class FactoryResetterTest {
                .setWipeFactoryResetProtection(true)
                .build().factoryReset();

        assertThat(success).isTrue();
        verifyWipeAdoptableStorageCalled();
        verifyWipeFactoryResetProtectionCalled();
        verifyRebootWipeUserDataAllArgsCalled();
@@ -202,9 +207,10 @@ public final class FactoryResetterTest {
    public void testFactoryReset_minimumArgs_safetyChecker_neverReplied() throws Exception {
        allowFactoryReset();

        FactoryResetter.newBuilder(mContext).setSafetyChecker(mSafetyChecker).build()
                .factoryReset();
        boolean success = FactoryResetter.newBuilder(mContext)
                .setSafetyChecker(mSafetyChecker).build().factoryReset();

        assertThat(success).isFalse();
        verifyWipeAdoptableStorageNotCalled();
        verifyWipeFactoryResetProtectionNotCalled();
        verifyRebootWipeUserDataNotCalled();
@@ -221,7 +227,7 @@ public final class FactoryResetterTest {
            return null;
        }).when(mSafetyChecker).onFactoryReset(any());

        FactoryResetter.newBuilder(mContext)
        boolean success = FactoryResetter.newBuilder(mContext)
                .setSafetyChecker(mSafetyChecker)
                .setReason(REASON)
                .setForce(true)
@@ -231,6 +237,7 @@ public final class FactoryResetterTest {
                .setWipeFactoryResetProtection(true)
                .build().factoryReset();

        assertThat(success).isFalse();
        verifyWipeAdoptableStorageCalled();
        verifyWipeFactoryResetProtectionCalled();
        verifyRebootWipeUserDataAllArgsCalled();
+2 −2
Original line number Diff line number Diff line
@@ -319,10 +319,10 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
        }

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

Loading