diff options
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 { |