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

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

Merge "Report RoR metrics in recovery system"

parents eed88a70 9a8538c8
Loading
Loading
Loading
Loading
+113 −7
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.recoverysystem;

import static android.os.UserHandle.USER_SYSTEM;

import android.annotation.IntDef;
import android.content.Context;
import android.content.IntentSender;
@@ -33,12 +35,14 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.RebootEscrowListener;
import com.android.server.LocalServices;
@@ -52,6 +56,8 @@ import java.io.FileDescriptor;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * The recovery system service is responsible for coordinating recovery related
@@ -132,6 +138,24 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
            ROR_REQUESTED_SKIP_CLEAR})
    private @interface ResumeOnRebootActionsOnClear {}

    /**
     * The error code for reboots initiated by resume on reboot clients.
     */
    private static final int REBOOT_ERROR_NONE = 0;
    private static final int REBOOT_ERROR_UNKNOWN = 1;
    private static final int REBOOT_ERROR_INVALID_PACKAGE_NAME = 2;
    private static final int REBOOT_ERROR_LSKF_NOT_CAPTURED = 3;
    private static final int REBOOT_ERROR_SLOT_MISMATCH = 4;
    private static final int REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE = 5;

    @IntDef({ REBOOT_ERROR_NONE,
            REBOOT_ERROR_UNKNOWN,
            REBOOT_ERROR_INVALID_PACKAGE_NAME,
            REBOOT_ERROR_LSKF_NOT_CAPTURED,
            REBOOT_ERROR_SLOT_MISMATCH,
            REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE})
    private @interface ResumeOnRebootRebootErrorCode {}

    static class Injector {
        protected final Context mContext;

@@ -202,6 +226,35 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
        public void threadSleep(long millis) throws InterruptedException {
            Thread.sleep(millis);
        }

        public int getUidFromPackageName(String packageName) {
            try {
                return mContext.getPackageManager().getPackageUidAsUser(packageName, USER_SYSTEM);
            } catch (PackageManager.NameNotFoundException e) {
                Slog.w(TAG, "Failed to find uid for " + packageName);
            }
            return -1;
        }

        public void reportRebootEscrowPreparationMetrics(int uid,
                @ResumeOnRebootActionsOnRequest int requestResult, int requestedClientCount) {
            FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_PREPARATION_REPORTED, uid,
                    requestResult, requestedClientCount);
        }

        public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
                int requestedToLskfCapturedDurationInSeconds) {
            FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_LSKF_CAPTURE_REPORTED, uid,
                    requestedClientCount, requestedToLskfCapturedDurationInSeconds);
        }

        public void reportRebootEscrowRebootMetrics(int errorCode, int uid,
                int preparedClientCount, int requestCount, boolean slotSwitch, boolean serverBased,
                int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) {
            FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_REBOOT_REPORTED, errorCode,
                    uid, preparedClientCount, requestCount, slotSwitch, serverBased,
                    lskfCapturedToRebootDurationInSeconds, lskfCapturedCounts);
        }
    }

    /**
@@ -367,6 +420,16 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
        }
    }

    private void reportMetricsOnRequestLskf(String packageName, int requestResult) {
        int uid = mInjector.getUidFromPackageName(packageName);
        int pendingRequestCount;
        synchronized (this) {
            pendingRequestCount = mCallerPendingRequest.size();
        }

        mInjector.reportRebootEscrowPreparationMetrics(uid, requestResult, pendingRequestCount);
    }

    @Override // Binder call
    public boolean requestLskf(String packageName, IntentSender intentSender) {
        enforcePermissionForResumeOnReboot();
@@ -378,6 +441,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo

        @ResumeOnRebootActionsOnRequest int action = updateRoRPreparationStateOnNewRequest(
                packageName, intentSender);
        reportMetricsOnRequestLskf(packageName, action);

        switch (action) {
            case ROR_SKIP_PREPARATION_AND_NOTIFY:
                // We consider the preparation done if someone else has prepared.
@@ -420,12 +485,26 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
        return needPreparation ? ROR_NEED_PREPARATION : ROR_SKIP_PREPARATION_NOT_NOTIFY;
    }

    private void reportMetricsOnPreparedForReboot() {
        List<String> preparedClients;
        synchronized (this) {
            preparedClients = new ArrayList<>(mCallerPreparedForReboot);
        }

        for (String packageName : preparedClients) {
            int uid = mInjector.getUidFromPackageName(packageName);
            mInjector.reportRebootEscrowLskfCapturedMetrics(uid, preparedClients.size(),
                    -1 /* duration */);
        }
    }

    @Override
    public void onPreparedForReboot(boolean ready) {
        if (!ready) {
            return;
        }
        updateRoRPreparationStateOnPreparedForReboot();
        reportMetricsOnPreparedForReboot();
    }

    private synchronized void updateRoRPreparationStateOnPreparedForReboot() {
@@ -548,22 +627,49 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
        return true;
    }

    private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
    private @ResumeOnRebootRebootErrorCode int armRebootEscrow(String packageName,
            boolean slotSwitch) {
        if (packageName == null) {
            Slog.w(TAG, "Missing packageName when rebooting with lskf.");
            return false;
            return REBOOT_ERROR_INVALID_PACKAGE_NAME;
        }
        if (!isLskfCaptured(packageName)) {
            return false;
            return REBOOT_ERROR_LSKF_NOT_CAPTURED;
        }

        if (!verifySlotForNextBoot(slotSwitch)) {
            return false;
            return REBOOT_ERROR_SLOT_MISMATCH;
        }

        // 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");
            return REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE;
        }

        return REBOOT_ERROR_NONE;
    }

    private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch,
            @ResumeOnRebootRebootErrorCode int errorCode) {
        int uid = mInjector.getUidFromPackageName(packageName);
        boolean serverBased = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
                "server_based_ror_enabled", false);
        int preparedClientCount;
        synchronized (this) {
            preparedClientCount = mCallerPreparedForReboot.size();
        }

        // TODO(b/179105110) report the true value of duration and counts
        mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
                1 /* request count */, slotSwitch, serverBased,
                -1 /* duration */, 1 /* lskf capture count */);
    }

    private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
        @ResumeOnRebootRebootErrorCode int errorCode = armRebootEscrow(packageName, slotSwitch);
        reportMetricsOnRebootWithLskf(packageName, slotSwitch, errorCode);

        if (errorCode != REBOOT_ERROR_NONE) {
            return false;
        }

+42 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.recoverysystem;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -70,6 +71,7 @@ public class RecoverySystemServiceTest {
    private FileWriter mUncryptUpdateFileWriter;
    private LockSettingsInternal mLockSettingsInternal;
    private IBootControl mIBootControl;
    private RecoverySystemServiceTestable.IMetricsReporter mMetricsReporter;

    private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package";
    private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package";
@@ -94,9 +96,11 @@ public class RecoverySystemServiceTest {
        when(mIBootControl.getCurrentSlot()).thenReturn(0);
        when(mIBootControl.getActiveBootSlot()).thenReturn(1);

        mMetricsReporter = mock(RecoverySystemServiceTestable.IMetricsReporter.class);

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

    @Test
@@ -226,6 +230,16 @@ public class RecoverySystemServiceTest {
        mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null);
    }

    @Test
    public void requestLskf_reportMetrics() throws Exception {
        IntentSender intentSender = mock(IntentSender.class);
        assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
                is(true));
        verify(mMetricsReporter).reportRebootEscrowPreparationMetrics(
                eq(1000), eq(0) /* need preparation */, eq(1) /* client count */);
    }


    @Test
    public void requestLskf_success() throws Exception {
        IntentSender intentSender = mock(IntentSender.class);
@@ -233,6 +247,8 @@ public class RecoverySystemServiceTest {
                is(true));
        mRecoverySystemService.onPreparedForReboot(true);
        verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any());
        verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics(
                eq(1000), eq(1) /* client count */, anyInt() /* duration */);
    }

    @Test
@@ -255,6 +271,8 @@ public class RecoverySystemServiceTest {
        assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender),
                is(true));
        verify(intentSender, never()).sendIntent(any(), anyInt(), any(), any(), any());
        verify(mMetricsReporter, never()).reportRebootEscrowLskfCapturedMetrics(
                anyInt(), anyInt(), anyInt());
    }

    @Test
@@ -337,6 +355,9 @@ public class RecoverySystemServiceTest {
        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true),
                is(true));
        verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000),
                eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */,
                anyBoolean(), anyInt(), eq(1) /* lskf capture count */);
    }


@@ -373,6 +394,20 @@ public class RecoverySystemServiceTest {
        verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
    }

    @Test
    public void rebootWithLskf_multiClient_success_reportMetrics() throws Exception {
        assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true));
        assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
        mRecoverySystemService.onPreparedForReboot(true);

        // Client B's clear won't affect client A's preparation.
        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true),
                is(true));
        verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000),
                eq(2) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */,
                anyBoolean(), anyInt(), eq(1) /* lskf capture count */);
    }

    @Test
    public void rebootWithLskf_multiClient_ClientBSuccess() throws Exception {
@@ -384,12 +419,18 @@ public class RecoverySystemServiceTest {
        assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true),
                is(false));
        verifyNoMoreInteractions(mIPowerManager);
        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(not(eq(0)), eq(1000),
                eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */,
                anyBoolean(), anyInt(), eq(1) /* lskf capture count */);

        assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true));
        assertThat(
                mRecoverySystemService.rebootWithLskf(FAKE_OTHER_PACKAGE_NAME, "ab-update", true),
                is(true));
        verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean());
        verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(2000),
                eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */,
                anyBoolean(), anyInt(), eq(1) /* lskf capture count */);
    }

    @Test
+49 −3
Original line number Diff line number Diff line
@@ -32,11 +32,12 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
        private final UncryptSocket mUncryptSocket;
        private final LockSettingsInternal mLockSettingsInternal;
        private final IBootControl mIBootControl;
        private final IMetricsReporter mIMetricsReporter;

        MockInjector(Context context, FakeSystemProperties systemProperties,
                PowerManager powerManager, FileWriter uncryptPackageFileWriter,
                UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal,
                IBootControl bootControl) {
                IBootControl bootControl, IMetricsReporter metricsReporter) {
            super(context);
            mSystemProperties = systemProperties;
            mPowerManager = powerManager;
@@ -44,6 +45,7 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
            mUncryptSocket = uncryptSocket;
            mLockSettingsInternal = lockSettingsInternal;
            mIBootControl = bootControl;
            mIMetricsReporter = metricsReporter;
        }

        @Override
@@ -94,14 +96,45 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
        public IBootControl getBootControl() {
            return mIBootControl;
        }
        @Override
        public int getUidFromPackageName(String packageName) {
            if ("fake.ota.package".equals(packageName)) {
                return 1000;
            }
            if ("fake.other.package".equals(packageName)) {
                return 2000;
            }
            return 3000;
        }

        @Override
        public void reportRebootEscrowPreparationMetrics(int uid, int requestResult,
                int requestedClientCount) {
            mIMetricsReporter.reportRebootEscrowPreparationMetrics(uid, requestResult,
                    requestedClientCount);
        }

        public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
                int requestedToLskfCapturedDurationInSeconds) {
            mIMetricsReporter.reportRebootEscrowLskfCapturedMetrics(uid, requestedClientCount,
                    requestedToLskfCapturedDurationInSeconds);
        }

        public void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount,
                int requestCount, boolean slotSwitch, boolean serverBased,
                int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) {
            mIMetricsReporter.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount,
                    requestCount, slotSwitch, serverBased, lskfCapturedToRebootDurationInSeconds,
                    lskfCapturedCounts);
        }
    }

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

    public static class FakeSystemProperties {
@@ -131,4 +164,17 @@ public class RecoverySystemServiceTestable extends RecoverySystemService {
            return mCtlStart;
        }
    }

    public interface IMetricsReporter {
        void reportRebootEscrowPreparationMetrics(int uid, int requestResult,
                int requestedClientCount);

        void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount,
                int requestedToLskfCapturedDurationInSeconds);

        void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount,
                int requestCount, boolean slotSwitch, boolean serverBased,
                int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts);
    }

}