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

Commit 70127316 authored by Tianjie Xu's avatar Tianjie Xu Committed by Gerrit Code Review
Browse files

Merge "Check slot in reboot function"

parents a906fd5e c451ffb6
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -112,6 +112,9 @@ java_library_static {
        "time_zone_distro",
        "time_zone_distro_installer",
        "android.hardware.authsecret-V1.0-java",
        "android.hardware.boot-V1.0-java",
        "android.hardware.boot-V1.1-java",
        "android.hardware.boot-V1.2-java",
        "android.hardware.broadcastradio-V2.0-java",
        "android.hardware.health-V1.0-java",
        "android.hardware.health-V2.0-java",
+76 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.hardware.boot.V1_0.IBootControl;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Binder;
@@ -73,6 +74,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
    static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
    @VisibleForTesting
    static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
    @VisibleForTesting
    static final String AB_UPDATE = "ro.build.ab_update";

    private static final Object sRequestLock = new Object();

@@ -177,6 +180,25 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
            return socket;
        }

        /**
         * Throws remote exception if there's an error getting the boot control HAL.
         * Returns null if the boot control HAL's version is older than V1_2.
         */
        public android.hardware.boot.V1_2.IBootControl getBootControl() throws RemoteException {
            IBootControl bootControlV10 = IBootControl.getService(true);
            if (bootControlV10 == null) {
                throw new RemoteException("Failed to get boot control HAL V1_0.");
            }

            android.hardware.boot.V1_2.IBootControl bootControlV12 =
                    android.hardware.boot.V1_2.IBootControl.castFrom(bootControlV10);
            if (bootControlV12 == null) {
                Slog.w(TAG, "Device doesn't implement boot control HAL V1_2.");
                return null;
            }
            return bootControlV12;
        }

        public void threadSleep(long millis) throws InterruptedException {
            Thread.sleep(millis);
        }
@@ -476,6 +498,56 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
        return needClear ? ROR_REQUESTED_NEED_CLEAR : ROR_REQUESTED_SKIP_CLEAR;
    }

    private boolean isAbDevice() {
        return "true".equalsIgnoreCase(mInjector.systemPropertiesGet(AB_UPDATE));
    }

    private boolean verifySlotForNextBoot(boolean slotSwitch) {
        if (!isAbDevice()) {
            Slog.w(TAG, "Device isn't a/b, skipping slot verification.");
            return true;
        }

        android.hardware.boot.V1_2.IBootControl bootControl;
        try {
            bootControl = mInjector.getBootControl();
        } catch (RemoteException e) {
            Slog.w(TAG, "Failed to get the boot control HAL " + e);
            return false;
        }

        // TODO(xunchang) enforce boot control V1_2 HAL on devices using multi client RoR
        if (bootControl == null) {
            Slog.w(TAG, "Cannot get the boot control HAL, skipping slot verification.");
            return true;
        }

        int current_slot;
        int next_active_slot;
        try {
            current_slot = bootControl.getCurrentSlot();
            if (current_slot != 0 && current_slot != 1) {
                throw new IllegalStateException("Current boot slot should be 0 or 1, got "
                        + current_slot);
            }
            next_active_slot = bootControl.getActiveBootSlot();
        } catch (RemoteException e) {
            Slog.w(TAG, "Failed to query the active slots", e);
            return false;
        }

        int expected_active_slot = current_slot;
        if (slotSwitch) {
            expected_active_slot = current_slot == 0 ? 1 : 0;
        }
        if (next_active_slot != expected_active_slot) {
            Slog.w(TAG, "The next active boot slot doesn't match the expected value, "
                    + "expected " + expected_active_slot + ", got " + next_active_slot);
            return false;
        }
        return true;
    }

    private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
        if (packageName == null) {
            Slog.w(TAG, "Missing packageName when rebooting with lskf.");
@@ -485,7 +557,10 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
            return false;
        }

        // TODO(xunchang) check the slot to boot into, and fail the reboot upon slot mismatch.
        if (!verifySlotForNextBoot(slotSwitch)) {
            return false;
        }

        // TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot.
        if (!mInjector.getLockSettingsService().armRebootEscrow()) {
            Slog.w(TAG, "Failure to escrow key for reboot");
+1 −1
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ public class RecoverySystemShellCommand extends ShellCommand {
    private int rebootAndApply() throws RemoteException {
        String packageName = getNextArgRequired();
        String rebootReason = getNextArgRequired();
        boolean success = mService.rebootWithLskf(packageName, rebootReason, true);
        boolean success = mService.rebootWithLskf(packageName, rebootReason, false);
        PrintWriter pw = getOutPrintWriter();
        // Keep the old message for cts test.
        pw.printf("%s Reboot and apply status: %s\n", packageName,
+18 −2
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.hardware.boot.V1_2.IBootControl;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IRecoverySystemProgressListener;
@@ -68,12 +69,13 @@ public class RecoverySystemServiceTest {
    private IThermalService mIThermalService;
    private FileWriter mUncryptUpdateFileWriter;
    private LockSettingsInternal mLockSettingsInternal;
    private IBootControl mIBootControl;

    private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package";
    private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package";

    @Before
    public void setup() {
    public void setup() throws Exception {
        mContext = mock(Context.class);
        mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties();
        mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class);
@@ -88,8 +90,13 @@ public class RecoverySystemServiceTest {
        PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
                mIThermalService, new Handler(looper));

        mIBootControl = mock(IBootControl.class);
        when(mIBootControl.getCurrentSlot()).thenReturn(0);
        when(mIBootControl.getActiveBootSlot()).thenReturn(1);

        mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
                powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal);
                powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal,
                mIBootControl);
    }

    @Test
@@ -332,6 +339,15 @@ public class RecoverySystemServiceTest {
        verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
    }


    @Test
    public void rebootWithLskf_slotMismatch_Failure() throws Exception {
        assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
        mRecoverySystemService.onPreparedForReboot(true);
        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", false),
                is(false));
    }

    @Test
    public void rebootWithLskf_withoutPrepare_Failure() throws Exception {
        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
+15 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.recoverysystem;

import android.content.Context;
import android.hardware.boot.V1_2.IBootControl;
import android.os.PowerManager;

import com.android.internal.widget.LockSettingsInternal;
@@ -30,16 +31,19 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
        private final FileWriter mUncryptPackageFileWriter;
        private final UncryptSocket mUncryptSocket;
        private final LockSettingsInternal mLockSettingsInternal;
        private final IBootControl mIBootControl;

        MockInjector(Context context, FakeSystemProperties systemProperties,
                PowerManager powerManager, FileWriter uncryptPackageFileWriter,
                UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) {
                UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
                IBootControl bootControl) {
            super(context);
            mSystemProperties = systemProperties;
            mPowerManager = powerManager;
            mUncryptPackageFileWriter = uncryptPackageFileWriter;
            mUncryptSocket = uncryptSocket;
            mLockSettingsInternal = lockSettingsInternal;
            mIBootControl = bootControl;
        }

        @Override
@@ -85,13 +89,19 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
        public LockSettingsInternal getLockSettingsService() {
            return mLockSettingsInternal;
        }

        @Override
        public IBootControl getBootControl() {
            return mIBootControl;
        }
    }

    RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties,
            PowerManager powerManager, FileWriter uncryptPackageFileWriter,
            UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) {
            UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
            IBootControl bootControl) {
        super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter,
                uncryptSocket, lockSettingsInternal));
                uncryptSocket, lockSettingsInternal, bootControl));
    }

    public static class FakeSystemProperties {
@@ -102,6 +112,8 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
                    || RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key)
                    || RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) {
                return null;
            } else if (RecoverySystemService.AB_UPDATE.equals(key)) {
                return "true";
            } else {
                throw new IllegalArgumentException("unexpected test key: " + key);
            }