diff options
-rw-r--r-- | PermissionController/res/values-ar/strings.xml | 2 | ||||
-rw-r--r-- | PermissionController/res/values-nb/strings.xml | 4 | ||||
-rw-r--r-- | PermissionController/res/values-ro-v33/strings.xml | 10 | ||||
-rw-r--r-- | service/java/com/android/safetycenter/SafetyCenterConfigReader.java | 6 | ||||
-rw-r--r-- | service/java/com/android/safetycenter/SafetyCenterDataTracker.java | 103 | ||||
-rw-r--r-- | service/java/com/android/safetycenter/SafetyCenterFlags.java | 13 | ||||
-rw-r--r-- | service/java/com/android/safetycenter/SafetyCenterPullAtomCallback.java | 222 | ||||
-rw-r--r-- | service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java | 18 | ||||
-rw-r--r-- | service/java/com/android/safetycenter/SafetyCenterRepository.java | 22 | ||||
-rw-r--r-- | service/java/com/android/safetycenter/SafetyCenterService.java | 65 | ||||
-rw-r--r-- | service/java/com/android/safetycenter/StatsdLogger.java (renamed from service/java/com/android/safetycenter/WestworldLogger.java) | 48 | ||||
-rw-r--r-- | tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt | 17 |
12 files changed, 302 insertions, 228 deletions
diff --git a/PermissionController/res/values-ar/strings.xml b/PermissionController/res/values-ar/strings.xml index f1bfe5691..d8e2d02ab 100644 --- a/PermissionController/res/values-ar/strings.xml +++ b/PermissionController/res/values-ar/strings.xml @@ -463,7 +463,7 @@ <string name="permgrouprequest_coarselocation" msgid="7244605063736425232">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الموقع الجغرافي التقريبي لهذا الجهاز؟"</string> <string name="permgrouprequest_finelocation_imagetext" msgid="1313062433398914334">"دقيق"</string> <string name="permgrouprequest_coarselocation_imagetext" msgid="8650605041483025297">"تقريبي"</string> - <string name="permgrouprequest_calendar" msgid="1493150855673603806">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالدخول إلى التقويم؟"</string> + <string name="permgrouprequest_calendar" msgid="1493150855673603806">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى التقويم؟"</string> <string name="permgrouprequest_sms" msgid="5672063688745420991">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بإرسال رسائل SMS وعرضها؟"</string> <string name="permgrouprequest_storage" msgid="8717773092518621602">"هل تريد السماح لتطبيق <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> بالوصول إلى الصور والوسائط والملفات على جهازك؟"</string> <string name="permgrouprequest_storage_q_to_s" msgid="8213701872983685505">"هل تسمح بوصول <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> إلى <b>الصور والفيديوهات والموسيقى والملفات الصوتية</b> على هذا الجهاز؟"</string> diff --git a/PermissionController/res/values-nb/strings.xml b/PermissionController/res/values-nb/strings.xml index 35e713151..c48bb2299 100644 --- a/PermissionController/res/values-nb/strings.xml +++ b/PermissionController/res/values-nb/strings.xml @@ -173,8 +173,8 @@ <string name="sort_spinner_most_permissions" msgid="1704349738096822836">"Flest tillatelser"</string> <string name="sort_spinner_most_accesses" msgid="5283913004357220161">"Mest brukt"</string> <string name="sort_spinner_recent" msgid="7513845273076525203">"Nylig"</string> - <string name="sort_by_app" msgid="4055799843051138087">"Sortér etter appbruk"</string> - <string name="sort_by_time" msgid="5435045320002150456">"Sortér etter tid"</string> + <string name="sort_by_app" msgid="4055799843051138087">"Sorter etter appbruk"</string> + <string name="sort_by_time" msgid="5435045320002150456">"Sorter etter tid"</string> <string name="item_separator" msgid="4030255389809224513">", "</string> <string name="permission_usage_refresh" msgid="2264056346561305420">"Last inn på nytt"</string> <string name="permission_history_title" msgid="8340081285133025225">"Tillatelseslogg"</string> diff --git a/PermissionController/res/values-ro-v33/strings.xml b/PermissionController/res/values-ro-v33/strings.xml index b96693674..fb3635eee 100644 --- a/PermissionController/res/values-ro-v33/strings.xml +++ b/PermissionController/res/values-ro-v33/strings.xml @@ -16,8 +16,8 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="role_dialer_request_description" msgid="6188305064871543419">"Aplicația va putea să vă trimită notificări și va avea acces la Camera foto, Agendă, Microfon, Telefon și SMS"</string> - <string name="role_sms_request_description" msgid="1506966389698625395">"Aplicația va putea să vă trimită notificări și va avea acces la Camera foto, Agendă, Fișiere, Microfon, Telefon și SMS"</string> + <string name="role_dialer_request_description" msgid="6188305064871543419">"Aplicația va putea să-ți trimită notificări și va avea acces la Camera foto, Agendă, Microfon, Telefon și SMS"</string> + <string name="role_sms_request_description" msgid="1506966389698625395">"Aplicația va putea să-ți trimită notificări și va avea acces la Camera foto, Agendă, Fișiere, Microfon, Telefon și SMS"</string> <string name="permission_description_summary_storage" msgid="1917071243213043858">"Aplicațiile cu această permisiune pot accesa toate fișierele de pe dispozitiv"</string> <string name="work_policy_title" msgid="832967780713677409">"Informații despre politica de serviciu"</string> <string name="work_policy_summary" msgid="3886113358084963931">"Setări gestionate de administratorul IT"</string> @@ -32,15 +32,15 @@ <string name="safety_center_issue_card_content_description" msgid="1281390769721765363">"Alertă. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>. <xliff:g id="ISSUE_CARD_SUMMARY">%2$s</xliff:g>"</string> <string name="safety_center_issue_card_content_description_with_subtitle" msgid="5504040663935313539">"Alertă. <xliff:g id="ISSUE_CARD_TITLE">%1$s</xliff:g>. <xliff:g id="ISSUE_CARD_SUBTITLE">%2$s</xliff:g>. <xliff:g id="ISSUE_CARD_SUMMARY">%3$s</xliff:g>"</string> <string name="safety_center_resolved_issue_fallback" msgid="8548932070610766651">"Acțiune încheiată"</string> - <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Verificați setările care pot spori protecția dispozitivului"</string> + <string name="safety_center_qs_status_summary" msgid="5193925895830451177">"Verifică setările care pot spori protecția dispozitivului"</string> <string name="safety_center_qs_page_landing" msgid="1717368301679228128">"Setări rapide privind securitatea și confidențialitatea"</string> <string name="safety_center_qs_close_button" msgid="1352313308176244599">"Închide"</string> <string name="safety_center_qs_expand_action" msgid="2193190557696484169">"Extinde și afișează opțiunile"</string> <string name="safety_center_qs_collapse_action" msgid="5809657430125309183">"Restrânge"</string> <string name="safety_center_qs_privacy_control" msgid="1160682635058529673">"Comutator. <xliff:g id="PRIVACY_CONTROL_TITLE">%1$s</xliff:g>. <xliff:g id="PRIVACY_CONTROL_STATUS">%2$s</xliff:g>"</string> - <string name="safety_center_qs_toggle_action" msgid="5920465736488119255">"Comutați"</string> + <string name="safety_center_qs_toggle_action" msgid="5920465736488119255">"Comută"</string> <string name="safety_center_qs_open_action" msgid="2760200829912423728">"Deschide"</string> - <string name="safety_center_review_settings_button" msgid="938981137942443930">"Examinați setările"</string> + <string name="safety_center_review_settings_button" msgid="938981137942443930">"Verifică setările"</string> <string name="safety_center_gear_label" msgid="5175877094379694098">"Setări"</string> <string name="safety_center_info_label" msgid="8993181584061825412">"Informații"</string> </resources> diff --git a/service/java/com/android/safetycenter/SafetyCenterConfigReader.java b/service/java/com/android/safetycenter/SafetyCenterConfigReader.java index c3e97400c..72dbae816 100644 --- a/service/java/com/android/safetycenter/SafetyCenterConfigReader.java +++ b/service/java/com/android/safetycenter/SafetyCenterConfigReader.java @@ -143,12 +143,12 @@ final class SafetyCenterConfigReader { return getCurrentConfigInternal().getExternalSafetySources().containsKey(safetySourceId); } - /** Returns whether the {@link SafetyCenterConfig} allows Westworld logging. */ - boolean allowsWestworldLogging() { + /** Returns whether the {@link SafetyCenterConfig} allows logging to statsd. */ + boolean allowsStatsdLogging() { if (!isOverrideForTestsActive()) { return true; } - return SafetyCenterFlags.getAllowWestworldLoggingInTests(); + return SafetyCenterFlags.getAllowStatsdLoggingInTests(); } /** diff --git a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java index 5c088b5d0..2e19c4e78 100644 --- a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java +++ b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java @@ -44,11 +44,9 @@ import android.safetycenter.config.SafetySourcesGroup; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; -import android.util.StatsEvent; import androidx.annotation.RequiresApi; -import com.android.permission.PermissionStatsLog; import com.android.safetycenter.internaldata.SafetyCenterEntryGroupId; import com.android.safetycenter.internaldata.SafetyCenterEntryId; import com.android.safetycenter.internaldata.SafetyCenterIds; @@ -87,7 +85,6 @@ final class SafetyCenterDataTracker { @NonNull private final SafetyCenterResourcesContext mSafetyCenterResourcesContext; @NonNull private final SafetyCenterConfigReader mSafetyCenterConfigReader; @NonNull private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker; - @NonNull private final WestworldLogger mWestworldLogger; @NonNull private final PendingIntentFactory mPendingIntentFactory; @NonNull private final SafetyCenterIssueCache mSafetyCenterIssueCache; @NonNull private final SafetyCenterRepository mSafetyCenterRepository; @@ -96,14 +93,12 @@ final class SafetyCenterDataTracker { @NonNull SafetyCenterResourcesContext safetyCenterResourcesContext, @NonNull SafetyCenterConfigReader safetyCenterConfigReader, @NonNull SafetyCenterRefreshTracker safetyCenterRefreshTracker, - @NonNull WestworldLogger westworldLogger, @NonNull PendingIntentFactory pendingIntentFactory, @NonNull SafetyCenterIssueCache safetyCenterIssueCache, @NonNull SafetyCenterRepository safetyCenterRepository) { mSafetyCenterResourcesContext = safetyCenterResourcesContext; mSafetyCenterConfigReader = safetyCenterConfigReader; mSafetyCenterRefreshTracker = safetyCenterRefreshTracker; - mWestworldLogger = westworldLogger; mPendingIntentFactory = pendingIntentFactory; mSafetyCenterIssueCache = safetyCenterIssueCache; mSafetyCenterRepository = safetyCenterRepository; @@ -137,104 +132,6 @@ final class SafetyCenterDataTracker { emptyList()); } - /** - * Pulls the {@link PermissionStatsLog#SAFETY_STATE} atom and writes all relevant {@link - * PermissionStatsLog#SAFETY_SOURCE_STATE_COLLECTED} atoms for the given {@link - * UserProfileGroup}. - */ - void pullAndWriteAtoms( - @NonNull UserProfileGroup userProfileGroup, @NonNull List<StatsEvent> statsEvents) { - pullOverallSafetyStateAtom(userProfileGroup, statsEvents); - // The SAFETY_SOURCE_STATE_COLLECTED atoms are written instead of being pulled, as they do - // not support pull. - writeSafetySourceStateCollectedAtoms(userProfileGroup); - } - - private void pullOverallSafetyStateAtom( - @NonNull UserProfileGroup userProfileGroup, @NonNull List<StatsEvent> statsEvents) { - SafetyCenterData safetyCenterData = getSafetyCenterData("android", userProfileGroup); - long openIssuesCount = safetyCenterData.getIssues().size(); - long dismissedIssuesCount = - mSafetyCenterIssueCache.countActiveIssues(userProfileGroup) - openIssuesCount; - - mWestworldLogger.pullSafetyStateEvent( - safetyCenterData.getStatus().getSeverityLevel(), - openIssuesCount, - dismissedIssuesCount, - statsEvents); - } - - private void writeSafetySourceStateCollectedAtoms(@NonNull UserProfileGroup userProfileGroup) { - List<SafetySourcesGroup> safetySourcesGroups = - mSafetyCenterConfigReader.getSafetySourcesGroups(); - for (int i = 0; i < safetySourcesGroups.size(); i++) { - SafetySourcesGroup safetySourcesGroup = safetySourcesGroups.get(i); - List<SafetySource> safetySources = safetySourcesGroup.getSafetySources(); - - for (int j = 0; j < safetySources.size(); j++) { - SafetySource safetySource = safetySources.get(j); - - if (!SafetySources.isExternal(safetySource) || !safetySource.isLoggingAllowed()) { - continue; - } - - writeSafetySourceStateCollectedAtom( - safetySource.getId(), userProfileGroup.getProfileParentUserId(), false); - - if (!SafetySources.supportsManagedProfiles(safetySource)) { - continue; - } - - int[] managedRunningProfilesUserIds = - userProfileGroup.getManagedRunningProfilesUserIds(); - for (int k = 0; k < managedRunningProfilesUserIds.length; k++) { - writeSafetySourceStateCollectedAtom( - safetySource.getId(), managedRunningProfilesUserIds[k], true); - } - } - } - } - - private void writeSafetySourceStateCollectedAtom( - @NonNull String safetySourceId, @UserIdInt int userId, boolean isUserManaged) { - SafetySourceKey key = SafetySourceKey.of(safetySourceId, userId); - SafetySourceData safetySourceData = mSafetyCenterRepository.getSafetySourceData(key); - SafetySourceStatus safetySourceStatus = getSafetySourceStatus(safetySourceData); - List<SafetySourceIssue> safetySourceIssues = - safetySourceData == null ? emptyList() : safetySourceData.getIssues(); - int maxSeverityLevel = Integer.MIN_VALUE; - long openIssuesCount = 0; - long dismissedIssuesCount = 0; - for (int i = 0; i < safetySourceIssues.size(); i++) { - SafetySourceIssue safetySourceIssue = safetySourceIssues.get(i); - SafetyCenterIssueKey safetyCenterIssueKey = - SafetyCenterIssueKey.newBuilder() - .setSafetySourceId(safetySourceId) - .setSafetySourceIssueId(safetySourceIssue.getId()) - .setUserId(userId) - .build(); - - if (mSafetyCenterIssueCache.isIssueDismissed( - safetyCenterIssueKey, safetySourceIssue.getSeverityLevel())) { - dismissedIssuesCount++; - } else { - openIssuesCount++; - maxSeverityLevel = Math.max(maxSeverityLevel, safetySourceIssue.getSeverityLevel()); - } - } - if (safetySourceStatus != null) { - maxSeverityLevel = Math.max(maxSeverityLevel, safetySourceStatus.getSeverityLevel()); - } - Integer maxSeverityOrNull = maxSeverityLevel > Integer.MIN_VALUE ? maxSeverityLevel : null; - - mWestworldLogger.writeSafetySourceStateCollected( - safetySourceId, - isUserManaged, - maxSeverityOrNull, - openIssuesCount, - dismissedIssuesCount); - } - @NonNull private SafetyCenterData getSafetyCenterData( @NonNull List<SafetySourcesGroup> safetySourcesGroups, diff --git a/service/java/com/android/safetycenter/SafetyCenterFlags.java b/service/java/com/android/safetycenter/SafetyCenterFlags.java index 124b8cd8f..e213825de 100644 --- a/service/java/com/android/safetycenter/SafetyCenterFlags.java +++ b/service/java/com/android/safetycenter/SafetyCenterFlags.java @@ -71,8 +71,8 @@ final class SafetyCenterFlags { private static final String PROPERTY_ISSUE_CATEGORY_ALLOWLISTS = "safety_center_issue_category_allowlists"; - private static final String PROPERTY_ALLOW_WESTWORLD_LOGGING_IN_TESTS = - "safety_center_allow_westworld_logging_in_tests"; + private static final String PROPERTY_ALLOW_STATSD_LOGGING_IN_TESTS = + "safety_center_allow_statsd_logging_in_tests"; private static final Duration REFRESH_SOURCES_TIMEOUT_DEFAULT_DURATION = Duration.ofSeconds(15); @@ -103,8 +103,7 @@ final class SafetyCenterFlags { printFlag( fout, PROPERTY_REFRESH_SOURCES_TIMEOUTS_MILLIS, getRefreshSourcesTimeoutsMillis()); printFlag(fout, PROPERTY_ISSUE_CATEGORY_ALLOWLISTS, getIssueCategoryAllowlists()); - printFlag( - fout, PROPERTY_ALLOW_WESTWORLD_LOGGING_IN_TESTS, getAllowWestworldLoggingInTests()); + printFlag(fout, PROPERTY_ALLOW_STATSD_LOGGING_IN_TESTS, getAllowStatsdLoggingInTests()); fout.println(); } @@ -280,9 +279,9 @@ final class SafetyCenterFlags { return getString(PROPERTY_ISSUE_CATEGORY_ALLOWLISTS, ""); } - /** Returns whether we allow Westworld logging in tests. */ - static boolean getAllowWestworldLoggingInTests() { - return getBoolean(PROPERTY_ALLOW_WESTWORLD_LOGGING_IN_TESTS, false); + /** Returns whether we allow statsd logging in tests. */ + static boolean getAllowStatsdLoggingInTests() { + return getBoolean(PROPERTY_ALLOW_STATSD_LOGGING_IN_TESTS, false); } @NonNull diff --git a/service/java/com/android/safetycenter/SafetyCenterPullAtomCallback.java b/service/java/com/android/safetycenter/SafetyCenterPullAtomCallback.java new file mode 100644 index 000000000..02ba90015 --- /dev/null +++ b/service/java/com/android/safetycenter/SafetyCenterPullAtomCallback.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.safetycenter; + +import static android.os.Build.VERSION_CODES.TIRAMISU; + +import static com.android.permission.PermissionStatsLog.SAFETY_STATE; + +import static java.util.Collections.emptyList; + +import android.annotation.NonNull; +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; +import android.util.StatsEvent; + +import androidx.annotation.RequiresApi; + +import com.android.internal.annotations.GuardedBy; +import com.android.permission.PermissionStatsLog; +import com.android.safetycenter.internaldata.SafetyCenterIssueKey; + +import java.util.List; + +/** + * A {@link StatsPullAtomCallback} that provides a {@link PermissionStatsLog#SAFETY_STATE} atom that + * when requested by the {@link StatsManager}. + * + * <p>Whenever that atom, which describes the overall Safety Center, is pulled this class also + * separately writes one {@code SAFETY_SOURCE_STATE_COLLECTED} atom for each active source (per + * profile). + */ +@RequiresApi(TIRAMISU) +final class SafetyCenterPullAtomCallback implements StatsPullAtomCallback { + + private static final String TAG = "SafetyCenterPullAtomCal"; + + @NonNull private final Context mContext; + @NonNull private final Object mApiLock; + + @GuardedBy("mApiLock") + @NonNull + private final StatsdLogger mStatsdLogger; + + @GuardedBy("mApiLock") + @NonNull + private final SafetyCenterConfigReader mSafetyCenterConfigReader; + + @GuardedBy("mApiLock") + @NonNull + private final SafetyCenterRepository mSafetyCenterRepository; + + @GuardedBy("mApiLock") + @NonNull + private final SafetyCenterDataTracker mSafetyCenterDataTracker; + + @GuardedBy("mApiLock") + @NonNull + private final SafetyCenterIssueCache mSafetyCenterIssueCache; + + SafetyCenterPullAtomCallback( + @NonNull Context context, + @NonNull Object apiLock, + @NonNull StatsdLogger statsdLogger, + @NonNull SafetyCenterConfigReader safetyCenterConfigReader, + @NonNull SafetyCenterRepository safetyCenterRepository, + @NonNull SafetyCenterDataTracker safetyCenterDataTracker, + @NonNull SafetyCenterIssueCache safetyCenterIssueCache) { + mContext = context; + mApiLock = apiLock; + mStatsdLogger = statsdLogger; + mSafetyCenterConfigReader = safetyCenterConfigReader; + mSafetyCenterRepository = safetyCenterRepository; + mSafetyCenterDataTracker = safetyCenterDataTracker; + mSafetyCenterIssueCache = safetyCenterIssueCache; + } + + @Override + public int onPullAtom(int atomTag, @NonNull List<StatsEvent> statsEvents) { + if (atomTag != SAFETY_STATE) { + Log.w(TAG, "Attempt to pull atom: " + atomTag + ", but only SAFETY_STATE is supported"); + return StatsManager.PULL_SKIP; + } + if (!SafetyCenterFlags.getSafetyCenterEnabled()) { + Log.w(TAG, "Attempt to pull SAFETY_STATE, but Safety Center is disabled"); + return StatsManager.PULL_SKIP; + } + List<UserProfileGroup> userProfileGroups = + UserProfileGroup.getAllUserProfileGroups(mContext); + synchronized (mApiLock) { + if (!mSafetyCenterConfigReader.allowsStatsdLogging()) { + Log.w(TAG, "Skipping pulling and writing atoms due to a test config override"); + return StatsManager.PULL_SKIP; + } + Log.i(TAG, "Pulling and writing atoms…"); + for (int i = 0; i < userProfileGroups.size(); i++) { + UserProfileGroup userProfileGroup = userProfileGroups.get(i); + statsEvents.add(createOverallSafetyStateAtomLocked(userProfileGroup)); + // The SAFETY_SOURCE_STATE_COLLECTED atoms are written instead of being pulled, + // they do not support pull but we want to collect them at the same time as + // the above pulled atom. + writeSafetySourceStateCollectedAtomsLocked(userProfileGroup); + } + } + return StatsManager.PULL_SUCCESS; + } + + @GuardedBy("mApiLock") + @NonNull + private StatsEvent createOverallSafetyStateAtomLocked( + @NonNull UserProfileGroup userProfileGroup) { + // TODO: We could make SafetyCenterPullAtomCallback a SafetyCenterListener and hold a + // reference to the last SafetyCenterData so we don't need to recalculate that here. + SafetyCenterData safetyCenterData = + mSafetyCenterDataTracker.getSafetyCenterData("android", userProfileGroup); + long openIssuesCount = safetyCenterData.getIssues().size(); + long dismissedIssuesCount = + mSafetyCenterIssueCache.countActiveIssues(userProfileGroup) - openIssuesCount; + + return mStatsdLogger.createSafetyStateEvent( + safetyCenterData.getStatus().getSeverityLevel(), + openIssuesCount, + dismissedIssuesCount); + } + + @GuardedBy("mApiLock") + private void writeSafetySourceStateCollectedAtomsLocked( + @NonNull UserProfileGroup userProfileGroup) { + List<SafetySourcesGroup> safetySourcesGroups = + mSafetyCenterConfigReader.getSafetySourcesGroups(); + for (int i = 0; i < safetySourcesGroups.size(); i++) { + SafetySourcesGroup safetySourcesGroup = safetySourcesGroups.get(i); + List<SafetySource> safetySources = safetySourcesGroup.getSafetySources(); + + for (int j = 0; j < safetySources.size(); j++) { + SafetySource safetySource = safetySources.get(j); + + if (!SafetySources.isExternal(safetySource) || !safetySource.isLoggingAllowed()) { + continue; + } + + writeSafetySourceStateCollectedAtomLocked( + safetySource.getId(), userProfileGroup.getProfileParentUserId(), false); + + if (!SafetySources.supportsManagedProfiles(safetySource)) { + continue; + } + + int[] managedRunningProfilesUserIds = + userProfileGroup.getManagedRunningProfilesUserIds(); + for (int k = 0; k < managedRunningProfilesUserIds.length; k++) { + writeSafetySourceStateCollectedAtomLocked( + safetySource.getId(), managedRunningProfilesUserIds[k], true); + } + } + } + } + + @GuardedBy("mApiLock") + private void writeSafetySourceStateCollectedAtomLocked( + @NonNull String safetySourceId, @UserIdInt int userId, boolean isUserManaged) { + SafetySourceKey key = SafetySourceKey.of(safetySourceId, userId); + SafetySourceData safetySourceData = mSafetyCenterRepository.getSafetySourceData(key); + SafetySourceStatus safetySourceStatus = + safetySourceData == null ? null : safetySourceData.getStatus(); + List<SafetySourceIssue> safetySourceIssues = + safetySourceData == null ? emptyList() : safetySourceData.getIssues(); + int maxSeverityLevel = Integer.MIN_VALUE; + long openIssuesCount = 0; + long dismissedIssuesCount = 0; + for (int i = 0; i < safetySourceIssues.size(); i++) { + SafetySourceIssue safetySourceIssue = safetySourceIssues.get(i); + SafetyCenterIssueKey safetyCenterIssueKey = + SafetyCenterIssueKey.newBuilder() + .setSafetySourceId(safetySourceId) + .setSafetySourceIssueId(safetySourceIssue.getId()) + .setUserId(userId) + .build(); + + if (mSafetyCenterIssueCache.isIssueDismissed( + safetyCenterIssueKey, safetySourceIssue.getSeverityLevel())) { + dismissedIssuesCount++; + } else { + openIssuesCount++; + maxSeverityLevel = Math.max(maxSeverityLevel, safetySourceIssue.getSeverityLevel()); + } + } + if (safetySourceStatus != null) { + maxSeverityLevel = Math.max(maxSeverityLevel, safetySourceStatus.getSeverityLevel()); + } + Integer maxSeverityOrNull = maxSeverityLevel > Integer.MIN_VALUE ? maxSeverityLevel : null; + + mStatsdLogger.writeSafetySourceStateCollected( + safetySourceId, + isUserManaged, + maxSeverityOrNull, + openIssuesCount, + dismissedIssuesCount); + } +} diff --git a/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java b/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java index e88a52a7f..7cf538b6e 100644 --- a/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java +++ b/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java @@ -20,7 +20,7 @@ import static android.os.Build.VERSION_CODES.TIRAMISU; import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLICK; import static com.android.permission.PermissionStatsLog.SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT; -import static com.android.safetycenter.WestworldLogger.toSystemEventResult; +import static com.android.safetycenter.StatsdLogger.toSystemEventResult; import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; @@ -60,10 +60,10 @@ final class SafetyCenterRefreshTracker { private int mRefreshCounter = 0; - @NonNull private final WestworldLogger mWestworldLogger; + @NonNull private final StatsdLogger mStatsdLogger; - SafetyCenterRefreshTracker(@NonNull WestworldLogger westworldLogger) { - mWestworldLogger = westworldLogger; + SafetyCenterRefreshTracker(@NonNull StatsdLogger statsdLogger) { + mStatsdLogger = statsdLogger; } /** @@ -135,7 +135,7 @@ final class SafetyCenterRefreshTracker { * the refresh as completed. The {@code successful} parameter indicates whether the refresh * completed successfully or not. * - * <p>Completed refreshes are tracked in Westworld. + * <p>Completed refreshes are logged to statsd. */ boolean reportSourceRefreshCompleted( @NonNull String refreshBroadcastId, @@ -152,7 +152,7 @@ final class SafetyCenterRefreshTracker { if (duration != null) { int sourceResult = toSystemEventResult(successful); - mWestworldLogger.writeSourceRefreshSystemEvent( + mStatsdLogger.writeSourceRefreshSystemEvent( requestType, sourceId, userId, duration, sourceResult); } @@ -162,7 +162,7 @@ final class SafetyCenterRefreshTracker { Log.v(TAG, "Refresh with id: " + mRefreshInProgress.getId() + " completed"); int wholeResult = toSystemEventResult(mRefreshInProgress.hasAnyTrackedSourceErrors()); - mWestworldLogger.writeWholeRefreshSystemEvent( + mStatsdLogger.writeWholeRefreshSystemEvent( requestType, mRefreshInProgress.getDurationSinceStart(), wholeResult); mRefreshInProgress = null; return true; @@ -240,7 +240,7 @@ final class SafetyCenterRefreshTracker { SafetySourceKey sourceKey = timedOutSources.valueAt(i); Duration duration = clearedRefresh.getDurationSinceSourceStart(sourceKey); if (duration != null) { - mWestworldLogger.writeSourceRefreshSystemEvent( + mStatsdLogger.writeSourceRefreshSystemEvent( requestType, sourceKey.getSourceId(), sourceKey.getUserId(), @@ -249,7 +249,7 @@ final class SafetyCenterRefreshTracker { } } - mWestworldLogger.writeWholeRefreshSystemEvent( + mStatsdLogger.writeWholeRefreshSystemEvent( requestType, clearedRefresh.getDurationSinceStart(), SAFETY_CENTER_SYSTEM_EVENT_REPORTED__RESULT__TIMEOUT); diff --git a/service/java/com/android/safetycenter/SafetyCenterRepository.java b/service/java/com/android/safetycenter/SafetyCenterRepository.java index 9821dc218..cb9ee977d 100644 --- a/service/java/com/android/safetycenter/SafetyCenterRepository.java +++ b/service/java/com/android/safetycenter/SafetyCenterRepository.java @@ -18,7 +18,7 @@ package com.android.safetycenter; import static android.os.Build.VERSION_CODES.TIRAMISU; -import static com.android.safetycenter.WestworldLogger.toSystemEventResult; +import static com.android.safetycenter.StatsdLogger.toSystemEventResult; import static com.android.safetycenter.internaldata.SafetyCenterIds.toUserFriendlyString; import android.annotation.NonNull; @@ -74,19 +74,19 @@ final class SafetyCenterRepository { @NonNull private final Context mContext; @NonNull private final SafetyCenterConfigReader mSafetyCenterConfigReader; @NonNull private final SafetyCenterRefreshTracker mSafetyCenterRefreshTracker; - @NonNull private final WestworldLogger mWestworldLogger; + @NonNull private final StatsdLogger mStatsdLogger; @NonNull private final SafetyCenterIssueCache mSafetyCenterIssueCache; SafetyCenterRepository( @NonNull Context context, @NonNull SafetyCenterConfigReader safetyCenterConfigReader, @NonNull SafetyCenterRefreshTracker safetyCenterRefreshTracker, - @NonNull WestworldLogger westworldLogger, + @NonNull StatsdLogger statsdLogger, @NonNull SafetyCenterIssueCache safetyCenterIssueCache) { mContext = context; mSafetyCenterConfigReader = safetyCenterConfigReader; mSafetyCenterRefreshTracker = safetyCenterRefreshTracker; - mWestworldLogger = westworldLogger; + mStatsdLogger = statsdLogger; mSafetyCenterIssueCache = safetyCenterIssueCache; } @@ -233,13 +233,13 @@ final class SafetyCenterRepository { } /** - * Unmarks the given {@link SafetyCenterIssueActionId} as in-flight, logs that event to - * Westworld with the given {@code result} value, and returns {@code true} if the underlying - * {@link SafetyCenterData} changed. + * Unmarks the given {@link SafetyCenterIssueActionId} as in-flight, logs that event to statsd + * with the given {@code result} value, and returns {@code true} if the underlying {@link + * SafetyCenterData} changed. */ boolean unmarkSafetyCenterIssueActionInFlight( @NonNull SafetyCenterIssueActionId safetyCenterIssueActionId, - @WestworldLogger.SystemEventResult int result) { + @StatsdLogger.SystemEventResult int result) { Long startElapsedMillis = mSafetyCenterIssueActionsInFlight.remove(safetyCenterIssueActionId); if (startElapsedMillis == null) { @@ -255,7 +255,7 @@ final class SafetyCenterRepository { String issueTypeId = issue == null ? null : issue.getIssueTypeId(); Duration duration = Duration.ofMillis(SystemClock.elapsedRealtime() - startElapsedMillis); - mWestworldLogger.writeInlineActionSystemEvent( + mStatsdLogger.writeInlineActionSystemEvent( issueKey.getSafetySourceId(), issueKey.getUserId(), issueTypeId, duration, result); if (issue == null || getSafetySourceIssueAction(safetyCenterIssueActionId) == null) { @@ -413,10 +413,10 @@ final class SafetyCenterRepository { int actionInFlightCount = mSafetyCenterIssueActionsInFlight.size(); fout.println("ACTIONS IN FLIGHT (" + actionInFlightCount + ")"); for (int i = 0; i < actionInFlightCount; i++) { - SafetyCenterIssueActionId id = mSafetyCenterIssueActionsInFlight.keyAt(i); + String printableId = toUserFriendlyString(mSafetyCenterIssueActionsInFlight.keyAt(i)); long startElapsedMillis = mSafetyCenterIssueActionsInFlight.valueAt(i); long durationMillis = SystemClock.elapsedRealtime() - startElapsedMillis; - fout.println("\t[" + i + "] " + id + "(duration=" + durationMillis + "ms)"); + fout.println("\t[" + i + "] " + printableId + "(duration=" + durationMillis + "ms)"); } fout.println(); } diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java index 99aab2ba5..3cca78270 100644 --- a/service/java/com/android/safetycenter/SafetyCenterService.java +++ b/service/java/com/android/safetycenter/SafetyCenterService.java @@ -40,7 +40,6 @@ import android.app.ActivityOptions; import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.StatsManager; -import android.app.StatsManager.PullAtomMetadata; import android.app.StatsManager.StatsPullAtomCallback; import android.content.ApexEnvironment; import android.content.BroadcastReceiver; @@ -66,14 +65,12 @@ import android.safetycenter.SafetySourceIssue; import android.safetycenter.config.SafetyCenterConfig; import android.util.ArraySet; import android.util.Log; -import android.util.StatsEvent; import androidx.annotation.Keep; import androidx.annotation.RequiresApi; import com.android.internal.annotations.GuardedBy; import com.android.modules.utils.BackgroundThread; -import com.android.permission.PermissionStatsLog; import com.android.permission.util.ForegroundThread; import com.android.permission.util.UserUtils; import com.android.safetycenter.internaldata.SafetyCenterIds; @@ -165,6 +162,7 @@ public final class SafetyCenterService extends SystemService { @NonNull private final SafetyCenterBroadcastDispatcher mSafetyCenterBroadcastDispatcher; + @NonNull private final StatsPullAtomCallback mPullAtomCallback; @NonNull private final AppOpsManager mAppOpsManager; private final boolean mDeviceSupportsSafetyCenter; @@ -175,22 +173,21 @@ public final class SafetyCenterService extends SystemService { super(context); mSafetyCenterResourcesContext = new SafetyCenterResourcesContext(context); mSafetyCenterConfigReader = new SafetyCenterConfigReader(mSafetyCenterResourcesContext); - WestworldLogger westworldLogger = new WestworldLogger(context, mSafetyCenterConfigReader); - mSafetyCenterRefreshTracker = new SafetyCenterRefreshTracker(westworldLogger); + StatsdLogger statsdLogger = new StatsdLogger(context, mSafetyCenterConfigReader); + mSafetyCenterRefreshTracker = new SafetyCenterRefreshTracker(statsdLogger); mSafetyCenterIssueCache = new SafetyCenterIssueCache(mSafetyCenterConfigReader); mSafetyCenterRepository = new SafetyCenterRepository( context, mSafetyCenterConfigReader, mSafetyCenterRefreshTracker, - westworldLogger, + statsdLogger, mSafetyCenterIssueCache); mSafetyCenterDataTracker = new SafetyCenterDataTracker( mSafetyCenterResourcesContext, mSafetyCenterConfigReader, mSafetyCenterRefreshTracker, - westworldLogger, new PendingIntentFactory(context), mSafetyCenterIssueCache, mSafetyCenterRepository); @@ -198,6 +195,15 @@ public final class SafetyCenterService extends SystemService { mSafetyCenterBroadcastDispatcher = new SafetyCenterBroadcastDispatcher( context, mSafetyCenterConfigReader, mSafetyCenterRefreshTracker); + mPullAtomCallback = + new SafetyCenterPullAtomCallback( + context, + mApiLock, + statsdLogger, + mSafetyCenterConfigReader, + mSafetyCenterRepository, + mSafetyCenterDataTracker, + mSafetyCenterIssueCache); mAppOpsManager = requireNonNull(context.getSystemService(AppOpsManager.class)); mDeviceSupportsSafetyCenter = context.getResources() @@ -241,12 +247,8 @@ public final class SafetyCenterService extends SystemService { private void registerSafetyCenterPullAtomCallback() { StatsManager statsManager = requireNonNull(getContext().getSystemService(StatsManager.class)); - PullAtomMetadata defaultMetadata = null; statsManager.setPullAtomCallback( - SAFETY_STATE, - defaultMetadata, - BackgroundThread.getExecutor(), - new SafetyCenterPullAtomCallback()); + SAFETY_STATE, null, BackgroundThread.getExecutor(), mPullAtomCallback); } /** Service implementation of {@link ISafetyCenterManager.Stub}. */ @@ -824,45 +826,6 @@ public final class SafetyCenterService extends SystemService { } } - /** - * A {@link StatsPullAtomCallback} that provides data for {@link - * PermissionStatsLog#SAFETY_STATE} when called by the {@link StatsManager}. - */ - private final class SafetyCenterPullAtomCallback implements StatsPullAtomCallback { - - private SafetyCenterPullAtomCallback() {} - - @Override - public int onPullAtom(int atomTag, @NonNull List<StatsEvent> statsEvents) { - if (atomTag != SAFETY_STATE) { - Log.w( - TAG, - "Attempt to pull atom: " - + atomTag - + ", but only SAFETY_STATE is supported"); - return StatsManager.PULL_SKIP; - } - if (!SafetyCenterFlags.getSafetyCenterEnabled()) { - Log.w(TAG, "Attempt to pull SAFETY_STATE, but Safety Center is disabled"); - return StatsManager.PULL_SKIP; - } - List<UserProfileGroup> userProfileGroups = - UserProfileGroup.getAllUserProfileGroups(getContext()); - synchronized (mApiLock) { - if (!mSafetyCenterConfigReader.allowsWestworldLogging()) { - Log.w(TAG, "Skipping pulling and writing atoms due to a test config override"); - return StatsManager.PULL_SKIP; - } - Log.i(TAG, "Pulling and writing atoms…"); - for (int i = 0; i < userProfileGroups.size(); i++) { - mSafetyCenterDataTracker.pullAndWriteAtoms( - userProfileGroups.get(i), statsEvents); - } - } - return StatsManager.PULL_SUCCESS; - } - } - /** A {@link Runnable} that is called to signal a refresh timeout. */ private final class RefreshTimeout implements Runnable { diff --git a/service/java/com/android/safetycenter/WestworldLogger.java b/service/java/com/android/safetycenter/StatsdLogger.java index 7c3cd57ad..e62983c97 100644 --- a/service/java/com/android/safetycenter/WestworldLogger.java +++ b/service/java/com/android/safetycenter/StatsdLogger.java @@ -47,6 +47,7 @@ import static com.android.permission.PermissionStatsLog.SAFETY_STATE__OVERALL_SE import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.safetycenter.SafetyCenterManager; @@ -56,7 +57,6 @@ import android.safetycenter.SafetySourceData; import android.util.Log; import android.util.StatsEvent; -import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.android.permission.PermissionStatsLog; @@ -68,21 +68,20 @@ import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.time.Duration; -import java.util.List; import javax.annotation.concurrent.NotThreadSafe; /** - * Marshalls and writes atoms to Westworld. Contains implementation details of how atom parameters - * are encoded and provides a better-typed interface for other classes to call. + * Marshalls and writes statsd atoms. Contains implementation details of how atom parameters are + * encoded and provides a better-typed interface for other classes to call. * * <p>This class isn't thread safe. Thread safety must be handled by the caller. */ @RequiresApi(TIRAMISU) @NotThreadSafe -final class WestworldLogger { +final class StatsdLogger { - private static final String TAG = "WestworldLogger"; + private static final String TAG = "StatsdLogger"; private static final long UNSET_SOURCE_ID = 0; private static final long UNSET_ISSUE_TYPE_ID = 0; @@ -99,31 +98,26 @@ final class WestworldLogger { @NonNull private final Context mContext; @NonNull private final SafetyCenterConfigReader mSafetyCenterConfigReader; - WestworldLogger( + StatsdLogger( @NonNull Context context, @NonNull SafetyCenterConfigReader safetyCenterConfigReader) { mContext = context; mSafetyCenterConfigReader = safetyCenterConfigReader; } /** - * Pulls a {@link PermissionStatsLog#SAFETY_STATE} {@link StatsEvent} with the given parameters - * into {@code statsEvents}. + * Creates a {@link PermissionStatsLog#SAFETY_STATE} {@link StatsEvent} with the given + * parameters. */ - void pullSafetyStateEvent( + @NonNull + StatsEvent createSafetyStateEvent( @SafetyCenterStatus.OverallSeverityLevel int severityLevel, long openIssueCount, - long dismissedIssueCount, - @NonNull List<StatsEvent> statsEvents) { - if (!mSafetyCenterConfigReader.allowsWestworldLogging()) { - return; - } - StatsEvent safetyStateEvent = - PermissionStatsLog.buildStatsEvent( - SAFETY_STATE, - toSafetyStateOverallSeverityLevel(severityLevel), - openIssueCount, - dismissedIssueCount); - statsEvents.add(safetyStateEvent); + long dismissedIssueCount) { + return PermissionStatsLog.buildStatsEvent( + SAFETY_STATE, + toSafetyStateOverallSeverityLevel(severityLevel), + openIssueCount, + dismissedIssueCount); } /** @@ -138,7 +132,7 @@ final class WestworldLogger { @Nullable @SafetySourceData.SeverityLevel Integer sourceSeverityLevel, long openIssuesCount, long dismissedIssuesCount) { - if (!mSafetyCenterConfigReader.allowsWestworldLogging()) { + if (!mSafetyCenterConfigReader.allowsStatsdLogging()) { return; } int profileType = @@ -164,7 +158,7 @@ final class WestworldLogger { @UserIdInt int userId, @NonNull Duration duration, @SystemEventResult int result) { - if (!mSafetyCenterConfigReader.allowsWestworldLogging()) { + if (!mSafetyCenterConfigReader.allowsStatsdLogging()) { return; } PermissionStatsLog.write( @@ -185,7 +179,7 @@ final class WestworldLogger { @RefreshRequestType int refreshType, @NonNull Duration duration, @SystemEventResult int result) { - if (!mSafetyCenterConfigReader.allowsWestworldLogging()) { + if (!mSafetyCenterConfigReader.allowsStatsdLogging()) { return; } PermissionStatsLog.write( @@ -208,7 +202,7 @@ final class WestworldLogger { @Nullable String issueTypeId, @NonNull Duration duration, @SystemEventResult int result) { - if (!mSafetyCenterConfigReader.allowsWestworldLogging()) { + if (!mSafetyCenterConfigReader.allowsStatsdLogging()) { return; } PermissionStatsLog.write( @@ -262,7 +256,7 @@ final class WestworldLogger { /** * Converts a {@link String} ID (e.g. a Safety Source ID) to a {@code long} suitable for logging - * to Westworld. + * to statsd. */ private static long idStringToLong(@NonNull String id) { MessageDigest messageDigest; diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt index 15bbf6eac..f91cd3312 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/testing/SafetyCenterFlags.kt @@ -141,14 +141,13 @@ object SafetyCenterFlags { SetParser(StringParser())) /** - * Flag that determines whether Westworld logging is allowed in tests. + * Flag that determines whether statsd logging is allowed in tests. * - * This is useful to allow testing Westworld logs in some specific tests, while keeping the - * other tests from polluting our Westworld logs. + * This is useful to allow testing statsd logs in some specific tests, while keeping the other + * tests from polluting our statsd logs. */ - private val allowWestworldLoggingInTestsFlag = - Flag( - "safety_center_allow_westworld_logging_in_tests", defaultValue = false, BooleanParser()) + private val allowStatsdLoggingInTestsFlag = + Flag("safety_center_allow_statsd_logging_in_tests", defaultValue = false, BooleanParser()) /** * The Package Manager flag used while toggling the QS tile component. @@ -176,7 +175,7 @@ object SafetyCenterFlags { resurfaceIssueDelaysFlag, issueCategoryAllowlistsFlag, backgroundRefreshDeniedSourcesFlag, - allowWestworldLoggingInTestsFlag, + allowStatsdLoggingInTestsFlag, qsTileComponentSettingFlag) /** Returns whether the device supports Safety Center. */ @@ -217,8 +216,8 @@ object SafetyCenterFlags { /** A property that allows getting and setting the [backgroundRefreshDeniedSourcesFlag]. */ var backgroundRefreshDeniedSources: Set<String> by backgroundRefreshDeniedSourcesFlag - /** A property that allows getting and setting the [allowWestworldLoggingInTestsFlag]. */ - var allowWestworldLoggingInTests: Boolean by allowWestworldLoggingInTestsFlag + /** A property that allows getting and setting the [allowStatsdLoggingInTestsFlag]. */ + var allowStatsdLoggingInTests: Boolean by allowStatsdLoggingInTestsFlag /** * Returns a snapshot of all the Safety Center flags. |