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

Commit 097aabdb authored by Tianjie Xu's avatar Tianjie Xu Committed by Automerger Merge Worker
Browse files

Merge "Check slot in reboot function" am: 70127316 am: 4635bad1 am: 3720d381

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1504110

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I9f3568bf1c225ed9b9e498c0ea792804d8623f56
parents e8295597 3720d381
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -120,6 +120,9 @@ java_library_static {
        "time_zone_distro",
        "time_zone_distro",
        "time_zone_distro_installer",
        "time_zone_distro_installer",
        "android.hardware.authsecret-V1.0-java",
        "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.broadcastradio-V2.0-java",
        "android.hardware.health-V1.0-java",
        "android.hardware.health-V1.0-java",
        "android.hardware.health-V2.0-java",
        "android.hardware.health-V2.0-java",
+76 −1
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.content.Context;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.hardware.boot.V1_0.IBootControl;
import android.net.LocalSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.LocalSocketAddress;
import android.os.Binder;
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";
    static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
    @VisibleForTesting
    @VisibleForTesting
    static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
    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();
    private static final Object sRequestLock = new Object();


@@ -177,6 +180,25 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
            return socket;
            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 {
        public void threadSleep(long millis) throws InterruptedException {
            Thread.sleep(millis);
            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;
        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) {
    private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
        if (packageName == null) {
        if (packageName == null) {
            Slog.w(TAG, "Missing packageName when rebooting with lskf.");
            Slog.w(TAG, "Missing packageName when rebooting with lskf.");
@@ -485,7 +557,10 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
            return false;
            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.
        // TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot.
        if (!mInjector.getLockSettingsService().armRebootEscrow()) {
        if (!mInjector.getLockSettingsService().armRebootEscrow()) {
            Slog.w(TAG, "Failure to escrow key for reboot");
            Slog.w(TAG, "Failure to escrow key for reboot");
+1 −1
Original line number Original line Diff line number Diff line
@@ -76,7 +76,7 @@ public class RecoverySystemShellCommand extends ShellCommand {
    private int rebootAndApply() throws RemoteException {
    private int rebootAndApply() throws RemoteException {
        String packageName = getNextArgRequired();
        String packageName = getNextArgRequired();
        String rebootReason = getNextArgRequired();
        String rebootReason = getNextArgRequired();
        boolean success = mService.rebootWithLskf(packageName, rebootReason, true);
        boolean success = mService.rebootWithLskf(packageName, rebootReason, false);
        PrintWriter pw = getOutPrintWriter();
        PrintWriter pw = getOutPrintWriter();
        // Keep the old message for cts test.
        // Keep the old message for cts test.
        pw.printf("%s Reboot and apply status: %s\n", packageName,
        pw.printf("%s Reboot and apply status: %s\n", packageName,
+18 −2
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.hardware.boot.V1_2.IBootControl;
import android.os.Handler;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IPowerManager;
import android.os.IRecoverySystemProgressListener;
import android.os.IRecoverySystemProgressListener;
@@ -68,12 +69,13 @@ public class RecoverySystemServiceTest {
    private IThermalService mIThermalService;
    private IThermalService mIThermalService;
    private FileWriter mUncryptUpdateFileWriter;
    private FileWriter mUncryptUpdateFileWriter;
    private LockSettingsInternal mLockSettingsInternal;
    private LockSettingsInternal mLockSettingsInternal;
    private IBootControl mIBootControl;


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


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


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

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


    @Test
    @Test
@@ -332,6 +339,15 @@ public class RecoverySystemServiceTest {
        verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
        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
    @Test
    public void rebootWithLskf_withoutPrepare_Failure() throws Exception {
    public void rebootWithLskf_withoutPrepare_Failure() throws Exception {
        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
+15 −3
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.recoverysystem;
package com.android.server.recoverysystem;


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


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


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


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

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


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


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