summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/java/com/android/safetycenter/SafetySources.java6
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterDataManager.java151
-rw-r--r--service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java2
-rw-r--r--service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java65
-rw-r--r--service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java112
-rw-r--r--tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt25
-rw-r--r--tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt16
7 files changed, 143 insertions, 234 deletions
diff --git a/service/java/com/android/safetycenter/SafetySources.java b/service/java/com/android/safetycenter/SafetySources.java
index f0f1ac7d6..c0b0bdc48 100644
--- a/service/java/com/android/safetycenter/SafetySources.java
+++ b/service/java/com/android/safetycenter/SafetySources.java
@@ -51,12 +51,6 @@ public final class SafetySources {
return false;
}
- /** Returns whether a {@link SafetySource} is issue-only. */
- public static boolean isIssueOnly(SafetySource safetySource) {
- int safetySourceType = safetySource.getType();
- return safetySourceType == SafetySource.SAFETY_SOURCE_TYPE_ISSUE_ONLY;
- }
-
/** Returns whether a {@link SafetySource} supports managed profiles. */
public static boolean supportsManagedProfiles(SafetySource safetySource) {
int safetySourceProfile = safetySource.getProfile();
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java b/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java
index 3a5afe28a..edbceaa15 100644
--- a/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java
+++ b/service/java/com/android/safetycenter/data/SafetyCenterDataManager.java
@@ -21,11 +21,10 @@ import static android.os.Build.VERSION_CODES.TIRAMISU;
import static com.android.safetycenter.logging.SafetyCenterStatsdLogger.toSystemEventResult;
import android.annotation.Nullable;
-import android.annotation.UptimeMillisLong;
import android.annotation.UserIdInt;
import android.content.Context;
-import android.os.SystemClock;
import android.safetycenter.SafetyCenterData;
+import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.safetycenter.SafetySourceErrorDetails;
@@ -159,8 +158,8 @@ public final class SafetyCenterDataManager {
mSafetyCenterIssueRepository.updateIssues(userId);
}
- logSafetySourceStateCollected(
- key, userId, safetySourceData, refreshReason, sourceDataDiffers);
+ logSafetySourceStateCollectedSourceUpdated(
+ key, safetySourceData, refreshReason, sourceDataDiffers, userId, safetyEvent);
return safetyCenterDataChanged;
}
@@ -203,23 +202,32 @@ public final class SafetyCenterDataManager {
null, safetySourceId, packageName, userId)) {
return false;
}
+ SafetyEvent safetyEvent = safetySourceErrorDetails.getSafetyEvent();
+ SafetySourceKey key = SafetySourceKey.of(safetySourceId, userId);
+
+ // Must fetch refresh reason before calling processSafetyEvent because the latter may
+ // complete and clear the current refresh.
+ // TODO(b/277174417): Restructure this code to avoid this error-prone sequencing concern
+ Integer refreshReason = null;
+ if (safetyEvent.getType() == SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED) {
+ refreshReason = mSafetyCenterRefreshTracker.getRefreshReason();
+ }
+
boolean sourceDataDiffers =
mSafetySourceDataRepository.reportSafetySourceError(
safetySourceErrorDetails, safetySourceId, userId);
boolean eventCausedChange =
- processSafetyEvent(
- safetySourceId,
- safetySourceErrorDetails.getSafetyEvent(),
- userId,
- true,
- false);
-
- if (eventCausedChange || sourceDataDiffers) {
+ processSafetyEvent(safetySourceId, safetyEvent, userId, true, sourceDataDiffers);
+ boolean safetyCenterDataChanged = sourceDataDiffers || eventCausedChange;
+
+ if (safetyCenterDataChanged) {
mSafetyCenterIssueRepository.updateIssues(userId);
- return true;
}
- return false;
+ logSafetySourceStateCollectedSourceUpdated(
+ key, null, refreshReason, sourceDataDiffers, userId, safetyEvent);
+
+ return safetyCenterDataChanged;
}
/**
@@ -368,20 +376,6 @@ public final class SafetyCenterDataManager {
}
/**
- * Returns the list of issues for the given {@code userId} which were removed from the given
- * list of issues in the most recent {@link SafetyCenterIssueDeduplicator#deduplicateIssues}
- * call. These issues were removed because they were duplicates of other issues (see {@link
- * SafetySourceIssue#getDeduplicationId()} for more info).
- *
- * <p>If this method is called before any calls to {@link
- * SafetyCenterIssueDeduplicator#deduplicateIssues} then an empty list is returned.
- */
- public List<SafetySourceIssueInfo> getMostRecentFilteredOutDuplicateIssues(
- @UserIdInt int userId) {
- return mSafetyCenterIssueRepository.getMostRecentFilteredOutDuplicateIssues(userId);
- }
-
- /**
* Returns a set of {@link SafetySourcesGroup} IDs that the given {@link SafetyCenterIssueKey}
* is mapped to, or an empty list of no such mapping is configured.
*
@@ -471,26 +465,6 @@ public final class SafetyCenterDataManager {
return mSafetySourceDataRepository.getSafetySourceIssueAction(safetyCenterIssueActionId);
}
- /**
- * Returns the elapsed realtime millis of when the data of the given {@link SafetySourceKey} was
- * last updated, or {@code 0L} if no update has occurred.
- *
- * @see SystemClock#elapsedRealtime()
- */
- @UptimeMillisLong
- public long getSafetySourceLastUpdated(SafetySourceKey safetySourceKey) {
- return mSafetySourceDataRepository.getSafetySourceLastUpdated(safetySourceKey);
- }
-
- /**
- * Returns the current {@link SafetyCenterStatsdLogger.SourceState} of the given {@link
- * SafetySourceKey}.
- */
- @SafetyCenterStatsdLogger.SourceState
- public int getSourceState(SafetySourceKey safetySourceKey) {
- return mSafetySourceDataRepository.getSourceState(safetySourceKey);
- }
-
///////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Other /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -558,12 +532,50 @@ public final class SafetyCenterDataManager {
return false;
}
+ /**
+ * Writes a SafetySourceStateCollected atom for the given source in response to a stats pull.
+ */
+ public void logSafetySourceStateCollectedAutomatic(
+ SafetySourceKey sourceKey, boolean isManagedProfile) {
+ logSafetySourceStateCollected(
+ sourceKey,
+ getSafetySourceDataInternal(sourceKey),
+ /* refreshReason= */ null,
+ /* sourceDataDiffers= */ false,
+ isManagedProfile,
+ /* safetyEvent= */ null,
+ mSafetySourceDataRepository.getSafetySourceLastUpdated(sourceKey));
+ }
+
+ /**
+ * Writes a SafetySourceStateCollected atom for the given source in response to that source
+ * updating its own state.
+ */
+ private void logSafetySourceStateCollectedSourceUpdated(
+ SafetySourceKey key,
+ @Nullable SafetySourceData safetySourceData,
+ @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason,
+ boolean sourceDataDiffers,
+ int userId,
+ SafetyEvent safetyEvent) {
+ logSafetySourceStateCollected(
+ key,
+ safetySourceData,
+ refreshReason,
+ sourceDataDiffers,
+ UserUtils.isManagedProfile(userId, mContext),
+ safetyEvent,
+ /* lastUpdatedElapsedTimeMillis= */ null);
+ }
+
private void logSafetySourceStateCollected(
SafetySourceKey sourceKey,
- @UserIdInt int userId,
@Nullable SafetySourceData sourceData,
- @Nullable Integer refreshReason,
- boolean sourceDataDiffers) {
+ @Nullable @SafetyCenterManager.RefreshReason Integer refreshReason,
+ boolean sourceDataDiffers,
+ boolean isManagedProfile,
+ @Nullable SafetyEvent safetyEvent,
+ @Nullable Long lastUpdatedElapsedTimeMillis) {
SafetySourceStatus sourceStatus = sourceData == null ? null : sourceData.getStatus();
List<SafetySourceIssue> sourceIssues =
sourceData == null ? Collections.emptyList() : sourceData.getIssues();
@@ -581,7 +593,7 @@ public final class SafetyCenterDataManager {
long dismissedIssuesCount = 0;
for (int i = 0; i < sourceIssues.size(); i++) {
SafetySourceIssue issue = sourceIssues.get(i);
- if (isIssueDismissed(issue, sourceKey.getSourceId(), userId)) {
+ if (isIssueDismissed(issue, sourceKey)) {
dismissedIssuesCount++;
} else {
openIssuesCount++;
@@ -589,39 +601,40 @@ public final class SafetyCenterDataManager {
}
}
- SafetyCenterStatsdLogger.writeSafetySourceStateCollectedSourceUpdated(
+ SafetyCenterStatsdLogger.writeSafetySourceStateCollected(
sourceKey.getSourceId(),
- UserUtils.isManagedProfile(userId, mContext),
+ isManagedProfile,
maxSeverityLevel > Integer.MIN_VALUE ? maxSeverityLevel : null,
openIssuesCount,
dismissedIssuesCount,
- getDuplicateFilteredOutIssueCount(userId, sourceKey.getSourceId()),
- getSourceState(sourceKey),
+ getDuplicateCount(sourceKey),
+ mSafetySourceDataRepository.getSourceState(sourceKey),
+ safetyEvent,
refreshReason,
- sourceDataDiffers);
+ sourceDataDiffers,
+ lastUpdatedElapsedTimeMillis);
}
- private boolean isIssueDismissed(
- SafetySourceIssue issue, String sourceId, @UserIdInt int userId) {
+ private boolean isIssueDismissed(SafetySourceIssue issue, SafetySourceKey sourceKey) {
SafetyCenterIssueKey issueKey =
SafetyCenterIssueKey.newBuilder()
- .setSafetySourceId(sourceId)
+ .setSafetySourceId(sourceKey.getSourceId())
.setSafetySourceIssueId(issue.getId())
- .setUserId(userId)
+ .setUserId(sourceKey.getUserId())
.build();
return mSafetyCenterIssueDismissalRepository.isIssueDismissed(
issueKey, issue.getSeverityLevel());
}
- private long getDuplicateFilteredOutIssueCount(@UserIdInt int userId, String sourceId) {
- long duplicateFilteredOutIssuesCount = 0;
- List<SafetySourceIssueInfo> filteredOutDuplicateIssues =
- getMostRecentFilteredOutDuplicateIssues(userId);
- for (int i = 0; i < filteredOutDuplicateIssues.size(); i++) {
- if (filteredOutDuplicateIssues.get(i).getSafetySource().getId().equals(sourceId)) {
- duplicateFilteredOutIssuesCount++;
+ private long getDuplicateCount(SafetySourceKey sourceKey) {
+ long count = 0;
+ List<SafetySourceIssueInfo> duplicates =
+ mSafetyCenterIssueRepository.getLatestDuplicates(sourceKey.getUserId());
+ for (int i = 0; i < duplicates.size(); i++) {
+ if (duplicates.get(i).getSafetySource().getId().equals(sourceKey.getSourceId())) {
+ count++;
}
}
- return duplicateFilteredOutIssuesCount;
+ return count;
}
}
diff --git a/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java b/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java
index d1f89829a..566c28c1e 100644
--- a/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java
+++ b/service/java/com/android/safetycenter/data/SafetyCenterIssueRepository.java
@@ -184,7 +184,7 @@ final class SafetyCenterIssueRepository {
* <p>If this method is called before any calls to {@link
* SafetyCenterIssueDeduplicator#deduplicateIssues} then an empty list is returned.
*/
- List<SafetySourceIssueInfo> getMostRecentFilteredOutDuplicateIssues(@UserIdInt int userId) {
+ List<SafetySourceIssueInfo> getLatestDuplicates(@UserIdInt int userId) {
return mUserIdToDedupInfo.get(userId, EMPTY_DEDUP_INFO).getFilteredOutDuplicateIssues();
}
diff --git a/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java b/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java
index f9d2914bc..d9514f56e 100644
--- a/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java
+++ b/service/java/com/android/safetycenter/logging/SafetyCenterPullAtomCallback.java
@@ -17,20 +17,14 @@
package com.android.safetycenter.logging;
import static android.os.Build.VERSION_CODES.TIRAMISU;
-import static android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED;
import static com.android.permission.PermissionStatsLog.SAFETY_STATE;
-import static java.util.Collections.emptyList;
-
import android.annotation.UserIdInt;
import android.app.StatsManager;
import android.app.StatsManager.StatsPullAtomCallback;
import android.content.Context;
import android.safetycenter.SafetyCenterData;
-import android.safetycenter.SafetySourceData;
-import android.safetycenter.SafetySourceIssue;
-import android.safetycenter.SafetySourceStatus;
import android.safetycenter.config.SafetySource;
import android.safetycenter.config.SafetySourcesGroup;
import android.util.Log;
@@ -45,12 +39,10 @@ import com.android.safetycenter.ApiLock;
import com.android.safetycenter.SafetyCenterConfigReader;
import com.android.safetycenter.SafetyCenterDataFactory;
import com.android.safetycenter.SafetyCenterFlags;
-import com.android.safetycenter.SafetySourceIssueInfo;
import com.android.safetycenter.SafetySourceKey;
import com.android.safetycenter.SafetySources;
import com.android.safetycenter.UserProfileGroup;
import com.android.safetycenter.data.SafetyCenterDataManager;
-import com.android.safetycenter.internaldata.SafetyCenterIssueKey;
import java.util.List;
@@ -183,61 +175,6 @@ public final class SafetyCenterPullAtomCallback implements StatsPullAtomCallback
private void writeSafetySourceStateCollectedAtomLocked(
SafetySource safetySource, @UserIdInt int userId, boolean isUserManaged) {
SafetySourceKey sourceKey = SafetySourceKey.of(safetySource.getId(), userId);
- SafetySourceData sourceData = mDataManager.getSafetySourceDataInternal(sourceKey);
- SafetySourceStatus sourceStatus = sourceData == null ? null : sourceData.getStatus();
- List<SafetySourceIssue> sourceIssues =
- sourceData == null ? emptyList() : sourceData.getIssues();
-
- boolean isIssueOnlyWithData = SafetySources.isIssueOnly(safetySource) && sourceData != null;
- int maxSeverityLevel = isIssueOnlyWithData ? SEVERITY_LEVEL_UNSPECIFIED : Integer.MIN_VALUE;
- long openIssuesCount = 0;
- long dismissedIssuesCount = 0;
- for (int i = 0; i < sourceIssues.size(); i++) {
- SafetySourceIssue issue = sourceIssues.get(i);
- if (isIssueDismissedLocked(issue, safetySource.getId(), userId)) {
- dismissedIssuesCount++;
- } else {
- openIssuesCount++;
- maxSeverityLevel = Math.max(maxSeverityLevel, issue.getSeverityLevel());
- }
- }
- if (sourceStatus != null) {
- maxSeverityLevel = Math.max(maxSeverityLevel, sourceStatus.getSeverityLevel());
- }
-
- SafetyCenterStatsdLogger.writeSafetySourceStateCollectedAutomatic(
- safetySource.getId(),
- isUserManaged,
- maxSeverityLevel > Integer.MIN_VALUE ? maxSeverityLevel : null,
- openIssuesCount,
- dismissedIssuesCount,
- getDuplicateFilteredOutIssueCountLocked(userId, sourceKey.getSourceId()),
- mDataManager.getSourceState(sourceKey),
- mDataManager.getSafetySourceLastUpdated(sourceKey));
- }
-
- @GuardedBy("mApiLock")
- private boolean isIssueDismissedLocked(
- SafetySourceIssue issue, String sourceId, @UserIdInt int userId) {
- SafetyCenterIssueKey issueKey =
- SafetyCenterIssueKey.newBuilder()
- .setSafetySourceId(sourceId)
- .setSafetySourceIssueId(issue.getId())
- .setUserId(userId)
- .build();
- return mDataManager.isIssueDismissed(issueKey, issue.getSeverityLevel());
- }
-
- @GuardedBy("mApiLock")
- private long getDuplicateFilteredOutIssueCountLocked(@UserIdInt int userId, String sourceId) {
- long duplicateFilteredOutIssuesCount = 0;
- List<SafetySourceIssueInfo> filteredOutDuplicateIssues =
- mDataManager.getMostRecentFilteredOutDuplicateIssues(userId);
- for (int i = 0; i < filteredOutDuplicateIssues.size(); i++) {
- if (filteredOutDuplicateIssues.get(i).getSafetySource().getId().equals(sourceId)) {
- duplicateFilteredOutIssuesCount++;
- }
- }
- return duplicateFilteredOutIssuesCount;
+ mDataManager.logSafetySourceStateCollectedAutomatic(sourceKey, isUserManaged);
}
}
diff --git a/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java b/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java
index c29a25761..8c5916cc3 100644
--- a/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java
+++ b/service/java/com/android/safetycenter/logging/SafetyCenterStatsdLogger.java
@@ -74,10 +74,10 @@ import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SE
import android.annotation.IntDef;
import android.annotation.Nullable;
-import android.annotation.UptimeMillisLong;
import android.safetycenter.SafetyCenterManager;
import android.safetycenter.SafetyCenterManager.RefreshRequestType;
import android.safetycenter.SafetyCenterStatus;
+import android.safetycenter.SafetyEvent;
import android.safetycenter.SafetySourceData;
import android.util.Log;
import android.util.StatsEvent;
@@ -108,8 +108,6 @@ public final class SafetyCenterStatsdLogger {
private static final long UNSET_ISSUE_TYPE_ID = 0;
private static final long UNSET_SESSION_ID = 0;
private static final long UNSET_SOURCE_GROUP_ID = 0;
- private static final int UNSET_UPDATE_TYPE =
- SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__UPDATE_TYPE_UNKNOWN;
private static final long UNSET_REFRESH_REASON = 0L;
private static final boolean UNSET_DATA_CHANGED = false;
private static final long UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS = 0L;
@@ -163,54 +161,8 @@ public final class SafetyCenterStatsdLogger {
dismissedIssueCount);
}
- /**
- * Writes a {@link PermissionStatsLog#SAFETY_SOURCE_STATE_COLLECTED} atom with {@code AUTOMATIC}
- * collection type.
- *
- * <p>The method should be used during periodic statsd pull and not due to new data being
- * received from the source.
- *
- * @param sourceSeverityLevel is the {@link SafetySourceData.SeverityLevel} to log for this
- * source, or {@code null} if none/unknown severity should be recorded.
- */
- static void writeSafetySourceStateCollectedAutomatic(
- String sourceId,
- boolean isManagedProfile,
- @Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel,
- long openIssuesCount,
- long dismissedIssuesCount,
- long duplicateFilteredOutIssuesCount,
- @SourceState int sourceState,
- @UptimeMillisLong long lastUpdatedElapsedTimeMillis) {
- writeSafetySourceStateCollected(
- sourceId,
- isManagedProfile,
- sourceSeverityLevel,
- openIssuesCount,
- dismissedIssuesCount,
- duplicateFilteredOutIssuesCount,
- sourceState,
- SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__AUTOMATIC,
- UNSET_UPDATE_TYPE,
- UNSET_REFRESH_REASON,
- UNSET_DATA_CHANGED,
- lastUpdatedElapsedTimeMillis);
- }
-
- /**
- * Writes a {@link PermissionStatsLog#SAFETY_SOURCE_STATE_COLLECTED} atom with {@code
- * SOURCE_UPDATED} collection type.
- *
- * <p>This method should be used when new data is received from the source in response to a
- * refresh request from Safety Center, or spontaneously i.e. pushed by the source not in
- * response to a refresh.
- *
- * @param sourceSeverityLevel is the {@link SafetySourceData.SeverityLevel} to log for this
- * source, or {@code null} if none/unknown severity should be recorded.
- * @param refreshReason is the {@link SafetyCenterManager.RefreshReason} of the refresh the
- * source is responding to, or {@code null} if the source pushed data spontaneously.
- */
- public static void writeSafetySourceStateCollectedSourceUpdated(
+ /** Writes a {@link PermissionStatsLog#SAFETY_SOURCE_STATE_COLLECTED} atom. */
+ public static void writeSafetySourceStateCollected(
String sourceId,
boolean isManagedProfile,
@Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel,
@@ -218,43 +170,17 @@ public final class SafetyCenterStatsdLogger {
long dismissedIssuesCount,
long duplicateFilteredOutIssuesCount,
@SourceState int sourceState,
+ @Nullable SafetyEvent safetyEvent,
@Nullable @SafetyCenterManager.RefreshReason Integer refreshReason,
- boolean dataChanged) {
- int updateType =
- refreshReason != null
- ? SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__REFRESH_RESPONSE
- : SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__SELF_INITIATED;
- writeSafetySourceStateCollected(
- sourceId,
- isManagedProfile,
- sourceSeverityLevel,
- openIssuesCount,
- dismissedIssuesCount,
- duplicateFilteredOutIssuesCount,
- sourceState,
- SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__SOURCE_UPDATED,
- updateType,
- refreshReason != null ? refreshReason : UNSET_REFRESH_REASON,
- dataChanged,
- UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS);
- }
-
- private static void writeSafetySourceStateCollected(
- String sourceId,
- boolean isManagedProfile,
- @Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel,
- long openIssuesCount,
- long dismissedIssuesCount,
- long duplicateFilteredOutIssuesCount,
- @SourceState int sourceState,
- int collectionType,
- int updateType,
- long refreshReason,
boolean dataChanged,
- long lastUpdatedElapsedTimeMillis) {
+ @Nullable Long lastUpdatedElapsedTimeMillis) {
if (!SafetyCenterFlags.getAllowStatsdLogging()) {
return;
}
+ int collectionType =
+ safetyEvent != null
+ ? SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__SOURCE_UPDATED
+ : SAFETY_SOURCE_STATE_COLLECTED__COLLECTION_TYPE__AUTOMATIC;
PermissionStatsLog.write(
SAFETY_SOURCE_STATE_COLLECTED,
idStringToLong(sourceId),
@@ -265,10 +191,12 @@ public final class SafetyCenterStatsdLogger {
duplicateFilteredOutIssuesCount,
sourceState,
collectionType,
- updateType,
- refreshReason,
+ toSafetySourceStateCollectedCollectionType(safetyEvent),
+ refreshReason != null ? refreshReason : UNSET_REFRESH_REASON,
dataChanged,
- lastUpdatedElapsedTimeMillis);
+ lastUpdatedElapsedTimeMillis != null
+ ? lastUpdatedElapsedTimeMillis
+ : UNSET_LAST_UPDATED_ELAPSED_TIME_MILLIS);
}
/**
@@ -541,4 +469,16 @@ public final class SafetyCenterStatsdLogger {
Log.w(TAG, "Unexpected SafetySourceData.SeverityLevel: " + severityLevel);
return SAFETY_STATE__OVERALL_SEVERITY_LEVEL__SAFETY_SEVERITY_LEVEL_UNKNOWN;
}
+
+ private static int toSafetySourceStateCollectedCollectionType(
+ @Nullable SafetyEvent safetyEvent) {
+ if (safetyEvent == null) {
+ return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__UPDATE_TYPE_UNKNOWN;
+ }
+ if (safetyEvent.getType() == SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED) {
+ return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__REFRESH_RESPONSE;
+ } else {
+ return SAFETY_SOURCE_STATE_COLLECTED__UPDATE_TYPE__SELF_INITIATED;
+ }
+ }
}
diff --git a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt
index 52a9750eb..b7bd60d10 100644
--- a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt
+++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt
@@ -18,10 +18,13 @@ package android.safetycenter.hostside.device
import android.content.Context
import android.safetycenter.SafetyCenterManager
+import android.safetycenter.SafetyEvent
+import android.safetycenter.SafetySourceErrorDetails
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compatibility.common.util.SystemUtil
import com.android.safetycenter.testing.*
+import com.android.safetycenter.testing.SafetyCenterApisWithShellPermissions.reportSafetySourceErrorWithPermission
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_1
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_2
import com.android.safetycenter.testing.SafetyCenterTestConfigs.Companion.SOURCE_ID_3
@@ -67,6 +70,16 @@ class SafetySourceStateCollectedLoggingHelperTests {
}
@Test
+ fun reportSafetySourceError_source1() {
+ safetyCenterManager.reportSafetySourceErrorWithPermission(
+ SOURCE_ID_1,
+ SafetySourceErrorDetails(
+ SafetyEvent.Builder(SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
+ )
+ )
+ }
+
+ @Test
fun refreshAllSources_reasonPageOpen_allSuccessful() {
simulateRefresh(
Response.SetData(safetySourceTestData.information),
@@ -89,14 +102,14 @@ class SafetySourceStateCollectedLoggingHelperTests {
@Test
fun refreshAllSources_twiceDifferentData_onlySource1Unchanged() {
simulateRefresh(
- Response.SetData(safetySourceTestData.information),
- Response.SetData(safetySourceTestData.recommendationWithAccountIssue),
- Response.SetData(safetySourceTestData.criticalWithResolvingDeviceIssue)
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.recommendationWithAccountIssue),
+ Response.SetData(safetySourceTestData.criticalWithResolvingDeviceIssue)
)
simulateRefresh(
- Response.SetData(safetySourceTestData.information),
- Response.SetData(safetySourceTestData.information),
- Response.SetData(safetySourceTestData.information)
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.information),
+ Response.SetData(safetySourceTestData.information)
)
}
diff --git a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt
index 8c00ef35c..22a380e12 100644
--- a/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt
+++ b/tests/hostside/safetycenter/src/android/safetycenter/hostside/SafetySourceStateCollectedLoggingHostTest.kt
@@ -104,6 +104,18 @@ class SafetySourceStateCollectedLoggingHostTest : BaseHostJUnit4Test() {
.containsExactly(SafetySourceStateCollected.CollectionType.SOURCE_UPDATED)
}
+ @Test
+ fun reportSafetySourceError_atomPushedForThatSource() {
+ helperAppRule.runTest(TEST_CLASS_NAME, "reportSafetySourceError_source1")
+
+ val sourceStateAtoms = getSafetySourceStateCollectedAtoms()
+
+ assertThat(sourceStateAtoms.map { it.encodedSafetySourceId })
+ .containsExactly(SOURCE_1_ENCODED_SOURCE_ID)
+ assertThat(sourceStateAtoms.map { it.collectionType })
+ .containsExactly(SafetySourceStateCollected.CollectionType.SOURCE_UPDATED)
+ }
+
private fun getSafetySourceStateCollectedAtoms() =
ReportUtils.getEventMetricDataList(device)
.mapNotNull { it.atom.safetySourceStateCollected }
@@ -113,8 +125,8 @@ class SafetySourceStateCollectedLoggingHostTest : BaseHostJUnit4Test() {
// specifically filter the resultant atoms out using the real encoded source ID.
// Similar failures are also observed on Android Test Hub due to the background
// location source (b/278782808)
- it.encodedSafetySourceId == PLAY_PROTECT_ENCODED_SOURCE_ID
- || it.encodedSafetySourceId == BACKGROUND_LOCATION_ENCODED_SOURCE_ID
+ it.encodedSafetySourceId == PLAY_PROTECT_ENCODED_SOURCE_ID ||
+ it.encodedSafetySourceId == BACKGROUND_LOCATION_ENCODED_SOURCE_ID
}
private companion object {