Report RoR metrics in recovery system
Add metrics reporting for resume on reboot in RecoverySystem. These metrics are reported before reboot. Details in http://go/ror-metrics Bug: 179105110 Test: build Change-Id: I5a4cb56bd1e6596f41d35259be5be4958f4a20e9
This commit is contained in:
@@ -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
|
||||
@@ -127,10 +133,28 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
|
||||
/**
|
||||
* The action to perform upon resume on reboot clear request for a given client.
|
||||
*/
|
||||
@IntDef({ROR_NOT_REQUESTED,
|
||||
@IntDef({ ROR_NOT_REQUESTED,
|
||||
ROR_REQUESTED_NEED_CLEAR,
|
||||
ROR_REQUESTED_SKIP_CLEAR})
|
||||
private @interface ResumeOnRebootActionsOnClear{}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user