diff options
5 files changed, 168 insertions, 157 deletions
diff --git a/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java b/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java index 850d896b3..1690f4aee 100644 --- a/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java +++ b/service/java/com/android/safetycenter/SafetyCenterBroadcastDispatcher.java @@ -43,7 +43,6 @@ import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.UserHandle; -import android.provider.DeviceConfig; import android.safetycenter.SafetyCenterManager; import android.safetycenter.SafetyCenterManager.RefreshReason; import android.safetycenter.SafetyCenterManager.RefreshRequestType; @@ -63,22 +62,6 @@ import java.util.List; @RequiresApi(TIRAMISU) final class SafetyCenterBroadcastDispatcher { - private static final String TAG = "SafetyCenterBroadcastDi"; - - /** - * Device Config flag that determines the time for which an app, upon receiving a Safety Center - * refresh broadcast, will be placed on a temporary power allowlist allowing it to start a - * foreground service from the background. - */ - private static final String PROPERTY_FGS_ALLOWLIST_DURATION_MILLIS = - "safety_center_refresh_fgs_allowlist_duration_millis"; - - /** - * Default time for which an app, upon receiving a particular broadcast, will be placed on a - * temporary power allowlist allowing it to start a foreground service from the background. - */ - private static final Duration FGS_ALLOWLIST_DEFAULT_DURATION = Duration.ofSeconds(20); - @NonNull private final Context mContext; /** Creates a {@link SafetyCenterBroadcastDispatcher} using the given {@link Context}. */ @@ -261,12 +244,12 @@ final class SafetyCenterBroadcastDispatcher { @NonNull private static BroadcastOptions createBroadcastOptions() { BroadcastOptions broadcastOptions = BroadcastOptions.makeBasic(); - // The following operation requires the START_FOREGROUND_SERVICES_FROM_BACKGROUND - // and READ_DEVICE_CONFIG permissions. + Duration allowListDuration = SafetyCenterFlags.getFgsAllowlistDuration(); + // The following operation requires the START_FOREGROUND_SERVICES_FROM_BACKGROUND. final long callingId = Binder.clearCallingIdentity(); try { broadcastOptions.setTemporaryAppAllowlist( - getFgsAllowlistDuration().toMillis(), + allowListDuration.toMillis(), TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, REASON_REFRESH_SAFETY_SOURCES, "Safety Center is requesting data from safety sources"); @@ -290,16 +273,4 @@ final class SafetyCenterBroadcastDispatcher { } throw new IllegalArgumentException("Unexpected refresh reason: " + refreshReason); } - - /** - * Returns the time for which an app, upon receiving a particular broadcast, should be placed on - * a temporary power allowlist allowing it to start a foreground service from the background. - */ - private static Duration getFgsAllowlistDuration() { - return Duration.ofMillis( - DeviceConfig.getLong( - DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_FGS_ALLOWLIST_DURATION_MILLIS, - FGS_ALLOWLIST_DEFAULT_DURATION.toMillis())); - } } diff --git a/service/java/com/android/safetycenter/SafetyCenterFlags.java b/service/java/com/android/safetycenter/SafetyCenterFlags.java new file mode 100644 index 000000000..2c81ba528 --- /dev/null +++ b/service/java/com/android/safetycenter/SafetyCenterFlags.java @@ -0,0 +1,146 @@ +/* + * 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 android.annotation.NonNull; +import android.os.Binder; +import android.provider.DeviceConfig; +import android.util.ArraySet; + +import androidx.annotation.RequiresApi; + +import java.time.Duration; + +/** A class to access the Safety Center {@link DeviceConfig} flags. */ +@RequiresApi(TIRAMISU) +final class SafetyCenterFlags { + + /** {@link DeviceConfig} property name for {@link #getSafetyCenterEnabled()}. */ + static final String PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"; + + private static final String PROPERTY_SHOW_ERROR_ENTRIES_ON_TIMEOUT = + "show_error_entries_on_timeout"; + + private static final String PROPERTY_REFRESH_SOURCE_TIMEOUT_MILLIS = + "safety_center_refresh_source_timeout_millis"; + + private static final String PROPERTY_RESOLVING_ACTION_TIMEOUT_MILLIS = + "safety_center_resolve_action_timeout_millis"; + + private static final String PROPERTY_FGS_ALLOWLIST_DURATION_MILLIS = + "safety_center_refresh_fgs_allowlist_duration_millis"; + + private static final String PROPERTY_UNTRACKED_SOURCES = "safety_center_untracked_sources"; + + private static final Duration REFRESH_SOURCE_TIMEOUT_DEFAULT_DURATION = Duration.ofSeconds(10); + + private static final Duration RESOLVING_ACTION_TIMEOUT_DEFAULT_DURATION = + Duration.ofSeconds(10); + + private static final Duration FGS_ALLOWLIST_DEFAULT_DURATION = Duration.ofSeconds(20); + + /** Returns whether Safety Center is enabled. */ + static boolean getSafetyCenterEnabled() { + return getBoolean(PROPERTY_SAFETY_CENTER_ENABLED, false); + } + + /** + * Returns whether we should show error entries for sources that timeout when refreshing them. + */ + static boolean getShowErrorEntriesOnTimeout() { + return getBoolean(PROPERTY_SHOW_ERROR_ENTRIES_ON_TIMEOUT, false); + } + + /** + * Returns the time for which a Safety Center refresh is allowed to wait for a source to respond + * to a refresh request before timing out and marking the refresh as completed. + */ + static Duration getRefreshTimeout() { + return getDuration( + PROPERTY_REFRESH_SOURCE_TIMEOUT_MILLIS, REFRESH_SOURCE_TIMEOUT_DEFAULT_DURATION); + } + + /** + * Returns the time for which Safety Center will wait for a source to respond to a resolving + * action before timing out. + */ + static Duration getResolvingActionTimeout() { + return getDuration( + PROPERTY_RESOLVING_ACTION_TIMEOUT_MILLIS, + RESOLVING_ACTION_TIMEOUT_DEFAULT_DURATION); + } + + /** + * Returns the time for which an app, upon receiving a Safety Center refresh broadcast, will be + * placed on a temporary power allowlist allowing it to start a foreground service from the + * background. + */ + static Duration getFgsAllowlistDuration() { + return getDuration(PROPERTY_FGS_ALLOWLIST_DURATION_MILLIS, FGS_ALLOWLIST_DEFAULT_DURATION); + } + + /** + * Returns the IDs of sources that should not be tracked, for example because they are + * mid-rollout. Broadcasts are still sent to these sources. + */ + @NonNull + static ArraySet<String> getUntrackedSourceIds() { + String untrackedSourcesConfigString = getString(PROPERTY_UNTRACKED_SOURCES, ""); + String[] untrackedSourcesList = untrackedSourcesConfigString.split(","); + return new ArraySet<>(untrackedSourcesList); + } + + @NonNull + private static Duration getDuration(@NonNull String property, @NonNull Duration defaultValue) { + return Duration.ofMillis(getLong(property, defaultValue.toMillis())); + } + + private static boolean getBoolean(@NonNull String property, boolean defaultValue) { + // This call requires the READ_DEVICE_CONFIG permission. + final long callingId = Binder.clearCallingIdentity(); + try { + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, property, defaultValue); + } finally { + Binder.restoreCallingIdentity(callingId); + } + } + + private static long getLong(@NonNull String property, long defaultValue) { + // This call requires the READ_DEVICE_CONFIG permission. + final long callingId = Binder.clearCallingIdentity(); + try { + return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PRIVACY, property, defaultValue); + } finally { + Binder.restoreCallingIdentity(callingId); + } + } + + @NonNull + private static String getString(@NonNull String property, @NonNull String defaultValue) { + // This call requires the READ_DEVICE_CONFIG permission. + final long callingId = Binder.clearCallingIdentity(); + try { + return DeviceConfig.getString(DeviceConfig.NAMESPACE_PRIVACY, property, defaultValue); + } finally { + Binder.restoreCallingIdentity(callingId); + } + } + + private SafetyCenterFlags() {} +} diff --git a/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java b/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java index 4168978cd..77efe9535 100644 --- a/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java +++ b/service/java/com/android/safetycenter/SafetyCenterRefreshTracker.java @@ -22,8 +22,6 @@ import static android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUT import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.os.Binder; -import android.provider.DeviceConfig; import android.safetycenter.SafetyCenterManager.RefreshReason; import android.safetycenter.SafetyCenterStatus; import android.safetycenter.SafetyCenterStatus.RefreshStatus; @@ -48,7 +46,6 @@ import javax.annotation.concurrent.NotThreadSafe; @NotThreadSafe final class SafetyCenterRefreshTracker { private static final String TAG = "SafetyCenterRefreshTrac"; - private static final String PROPERTY_UNTRACKED_SOURCES = "safety_center_untracked_sources"; @NonNull private final SafetyCenterConfigReader mSafetyCenterConfigReader; @@ -93,7 +90,7 @@ final class SafetyCenterRefreshTracker { refreshBroadcastId, refreshReason, userProfileGroup, - getUntrackedSourceIds()); + SafetyCenterFlags.getUntrackedSourceIds()); for (int i = 0; i < broadcasts.size(); i++) { Broadcast broadcast = broadcasts.get(i); @@ -237,27 +234,6 @@ final class SafetyCenterRefreshTracker { return true; } - /** - * Returns the IDs of sources that should not be tracked, for example because they are - * mid-rollout. Broadcasts are still sent to these sources. - */ - private static ArraySet<String> getUntrackedSourceIds() { - String untrackedSourcesConfigString = getUntrackedSourcesConfigString(); - String[] untrackedSourcesList = untrackedSourcesConfigString.split(","); - return new ArraySet<>(untrackedSourcesList); - } - - private static String getUntrackedSourcesConfigString() { - // This call requires the READ_DEVICE_CONFIG permission. - final long callingId = Binder.clearCallingIdentity(); - try { - return DeviceConfig.getString( - DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_UNTRACKED_SOURCES, ""); - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - /** Class representing the state of a refresh in progress. */ private static final class RefreshInProgress { @NonNull private final String mId; diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java index 8aa110409..2cc953c75 100644 --- a/service/java/com/android/safetycenter/SafetyCenterService.java +++ b/service/java/com/android/safetycenter/SafetyCenterService.java @@ -23,6 +23,8 @@ import static android.os.Build.VERSION_CODES.TIRAMISU; import static android.safetycenter.SafetyCenterManager.RefreshReason; import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED; +import static com.android.safetycenter.SafetyCenterFlags.PROPERTY_SAFETY_CENTER_ENABLED; + import static java.util.Objects.requireNonNull; import android.annotation.NonNull; @@ -96,44 +98,6 @@ public final class SafetyCenterService extends SystemService { private static final String TAG = "SafetyCenterService"; - /** Phenotype flag that determines whether SafetyCenter is enabled. */ - private static final String PROPERTY_SAFETY_CENTER_ENABLED = "safety_center_is_enabled"; - - /** - * Phenotype flag that determines whether we should show error entries for sources that timeout - * when refreshing them. - */ - private static final String PROPERTY_SHOW_ERROR_ENTRIES_ON_TIMEOUT = - "show_error_entries_on_timeout"; - - /** - * Device Config flag that determines the time for which a Safety Center refresh is allowed to - * wait for a source to respond to a refresh request before timing out and marking the refresh - * as finished. - */ - private static final String PROPERTY_REFRESH_SOURCE_TIMEOUT_MILLIS = - "safety_center_refresh_source_timeout_millis"; - - /** - * Default time for which a Safety Center refresh is allowed to wait for a source to respond to - * a refresh request before timing out and marking the refresh as finished. - */ - private static final Duration REFRESH_SOURCE_TIMEOUT_DEFAULT_DURATION = Duration.ofSeconds(10); - - /** - * Device Config flag that determines the time for which Safety Center will wait for a source to - * respond to a resolving action before timing out. - */ - private static final String PROPERTY_RESOLVING_ACTION_TIMEOUT_MILLIS = - "safety_center_resolve_action_timeout_millis"; - - /** - * Default time for which Safety Center will wait for a source to respond to a resolving action - * before timing out. - */ - private static final Duration RESOLVING_ACTION_TIMEOUT_DEFAULT_DURATION = - Duration.ofSeconds(10); - /** The APEX name used to retrieve the APEX owned data directories. */ private static final String APEX_MODULE_NAME = "com.android.permission"; @@ -348,7 +312,7 @@ public final class SafetyCenterService extends SystemService { RefreshTimeout refreshTimeout = new RefreshTimeout(refreshBroadcastId, userProfileGroup); - mSafetyCenterTimeouts.add(refreshTimeout, getRefreshTimeout()); + mSafetyCenterTimeouts.add(refreshTimeout, SafetyCenterFlags.getRefreshTimeout()); mSafetyCenterListeners.deliverUpdateForUserProfileGroup( userProfileGroup, true, null); @@ -568,7 +532,8 @@ public final class SafetyCenterService extends SystemService { safetyCenterIssueActionId); ResolvingActionTimeout resolvingActionTimeout = new ResolvingActionTimeout(safetyCenterIssueActionId, userProfileGroup); - mSafetyCenterTimeouts.add(resolvingActionTimeout, getResolvingActionTimeout()); + mSafetyCenterTimeouts.add( + resolvingActionTimeout, SafetyCenterFlags.getResolvingActionTimeout()); mSafetyCenterListeners.deliverUpdateForUserProfileGroup( userProfileGroup, true, null); } @@ -630,7 +595,7 @@ public final class SafetyCenterService extends SystemService { } private boolean isApiEnabled() { - return canUseSafetyCenter() && getSafetyCenterEnabled(); + return canUseSafetyCenter() && SafetyCenterFlags.getSafetyCenterEnabled(); } private void enforceAnyCallingOrSelfPermissions( @@ -702,12 +667,14 @@ public final class SafetyCenterService extends SystemService { } /** - * An {@link OnPropertiesChangedListener} for {@link #PROPERTY_SAFETY_CENTER_ENABLED} that sends - * broadcasts when the SafetyCenter property is enabled or disabled. + * An {@link OnPropertiesChangedListener} for {@link + * SafetyCenterFlags#PROPERTY_SAFETY_CENTER_ENABLED} that sends broadcasts when the SafetyCenter + * property is enabled or disabled. * - * <p>This listener assumes that the {@link #PROPERTY_SAFETY_CENTER_ENABLED} value maps to - * {@link SafetyCenterManager#isSafetyCenterEnabled()}. It should only be registered if the - * device supports SafetyCenter and the {@link SafetyCenterConfig} was loaded successfully. + * <p>This listener assumes that the {@link SafetyCenterFlags#PROPERTY_SAFETY_CENTER_ENABLED} + * value maps to {@link SafetyCenterManager#isSafetyCenterEnabled()}. It should only be + * registered if the device supports SafetyCenter and the {@link SafetyCenterConfig} was loaded + * successfully. * * <p>This listener is not thread-safe; it should be called on a single thread. */ @@ -730,7 +697,7 @@ public final class SafetyCenterService extends SystemService { } private void setInitialState() { - mSafetyCenterEnabled = getSafetyCenterEnabled(); + mSafetyCenterEnabled = SafetyCenterFlags.getSafetyCenterEnabled(); } private void onSafetyCenterEnabledChanged(boolean safetyCenterEnabled) { @@ -784,7 +751,8 @@ public final class SafetyCenterService extends SystemService { if (stillInFlight == null) { return; } - boolean showErrorEntriesOnTimeout = getShowErrorEntriesOnTimeout(); + boolean showErrorEntriesOnTimeout = + SafetyCenterFlags.getShowErrorEntriesOnTimeout(); if (showErrorEntriesOnTimeout) { for (int i = 0; i < stillInFlight.size(); i++) { mSafetyCenterDataTracker.setSafetySourceError(stillInFlight.valueAt(i)); @@ -883,58 +851,6 @@ public final class SafetyCenterService extends SystemService { return mDeviceSupportsSafetyCenter && mConfigAvailable; } - private boolean getSafetyCenterEnabled() { - // This call requires the READ_DEVICE_CONFIG permission. - final long callingId = Binder.clearCallingIdentity(); - try { - return DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_SAFETY_CENTER_ENABLED, - /* defaultValue = */ false); - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - - private boolean getShowErrorEntriesOnTimeout() { - // This call requires the READ_DEVICE_CONFIG permission. - final long callingId = Binder.clearCallingIdentity(); - try { - return DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_PRIVACY, PROPERTY_SHOW_ERROR_ENTRIES_ON_TIMEOUT, false); - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - - private Duration getRefreshTimeout() { - // This call requires the READ_DEVICE_CONFIG permission. - final long callingId = Binder.clearCallingIdentity(); - try { - return Duration.ofMillis( - DeviceConfig.getLong( - DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_REFRESH_SOURCE_TIMEOUT_MILLIS, - REFRESH_SOURCE_TIMEOUT_DEFAULT_DURATION.toMillis())); - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - - private Duration getResolvingActionTimeout() { - // This call requires the READ_DEVICE_CONFIG permission. - final long callingId = Binder.clearCallingIdentity(); - try { - return Duration.ofMillis( - DeviceConfig.getLong( - DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_RESOLVING_ACTION_TIMEOUT_MILLIS, - RESOLVING_ACTION_TIMEOUT_DEFAULT_DURATION.toMillis())); - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - private void registerUserRemovedReceiver() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_REMOVED); diff --git a/service/java/com/android/safetycenter/SafetySources.java b/service/java/com/android/safetycenter/SafetySources.java index 97686826a..d6fc3cfab 100644 --- a/service/java/com/android/safetycenter/SafetySources.java +++ b/service/java/com/android/safetycenter/SafetySources.java @@ -91,4 +91,6 @@ final class SafetySources { Log.w(TAG, "Unexpected safety source type: " + safetySourceType); return false; } + + private SafetySources() {} } |