Merge changes from topics "kill_switch", "disabled_by_device_config"
* changes: Reverted ContentCapture kill-switch mechanism. Disable ContentCapture at runtime when it's disabled by DeviceConfig.
This commit is contained in:
@@ -5712,6 +5712,7 @@ package android.provider {
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
|
||||
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
|
||||
field public static final String NAMESPACE_AUTOFILL = "autofill";
|
||||
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
|
||||
field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
|
||||
field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
|
||||
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
|
||||
@@ -5741,10 +5742,6 @@ package android.provider {
|
||||
field public static final String SERVICE_ENABLED = "service_enabled";
|
||||
}
|
||||
|
||||
public static interface DeviceConfig.ContentCapture {
|
||||
field public static final String NAMESPACE = "content_capture";
|
||||
}
|
||||
|
||||
public static interface DeviceConfig.DexBoot {
|
||||
field public static final String NAMESPACE = "dex_boot";
|
||||
field public static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled";
|
||||
|
||||
@@ -1788,11 +1788,7 @@ package android.provider {
|
||||
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String);
|
||||
method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String);
|
||||
method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean);
|
||||
}
|
||||
|
||||
public static interface DeviceConfig.ContentCapture {
|
||||
field public static final String NAMESPACE = "content_capture";
|
||||
field public static final String PROPERTY_CONTENTCAPTURE_ENABLED = "enable_contentcapture";
|
||||
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
|
||||
}
|
||||
|
||||
public static interface DeviceConfig.Privacy {
|
||||
@@ -2725,6 +2721,7 @@ package android.view.contentcapture {
|
||||
public final class ContentCaptureManager {
|
||||
method public boolean isContentCaptureFeatureEnabled();
|
||||
method public void setContentCaptureFeatureEnabled(boolean);
|
||||
field public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled";
|
||||
}
|
||||
|
||||
public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
|
||||
|
||||
@@ -72,39 +72,14 @@ public final class DeviceConfig {
|
||||
public static final String NAMESPACE_AUTOFILL = "autofill";
|
||||
|
||||
/**
|
||||
* ContentCapture-related properties definitions.
|
||||
* Namespace for content capture feature used by on-device machine intelligence
|
||||
* to provide suggestions in a privacy-safe manner.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@TestApi
|
||||
public interface ContentCapture {
|
||||
String NAMESPACE = "content_capture";
|
||||
|
||||
/**
|
||||
* Property used by {@code com.android.server.SystemServer} on start to decide whether
|
||||
* the Content Capture service should be created or not.
|
||||
*
|
||||
* <p>Possible values are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If set to {@code default}, it will only be set if the OEM provides and defines the
|
||||
* service name by overlaying {@code config_defaultContentCaptureService} (this is the
|
||||
* "default" mode)
|
||||
* <li>If set to {@code always}, it will always be enabled, even when the resource is not
|
||||
* overlaid (this is useful during development and to run the CTS tests on AOSP builds).
|
||||
* <li>Otherwise, it's explicitly disabled (this could work as a "kill switch" so OEMs
|
||||
* can disable it remotely in case of emergency by setting to something else (like
|
||||
* {@code "false"}); notice that it's also disabled if the OEM doesn't explicitly set one
|
||||
* of the values above).
|
||||
* </ul>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
// TODO(b/121153631): revert back to SERVICE_EXPLICITLY_ENABLED approach
|
||||
@TestApi
|
||||
String PROPERTY_CONTENTCAPTURE_ENABLED = "enable_contentcapture";
|
||||
}
|
||||
public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
|
||||
|
||||
/**
|
||||
* Namespace for all input-related features that are used at the native level.
|
||||
|
||||
@@ -66,6 +66,25 @@ public final class ContentCaptureManager {
|
||||
*/
|
||||
private static final int SYNC_CALLS_TIMEOUT_MS = 5000;
|
||||
|
||||
/**
|
||||
* DeviceConfig property used by {@code com.android.server.SystemServer} on start to decide
|
||||
* whether the Content Capture service should be created or not
|
||||
*
|
||||
* <p>By default it should *NOT* be set (or set to {@code "default"}, so the decision is based
|
||||
* on whether the OEM provides an implementation for the service), but it can be overridden to:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Provide a "kill switch" so OEMs can disable it remotely in case of emergency (when
|
||||
* it's set to {@code "false"}).
|
||||
* <li>Enable the CTS tests to be run on AOSP builds (when it's set to {@code "true"}).
|
||||
* </ul>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED =
|
||||
"service_explicitly_enabled";
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
@NonNull
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.ActivityThread;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
@@ -39,6 +40,7 @@ import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.Settings;
|
||||
import android.util.LocalLog;
|
||||
import android.util.Slog;
|
||||
@@ -89,19 +91,38 @@ public final class ContentCaptureManagerService extends
|
||||
@Nullable
|
||||
private SparseBooleanArray mDisabledUsers;
|
||||
|
||||
/**
|
||||
* Global kill-switch based on value defined by
|
||||
* {@link ContentCaptureManager#DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED}.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private boolean mDisabledByDeviceConfig;
|
||||
|
||||
public ContentCaptureManagerService(@NonNull Context context) {
|
||||
super(context, new FrameworkResourcesServiceNameResolver(context,
|
||||
com.android.internal.R.string.config_defaultContentCaptureService),
|
||||
UserManager.DISALLOW_CONTENT_CAPTURE);
|
||||
// Sets which serviecs are disabled
|
||||
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
|
||||
ActivityThread.currentApplication().getMainExecutor(),
|
||||
(namespace, key, value) -> {
|
||||
if (!ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED
|
||||
.equals(key)) {
|
||||
Slog.i(mTag, "Ignoring change on " + key);
|
||||
return;
|
||||
}
|
||||
setDisabledByDeviceConfig(value);
|
||||
});
|
||||
setDisabledByDeviceConfig();
|
||||
|
||||
// Sets which services are disabled
|
||||
final UserManager um = getContext().getSystemService(UserManager.class);
|
||||
final List<UserInfo> users = um.getUsers();
|
||||
for (int i = 0; i < users.size(); i++) {
|
||||
final int userId = users.get(i).id;
|
||||
final boolean disabled = isDisabledBySettings(userId);
|
||||
final boolean disabled = mDisabledByDeviceConfig || isDisabledBySettings(userId);
|
||||
if (disabled) {
|
||||
Slog.i(mTag, "user " + userId + " disabled by settings");
|
||||
Slog.i(mTag, "user " + userId + " disabled by settings or device config");
|
||||
if (mDisabledUsers == null) {
|
||||
mDisabledUsers = new SparseBooleanArray(1);
|
||||
}
|
||||
@@ -160,7 +181,8 @@ public final class ContentCaptureManagerService extends
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected boolean isDisabledLocked(@UserIdInt int userId) {
|
||||
return isDisabledBySettingsLocked(userId) || super.isDisabledLocked(userId);
|
||||
return mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId)
|
||||
|| super.isDisabledLocked(userId);
|
||||
}
|
||||
|
||||
private boolean isDisabledBySettingsLocked(@UserIdInt int userId) {
|
||||
@@ -191,6 +213,45 @@ public final class ContentCaptureManagerService extends
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setDisabledByDeviceConfig() {
|
||||
final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
|
||||
ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
|
||||
setDisabledByDeviceConfig(value);
|
||||
}
|
||||
|
||||
private void setDisabledByDeviceConfig(@Nullable String value) {
|
||||
if (verbose) Slog.v(mTag, "setDisabledByDeviceConfig(): value=" + value);
|
||||
final UserManager um = getContext().getSystemService(UserManager.class);
|
||||
final List<UserInfo> users = um.getUsers();
|
||||
|
||||
final boolean newDisabledValue;
|
||||
|
||||
if (value != null && value.equalsIgnoreCase("false")) {
|
||||
newDisabledValue = true;
|
||||
} else {
|
||||
newDisabledValue = false;
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
if (mDisabledByDeviceConfig == newDisabledValue) {
|
||||
if (verbose) {
|
||||
Slog.v(mTag, "setDisabledByDeviceConfig(): already " + newDisabledValue);
|
||||
}
|
||||
return;
|
||||
}
|
||||
mDisabledByDeviceConfig = newDisabledValue;
|
||||
|
||||
Slog.i(mTag, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig);
|
||||
for (int i = 0; i < users.size(); i++) {
|
||||
final int userId = users.get(i).id;
|
||||
boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId);
|
||||
Slog.i(mTag, "setDisabledByDeviceConfig(): updating service for user "
|
||||
+ userId + " to " + (disabled ? "'disabled'" : "'enabled'"));
|
||||
updateCachedServiceLocked(userId, disabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setContentCaptureFeatureEnabledForUser(@UserIdInt int userId, boolean enabled) {
|
||||
synchronized (mLock) {
|
||||
if (mDisabledUsers == null) {
|
||||
@@ -338,6 +399,8 @@ public final class ContentCaptureManagerService extends
|
||||
super.dumpLocked(prefix, pw);
|
||||
|
||||
pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
|
||||
pw.print(prefix); pw.print("Disabled by DeviceConfig: ");
|
||||
pw.println(mDisabledByDeviceConfig);
|
||||
}
|
||||
|
||||
final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
|
||||
@@ -406,7 +469,7 @@ public final class ContentCaptureManagerService extends
|
||||
"isContentCaptureFeatureEnabled()", userId, Binder.getCallingUid(), result);
|
||||
if (!isService) return;
|
||||
|
||||
enabled = !isDisabledBySettingsLocked(userId);
|
||||
enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
|
||||
}
|
||||
try {
|
||||
result.send(enabled ? ContentCaptureManager.RESULT_CODE_TRUE
|
||||
|
||||
@@ -64,6 +64,7 @@ import android.util.EventLog;
|
||||
import android.util.Slog;
|
||||
import android.util.TimingsTraceLog;
|
||||
import android.view.WindowManager;
|
||||
import android.view.contentcapture.ContentCaptureManager;
|
||||
import android.view.inputmethod.InputMethodSystemProperty;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -2214,33 +2215,30 @@ public final class SystemServer {
|
||||
}
|
||||
|
||||
private void startContentCaptureService(@NonNull Context context) {
|
||||
// Check if it was explicitly enabled by DeviceConfig
|
||||
final String settings = DeviceConfig.getProperty(DeviceConfig.ContentCapture.NAMESPACE,
|
||||
DeviceConfig.ContentCapture.PROPERTY_CONTENTCAPTURE_ENABLED);
|
||||
if (settings == null) {
|
||||
// Better be safe than sorry...
|
||||
Slog.d(TAG, "ContentCaptureService disabled because its not set by OEM");
|
||||
return;
|
||||
}
|
||||
switch (settings) {
|
||||
case "always":
|
||||
// Should be used only during development
|
||||
// First check if it was explicitly enabled by DeviceConfig
|
||||
boolean explicitlySupported = false;
|
||||
String settings = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
|
||||
ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
|
||||
if (settings != null && !settings.equalsIgnoreCase("default")) {
|
||||
explicitlySupported = Boolean.parseBoolean(settings);
|
||||
if (explicitlySupported) {
|
||||
Slog.d(TAG, "ContentCaptureService explicitly enabled by DeviceConfig");
|
||||
break;
|
||||
case "default":
|
||||
// Default case: check if OEM overlaid the resource that defines the service.
|
||||
final String serviceName = context.getString(
|
||||
com.android.internal.R.string.config_defaultContentCaptureService);
|
||||
if (TextUtils.isEmpty(serviceName)) {
|
||||
Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Kill switch for OEMs
|
||||
Slog.d(TAG, "ContentCaptureService disabled because its set to: " + settings);
|
||||
} else {
|
||||
Slog.d(TAG, "ContentCaptureService explicitly disabled by DeviceConfig");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Then check if OEM overlaid the resource that defines the service.
|
||||
if (!explicitlySupported) {
|
||||
final String serviceName = context
|
||||
.getString(com.android.internal.R.string.config_defaultContentCaptureService);
|
||||
if (TextUtils.isEmpty(serviceName)) {
|
||||
Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
traceBeginAndSlog("StartContentCaptureService");
|
||||
mSystemServiceManager.startService(CONTENT_CAPTURE_MANAGER_SERVICE_CLASS);
|
||||
traceEnd();
|
||||
|
||||
Reference in New Issue
Block a user