diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b53d9af5d4e45..f9e7bacd9b02b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12837,6 +12837,23 @@ public final class Settings {
public static final String MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY =
"max_sound_trigger_detection_service_ops_per_day";
+ /**
+ * Property used by {@code com.android.server.SystemServer} on start to decide whether
+ * the Smart Suggestions service should be created or not
+ *
+ *
By default it should *NOT* be set (in which case the decision is based on whether
+ * the OEM provides an implementation for the service), but it can be overridden to:
+ *
+ *
+ * - Provide a "kill switch" so OEMs can disable it remotely in case of emergency.
+ *
- Enable the CTS tests to be run on AOSP builds
+ *
+ *
+ * @hide
+ */
+ public static final String SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED =
+ "smart_suggestions_service_explicitly_enabled";
+
/**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index d917536b17150..e3184c18659c0 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -761,6 +761,13 @@ message GlobalSettingsProto {
}
optional SmartSelection smart_selection = 108;
+ message SmartSuggestions {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto service_explicitly_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional SmartSuggestions smart_suggestions = 145;
+
message Sms {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -991,5 +998,5 @@ message GlobalSettingsProto {
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 145;
+ // Next tag = 146;
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0cd6bc5cd7001..c62071bdf5527 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3350,6 +3350,14 @@
-->
+
+
+
true
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 01422c8ffd970..6854a84e950ac 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3265,6 +3265,7 @@
+
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index a8f9e8a5891b3..750505e76a61e 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -415,6 +415,7 @@ public class SettingsBackupTest {
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
+ Settings.Global.SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED,
Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED,
Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 56b768feee234..83b1e89af902c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1165,6 +1165,12 @@ class SettingsProtoDumpUtil {
GlobalSettingsProto.SmartSelection.UPDATE_METADATA_URL);
p.end(smartSelectToken);
+ final long smartSuggestionsToken = p.start(GlobalSettingsProto.SMART_SUGGESTIONS);
+ dumpSetting(s, p,
+ Settings.Global.SMART_SUGGESTIONS_SERVICE_EXPLICITLY_ENABLED,
+ GlobalSettingsProto.SmartSuggestions.SERVICE_EXPLICITLY_ENABLED);
+ p.end(smartSuggestionsToken);
+
final long smsToken = p.start(GlobalSettingsProto.SMS);
dumpSetting(s, p,
Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS,
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 0df99d4b6642b..18bc856700f7a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -190,6 +190,11 @@ final class AutofillManagerServiceImpl
return mInfo.getServiceInfo();
}
+ @Override // from PerUserSystemService
+ protected String getDefaultComponentName() {
+ return getComponentNameFromSettings();
+ }
+
@Nullable
String[] getUrlBarResourceIdsForCompatMode(@NonNull String packageName) {
return mAutofillCompatState.getUrlBarResourceIds(packageName, mUserId);
@@ -369,7 +374,7 @@ final class AutofillManagerServiceImpl
final long identity = Binder.clearCallingIdentity();
try {
- final String autoFillService = getComponentNameFromSettings();
+ final String autoFillService = getComponentNameLocked();
final ComponentName componentName = serviceInfo.getComponentName();
if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) {
mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF,
diff --git a/services/core/java/com/android/server/AbstractMasterSystemService.java b/services/core/java/com/android/server/AbstractMasterSystemService.java
index 1759ce195485b..76010b346a3b3 100644
--- a/services/core/java/com/android/server/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/AbstractMasterSystemService.java
@@ -39,6 +39,7 @@ import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
import java.io.PrintWriter;
import java.util.List;
@@ -210,6 +211,66 @@ public abstract class AbstractMasterSystemServiceTypically used by Shell command and/or CTS tests.
+ *
+ * @param componentName name of the new component
+ * @param durationMs how long the change will be valid (the service will be automatically reset
+ * to the default component after this timeout expires).
+ * @throws SecurityException if caller is not allowed to manage this service's settings.
+ * @throws IllegalArgumentException if value of {@code durationMs} is higher than
+ * {@link #getMaximumTemporaryServiceDurationMs()}.
+ */
+ public final void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
+ int durationMs) {
+ Slog.i(mTag, "setTemporaryService(" + userId + ") to " + componentName + " for "
+ + durationMs + "ms");
+ enforceCallingPermissionForManagement();
+
+ Preconditions.checkNotNull(componentName);
+ final int maxDurationMs = getMaximumTemporaryServiceDurationMs();
+ if (durationMs > maxDurationMs) {
+ throw new IllegalArgumentException(
+ "Max duration is " + maxDurationMs + " (called with " + durationMs + ")");
+ }
+
+ synchronized (mLock) {
+ final S service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.setTemporaryServiceLocked(componentName, durationMs);
+ }
+ }
+ }
+
+ /**
+ * Gets the maximum time the service implementation can be changed.
+ *
+ * @throws UnsupportedOperationException if subclass doesn't override it.
+ */
+ protected int getMaximumTemporaryServiceDurationMs() {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
+
+ /**
+ * Resets the temporary service implementation to the default component.
+ *
+ * Typically used by Shell command and/or CTS tests.
+ *
+ * @throws SecurityException if caller is not allowed to manage this service's settings.
+ */
+ public final void resetTemporaryService(@UserIdInt int userId) {
+ Slog.i(mTag, "resetTemporaryService(): " + userId);
+ enforceCallingPermissionForManagement();
+ synchronized (mLock) {
+ final S service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.resetTemporaryServiceLocked();
+ }
+ }
+ }
+
/**
* Asserts that the caller has permissions to manage this service.
*
diff --git a/services/core/java/com/android/server/AbstractPerUserSystemService.java b/services/core/java/com/android/server/AbstractPerUserSystemService.java
index 001d85f1b7982..a26102d57297c 100644
--- a/services/core/java/com/android/server/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/AbstractPerUserSystemService.java
@@ -26,12 +26,17 @@ import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Slog;
+import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
@@ -49,6 +54,9 @@ import java.io.PrintWriter;
public abstract class AbstractPerUserSystemService,
M extends AbstractMasterSystemService> {
+ /** Handler message to {@link #resetTemporaryServiceLocked()} */
+ private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
+
protected final @UserIdInt int mUserId;
protected final Object mLock;
protected final String mTag = getClass().getSimpleName();
@@ -70,6 +78,26 @@ public abstract class AbstractPerUserSystemServiceTypically used by Shell command and/or CTS tests.
+ */
+ @GuardedBy("mLock")
+ private String mTemporaryServiceName;
+
+ /**
+ * When the temporary service will expire (and reset back to the default).
+ */
+ @GuardedBy("mLock")
+ private long mTemporaryServiceExpiration;
+
+ /**
+ * Handler used to reset the temporary service name.
+ */
+ @GuardedBy("mLock")
+ private Handler mTemporaryHandler;
+
protected AbstractPerUserSystemService(@NonNull M master, @NonNull Object lock,
@UserIdInt int userId) {
mMaster = master;
@@ -130,7 +158,7 @@ public abstract class AbstractPerUserSystemServiceTypically implemented by returning {@link #getComponentNameFromSettings()} or by using
+ * a string from the system resources.
+ */
+ @Nullable
+ protected abstract String getDefaultComponentName();
+
/**
* Gets this name of the remote service this service binds to as defined by {@link Settings}.
*/
@@ -200,6 +251,66 @@ public abstract class AbstractPerUserSystemService