Loading services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +113 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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); } } /** Loading Loading @@ -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(); Loading @@ -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. Loading Loading @@ -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() { Loading Loading @@ -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; } Loading services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java +42 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"; Loading @@ -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 Loading Loading @@ -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); Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 */); } Loading Loading @@ -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 { Loading @@ -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 Loading services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java +49 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -44,6 +45,7 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { mUncryptSocket = uncryptSocket; mLockSettingsInternal = lockSettingsInternal; mIBootControl = bootControl; mIMetricsReporter = metricsReporter; } @Override Loading Loading @@ -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 { Loading Loading @@ -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); } } Loading
services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +113 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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); } } /** Loading Loading @@ -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(); Loading @@ -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. Loading Loading @@ -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() { Loading Loading @@ -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; } Loading
services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java +42 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"; Loading @@ -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 Loading Loading @@ -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); Loading @@ -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 Loading @@ -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 Loading Loading @@ -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 */); } Loading Loading @@ -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 { Loading @@ -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 Loading
services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java +49 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -44,6 +45,7 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { mUncryptSocket = uncryptSocket; mLockSettingsInternal = lockSettingsInternal; mIBootControl = bootControl; mIMetricsReporter = metricsReporter; } @Override Loading Loading @@ -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 { Loading Loading @@ -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); } }