Merge "remove overrides of onDrawText -- no longer called"
diff --git a/api/current.txt b/api/current.txt
index 2ef4a39..f6f5476 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11479,6 +11479,7 @@
field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
+ field public static final java.lang.String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
field public static final java.lang.String FEATURE_IRIS = "android.hardware.iris";
field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
diff --git a/api/system-current.txt b/api/system-current.txt
index a37da64..57b7eed 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -614,7 +614,12 @@
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
field public static final java.lang.String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
+ field public static final java.lang.String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
field public static final java.lang.String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+ field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
+ field public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
+ field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2
+ field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0
field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2
field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index aa1b5af..b9d5907 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4770,14 +4770,16 @@
TemplateBindResult result) {
boolean largeIconShown = bindLargeIcon(contentView, p);
boolean replyIconShown = bindReplyIcon(contentView, p);
+ boolean iconContainerVisible = largeIconShown || replyIconShown;
contentView.setViewVisibility(R.id.right_icon_container,
- largeIconShown || replyIconShown ? View.VISIBLE : View.GONE);
+ iconContainerVisible ? View.VISIBLE : View.GONE);
int marginEnd = calculateMarginEnd(largeIconShown, replyIconShown);
contentView.setViewLayoutMarginEnd(R.id.line1, marginEnd);
contentView.setViewLayoutMarginEnd(R.id.text, marginEnd);
contentView.setViewLayoutMarginEnd(R.id.progress, marginEnd);
if (result != null) {
result.setIconMarginEnd(marginEnd);
+ result.setRightIconContainerVisible(iconContainerVisible);
}
}
@@ -6777,7 +6779,8 @@
mBuilder.setTextViewColorSecondary(contentView, R.id.big_text, p);
contentView.setViewVisibility(R.id.big_text,
TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
- contentView.setBoolean(R.id.big_text, "setHasImage", mBuilder.mN.hasLargeIcon());
+ contentView.setBoolean(R.id.big_text, "setHasImage",
+ result.isRightIconContainerVisible());
return contentView;
}
@@ -9914,6 +9917,7 @@
*/
private static class TemplateBindResult {
int mIconMarginEnd;
+ boolean mRightIconContainerVisible;
/**
* Get the margin end that needs to be added to any fields that may overlap
@@ -9923,9 +9927,21 @@
return mIconMarginEnd;
}
+ /**
+ * Is the icon container visible on the right size because of the reply button or the
+ * right icon.
+ */
+ public boolean isRightIconContainerVisible() {
+ return mRightIconContainerVisible;
+ }
+
public void setIconMarginEnd(int iconMarginEnd) {
this.mIconMarginEnd = iconMarginEnd;
}
+
+ public void setRightIconContainerVisible(boolean iconContainerVisible) {
+ mRightIconContainerVisible = iconContainerVisible;
+ }
}
private static class StandardTemplateParams {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3a97284..e826250 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1121,6 +1121,64 @@
"android.app.extra.PROVISIONING_USE_MOBILE_DATA";
/**
+ * A String extra holding the provisioning trigger. It could be one of
+ * {@link #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT}, {@link #PROVISIONING_TRIGGER_QR_CODE},
+ * {@link #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER} or {@link
+ * #PROVISIONING_TRIGGER_UNSPECIFIED}.
+ *
+ * <p>Use in an intent with action {@link
+ * #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PROVISIONING_TRIGGER =
+ "android.app.extra.PROVISIONING_TRIGGER";
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger has not been specified.
+ * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+ * @see #PROVISIONING_TRIGGER_QR_CODE
+ * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger is cloud enrollment.
+ * @see #PROVISIONING_TRIGGER_QR_CODE
+ * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger is the QR code scanner.
+ * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+ * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_QR_CODE = 2;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger is persistent device owner enrollment.
+ * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+ * @see #PROVISIONING_TRIGGER_QR_CODE
+ * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3;
+
+ /**
* This MIME type is used for starting the device owner provisioning.
*
* <p>During device owner provisioning a device admin app is set as the owner of the device.
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 578a9ae..3cc56ae 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -47,6 +47,8 @@
public static final int REASON_TIMEOUT = JobProtoEnums.STOP_REASON_TIMEOUT; // 3.
/** @hide */
public static final int REASON_DEVICE_IDLE = JobProtoEnums.STOP_REASON_DEVICE_IDLE; // 4.
+ /** @hide */
+ public static final int REASON_DEVICE_THERMAL = JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5.
/** @hide */
public static String getReasonName(int reason) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b7df2bf..f40be84 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2687,6 +2687,16 @@
"android.software.device_id_attestation";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+ * the requisite kernel support for multinetworking-capable IPsec tunnels.
+ *
+ * <p>This feature implies that the device supports XFRM Interfaces (CONFIG_XFRM_INTERFACE), or
+ * VTIs with kernel patches allowing updates of output/set mark via UPDSA.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
+
+ /**
* Extra field name for the URI to a verification file. Passed to a package
* verifier.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 64aa088..f86296b8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1680,6 +1680,11 @@
*/
public static final String CALL_METHOD_TAG_KEY = "_tag";
+ /**
+ * @hide - String argument extra to the fast-path call()-based requests
+ */
+ public static final String CALL_METHOD_PREFIX_KEY = "_prefix";
+
/** @hide - Private call() method to write to 'system' table */
public static final String CALL_METHOD_PUT_SYSTEM = "PUT_system";
@@ -1701,15 +1706,18 @@
/** @hide - Private call() method to delete from the 'global' table */
public static final String CALL_METHOD_DELETE_GLOBAL = "DELETE_global";
+ /** @hide - Private call() method to reset to defaults the 'configuration' table */
+ public static final String CALL_METHOD_DELETE_CONFIG = "DELETE_config";
+
+ /** @hide - Private call() method to reset to defaults the 'secure' table */
+ public static final String CALL_METHOD_RESET_SECURE = "RESET_secure";
+
/** @hide - Private call() method to reset to defaults the 'global' table */
public static final String CALL_METHOD_RESET_GLOBAL = "RESET_global";
/** @hide - Private call() method to reset to defaults the 'configuration' table */
public static final String CALL_METHOD_RESET_CONFIG = "RESET_config";
- /** @hide - Private call() method to reset to defaults the 'secure' table */
- public static final String CALL_METHOD_RESET_SECURE = "RESET_secure";
-
/** @hide - Private call() method to query the 'system' table */
public static final String CALL_METHOD_LIST_SYSTEM = "LIST_system";
@@ -1719,6 +1727,9 @@
/** @hide - Private call() method to query the 'global' table */
public static final String CALL_METHOD_LIST_GLOBAL = "LIST_global";
+ /** @hide - Private call() method to reset to defaults the 'configuration' table */
+ public static final String CALL_METHOD_LIST_CONFIG = "LIST_config";
+
/**
* Activity Extra: Limit available options in launched activity based on the given authority.
* <p>
@@ -13671,6 +13682,22 @@
"smart_replies_in_notifications_flags";
/**
+ * Configuration flags for the automatic generation of smart replies and smart actions in
+ * notifications. This is encoded as a key=value list, separated by commas. Ex:
+ * "generate_replies=false,generate_actions=true".
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * generate_replies (boolean)
+ * generate_actions (boolean)
+ * </pre>
+ * @hide
+ */
+ public static final String SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS =
+ "smart_suggestions_in_notifications_flags";
+
+ /**
* If nonzero, crashes in foreground processes will bring up a dialog.
* Otherwise, the process will be silently killed.
* @hide
diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto
index 2290b2f..bba8328 100644
--- a/core/proto/android/app/job/enums.proto
+++ b/core/proto/android/app/job/enums.proto
@@ -30,4 +30,5 @@
STOP_REASON_PREEMPT = 2;
STOP_REASON_TIMEOUT = 3;
STOP_REASON_DEVICE_IDLE = 4;
+ STOP_REASON_DEVICE_THERMAL = 5;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 9620e4b..ca8da55 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -635,6 +635,9 @@
// separated by commas.
optional SettingProto snooze_options = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto smart_replies_in_notifications_flags = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Configuration options for smart replies and smart actions in notifications. This is
+ // encoded as a key=value list separated by commas.
+ optional SettingProto smart_suggestions_in_notifications_flags = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Notification notification = 82;
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 231caab..c2bc7bf 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -41,6 +41,7 @@
optional int64 last_heartbeat_time_millis = 16;
optional int64 next_heartbeat_time_millis = 17;
optional bool in_parole = 18;
+ optional bool in_thermal = 19;
repeated int32 started_users = 2;
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f1ed1c2..1d72a03 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -248,6 +248,7 @@
Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
+ Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
Settings.Global.ENHANCED_4G_MODE_ENABLED,
Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
Settings.Global.ERROR_LOGCAT_PREFIX,
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index 108585d..04e8802 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -16,6 +16,10 @@
package android.provider;
+import static org.hamcrest.Matchers.aMapWithSize;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.junit.Assert.assertThat;
+
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -26,6 +30,7 @@
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
@@ -33,10 +38,19 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/** Unit test for SettingsProvider. */
public class SettingsProviderTest extends AndroidTestCase {
+ /**
+ * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a System
+ * API.
+ */
+ private static final Uri CONFIG_CONTENT_URI =
+ Uri.parse("content://" + Settings.AUTHORITY + "/config");
+
@MediumTest
public void testNameValueCache() {
ContentResolver r = getContext().getContentResolver();
@@ -379,4 +393,109 @@
assertTrue(ssaid.equals(ssaid2));
}
+
+ @MediumTest
+ public void testCall_putAndGetConfig() {
+ ContentResolver r = getContext().getContentResolver();
+ String name = "key1";
+ String value = "value1";
+ String newValue = "value2";
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+
+ try {
+ // value is empty
+ Bundle results =
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertNull(results.get(Settings.NameValueTable.VALUE));
+
+ // save value
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args);
+ assertNull(results);
+
+ // value is no longer empty
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertEquals(value, results.get(Settings.NameValueTable.VALUE));
+
+ // save new value
+ args.putString(Settings.NameValueTable.VALUE, newValue);
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args);
+
+ // new value is returned
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertEquals(newValue, results.get(Settings.NameValueTable.VALUE));
+ } finally {
+ // clean up
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null);
+ }
+ }
+
+ @MediumTest
+ public void testCall_deleteConfig() {
+ ContentResolver r = getContext().getContentResolver();
+ String name = "key1";
+ String value = "value1";
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+
+ try {
+ // save value
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args);
+
+ // get value
+ Bundle results =
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertEquals(value, results.get(Settings.NameValueTable.VALUE));
+
+ // delete value
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null);
+
+ // value is empty now
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertNull(results.get(Settings.NameValueTable.VALUE));
+ } finally {
+ // clean up
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null);
+ }
+ }
+
+ @MediumTest
+ public void testCall_listConfig() {
+ ContentResolver r = getContext().getContentResolver();
+ String prefix = "foo";
+ String newPrefix = "bar";
+ String name = prefix + "/" + "key1";
+ String newName = newPrefix + "/" + "key1";
+ String value = "value1";
+ String newValue = "value2";
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+
+ try {
+ // save both values
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args);
+ args.putString(Settings.NameValueTable.VALUE, newValue);
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, newName, args);
+
+ // list all values
+ Bundle result = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_LIST_CONFIG,
+ null, null);
+ Map<String, String> keyValueMap =
+ (HashMap) result.getSerializable(Settings.NameValueTable.VALUE);
+ assertThat(keyValueMap.size(), greaterThanOrEqualTo(2));
+ assertEquals(value, keyValueMap.get(name));
+ assertEquals(newValue, keyValueMap.get(newName));
+
+ // list values for prefix
+ args.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix);
+ result = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_LIST_CONFIG, null, args);
+ keyValueMap = (HashMap) result.getSerializable(Settings.NameValueTable.VALUE);
+ assertThat(keyValueMap, aMapWithSize(1));
+ assertEquals(value, keyValueMap.get(name));
+ } finally {
+ // clean up
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null);
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, newName, null);
+ }
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ad88432..5e7fb85 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1004,6 +1004,9 @@
dumpSetting(s, p,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
GlobalSettingsProto.Notification.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS);
+ dumpSetting(s, p,
+ Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
+ GlobalSettingsProto.Notification.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS);
p.end(notificationToken);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 00ea45c..140a5a3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -94,6 +94,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -147,6 +148,7 @@
private static final String TABLE_SYSTEM = "system";
private static final String TABLE_SECURE = "secure";
private static final String TABLE_GLOBAL = "global";
+ private static final String TABLE_CONFIG = "config";
// Old tables no longer exist.
private static final String TABLE_FAVORITES = "favorites";
@@ -414,9 +416,8 @@
case Settings.CALL_METHOD_PUT_CONFIG: {
String value = getSettingValue(args);
- String tag = getSettingTag(args);
final boolean makeDefault = getSettingMakeDefault(args);
- insertConfigSetting(name, value, tag, makeDefault, requestingUserId, false);
+ insertConfigSetting(name, value, null, makeDefault, requestingUserId, false);
break;
}
@@ -444,8 +445,8 @@
case Settings.CALL_METHOD_RESET_CONFIG: {
final int mode = getResetModeEnforcingPermission(args);
- String tag = getSettingTag(args);
- resetConfigSetting(requestingUserId, mode, tag);
+ String prefix = getSettingPrefix(args);
+ resetConfigSetting(requestingUserId, mode, prefix);
break;
}
@@ -463,15 +464,8 @@
break;
}
- case Settings.CALL_METHOD_DELETE_SYSTEM: {
- int rows = deleteSystemSetting(name, requestingUserId) ? 1 : 0;
- Bundle result = new Bundle();
- result.putInt(RESULT_ROWS_DELETED, rows);
- return result;
- }
-
- case Settings.CALL_METHOD_DELETE_SECURE: {
- int rows = deleteSecureSetting(name, requestingUserId, false) ? 1 : 0;
+ case Settings.CALL_METHOD_DELETE_CONFIG: {
+ int rows = deleteConfigSetting(name, requestingUserId, false) ? 1 : 0;
Bundle result = new Bundle();
result.putInt(RESULT_ROWS_DELETED, rows);
return result;
@@ -484,10 +478,32 @@
return result;
}
- case Settings.CALL_METHOD_LIST_SYSTEM: {
+ case Settings.CALL_METHOD_DELETE_SECURE: {
+ int rows = deleteSecureSetting(name, requestingUserId, false) ? 1 : 0;
+ Bundle result = new Bundle();
+ result.putInt(RESULT_ROWS_DELETED, rows);
+ return result;
+ }
+
+ case Settings.CALL_METHOD_DELETE_SYSTEM: {
+ int rows = deleteSystemSetting(name, requestingUserId) ? 1 : 0;
+ Bundle result = new Bundle();
+ result.putInt(RESULT_ROWS_DELETED, rows);
+ return result;
+ }
+
+ case Settings.CALL_METHOD_LIST_CONFIG: {
+ String prefix = getSettingPrefix(args);
+ Bundle result = new Bundle();
+ result.putSerializable(
+ Settings.NameValueTable.VALUE, (HashMap) getAllConfigFlags(prefix));
+ return result;
+ }
+
+ case Settings.CALL_METHOD_LIST_GLOBAL: {
Bundle result = new Bundle();
result.putStringArrayList(RESULT_SETTINGS_LIST,
- buildSettingsList(getAllSystemSettings(requestingUserId, null)));
+ buildSettingsList(getAllGlobalSettings(null)));
return result;
}
@@ -498,10 +514,10 @@
return result;
}
- case Settings.CALL_METHOD_LIST_GLOBAL: {
+ case Settings.CALL_METHOD_LIST_SYSTEM: {
Bundle result = new Bundle();
result.putStringArrayList(RESULT_SETTINGS_LIST,
- buildSettingsList(getAllGlobalSettings(null)));
+ buildSettingsList(getAllSystemSettings(requestingUserId, null)));
return result;
}
@@ -1061,36 +1077,47 @@
MUTATION_OPERATION_INSERT, forceNotify, 0);
}
- private void resetConfigSetting(int requestingUserId, int mode, String tag) {
+ private boolean deleteConfigSetting(String name, int requestingUserId, boolean forceNotify) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "deleteConfigSetting(" + name + ", " + requestingUserId
+ + ", " + forceNotify + ")");
+ }
+ return mutateConfigSetting(name, null, null, false, requestingUserId,
+ MUTATION_OPERATION_DELETE, forceNotify, 0);
+ }
+
+ private void resetConfigSetting(int requestingUserId, int mode, String prefix) {
if (DEBUG) {
Slog.v(LOG_TAG, "resetConfigSetting(" + requestingUserId + ", "
- + mode + ", " + tag + ")");
+ + mode + ", " + prefix + ")");
}
- mutateConfigSetting(null, null, tag, false, requestingUserId,
+ mutateConfigSetting(null, null, prefix, false, requestingUserId,
MUTATION_OPERATION_RESET, false, mode);
}
- private boolean mutateConfigSetting(String name, String value, String tag,
+ private boolean mutateConfigSetting(String name, String value, String prefix,
boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
int mode) {
// TODO(b/117663715): check the new permission when it's added.
// enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
- // Resolve the userId on whose behalf the call is made.
- final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
-
// Perform the mutation.
synchronized (mLock) {
switch (operation) {
case MUTATION_OPERATION_INSERT: {
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
- UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
+ UserHandle.USER_SYSTEM, name, value, null, makeDefault,
getCallingPackage(), forceNotify, null);
}
+ case MUTATION_OPERATION_DELETE: {
+ return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_CONFIG,
+ UserHandle.USER_SYSTEM, name, forceNotify, null);
+ }
+
case MUTATION_OPERATION_RESET: {
mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
- UserHandle.USER_SYSTEM, getCallingPackage(), mode, tag);
+ UserHandle.USER_SYSTEM, getCallingPackage(), mode, null, prefix);
} return true;
}
}
@@ -1098,6 +1125,34 @@
return false;
}
+ private Map<String, String> getAllConfigFlags(@Nullable String prefix) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getAllConfigFlags() for " + prefix);
+ }
+
+ synchronized (mLock) {
+ // Get the settings.
+ SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
+ SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
+
+ List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_CONFIG,
+ UserHandle.USER_SYSTEM);
+
+ final int nameCount = names.size();
+ Map<String, String> flagsToValues = new HashMap<>(names.size());
+
+ for (int i = 0; i < nameCount; i++) {
+ String name = names.get(i);
+ Setting setting = settingsState.getSettingLocked(name);
+ if (prefix == null || setting.getName().startsWith(prefix)) {
+ flagsToValues.put(setting.getName(), setting.getValue());
+ }
+ }
+
+ return flagsToValues;
+ }
+ }
+
private Cursor getAllGlobalSettings(String[] projection) {
if (DEBUG) {
Slog.v(LOG_TAG, "getAllGlobalSettings()");
@@ -2085,6 +2140,13 @@
return (args != null) ? args.getString(Settings.CALL_METHOD_TAG_KEY) : null;
}
+ private static String getSettingPrefix(Bundle args) {
+ String prefix = (args != null) ? args.getString(Settings.CALL_METHOD_PREFIX_KEY) : null;
+ // Append '/' to ensure we only match properties with this exact prefix.
+ // i.e. "foo" should match "foo/property" but not "foobar/property"
+ return prefix != null ? prefix + "/" : null;
+ }
+
private static boolean getSettingMakeDefault(Bundle args) {
return (args != null) && args.getBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY);
}
@@ -2644,6 +2706,11 @@
public void resetSettingsLocked(int type, int userId, String packageName, int mode,
String tag) {
+ resetSettingsLocked(type, userId, packageName, mode, tag, null);
+ }
+
+ public void resetSettingsLocked(int type, int userId, String packageName, int mode,
+ String tag, @Nullable String prefix) {
final int key = makeKey(type, userId);
SettingsState settingsState = peekSettingsStateLocked(key);
if (settingsState == null) {
@@ -2656,7 +2723,8 @@
boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (packageName.equals(setting.getPackageName())) {
- if (tag != null && !tag.equals(setting.getTag())) {
+ if ((tag != null && !tag.equals(setting.getTag()))
+ || (prefix != null && !setting.getName().startsWith(prefix))) {
continue;
}
if (settingsState.resetSettingLocked(name)) {
@@ -2676,6 +2744,9 @@
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ continue;
+ }
if (settingsState.resetSettingLocked(name)) {
someSettingChanged = true;
notifyForSettingsChange(key, name);
@@ -2693,6 +2764,9 @@
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ continue;
+ }
if (setting.isDefaultFromSystem()) {
if (settingsState.resetSettingLocked(name)) {
someSettingChanged = true;
@@ -2713,6 +2787,9 @@
for (String name : settingsState.getSettingNamesLocked()) {
Setting setting = settingsState.getSettingLocked(name);
boolean someSettingChanged = false;
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ continue;
+ }
if (setting.isDefaultFromSystem()) {
if (settingsState.resetSettingLocked(name)) {
someSettingChanged = true;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 173f074..e8b2e8b 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -54,6 +54,8 @@
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
+import android.os.IThermalService;
+import android.os.IThermalStatusListener;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
@@ -62,6 +64,7 @@
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
+import android.os.Temperature;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.provider.Settings;
@@ -75,6 +78,7 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
@@ -179,6 +183,11 @@
private final StorageController mStorageController;
/** Need directly for sending uid state changes */
private final DeviceIdleJobsController mDeviceIdleJobsController;
+ /** Need directly for receiving thermal events */
+ private IThermalService mThermalService;
+ /** Thermal constraint. */
+ @GuardedBy("mLock")
+ private boolean mThermalConstraint = false;
/**
* Queue of pending jobs. The JobServiceContext class will receive jobs from this list
@@ -310,6 +319,19 @@
}
/**
+ * Thermal event received from Thermal Service
+ */
+ private final class ThermalStatusListener extends IThermalStatusListener.Stub {
+ @Override public void onStatusChange(int status) {
+ // Throttle for Temperature.THROTTLING_SEVERE and above
+ synchronized (mLock) {
+ mThermalConstraint = status >= Temperature.THROTTLING_SEVERE;
+ }
+ onControllerStateChanged();
+ }
+ }
+
+ /**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
* holding the JobSchedulerService.mLock lock.
@@ -1366,6 +1388,16 @@
}
// Remove any jobs that are not associated with any of the current users.
cancelJobsForNonExistentUsers();
+ // Register thermal callback
+ mThermalService = IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ if (mThermalService != null) {
+ try {
+ mThermalService.registerThermalStatusListener(new ThermalStatusListener());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register thermal callback.", e);
+ }
+ }
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mLock) {
// Let's go!
@@ -1789,14 +1821,26 @@
}
}
+ private boolean isJobThermalConstrainedLocked(JobStatus job) {
+ return mThermalConstraint && job.hasConnectivityConstraint()
+ && (evaluateJobPriorityLocked(job) < JobInfo.PRIORITY_FOREGROUND_APP);
+ }
+
private void stopNonReadyActiveJobsLocked() {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext serviceContext = mActiveServices.get(i);
final JobStatus running = serviceContext.getRunningJobLocked();
- if (running != null && !running.isReady()) {
+ if (running == null) {
+ continue;
+ }
+ if (!running.isReady()) {
serviceContext.cancelExecutingJobLocked(
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
"cancelled due to unsatisfied constraints");
+ } else if (isJobThermalConstrainedLocked(running)) {
+ serviceContext.cancelExecutingJobLocked(
+ JobParameters.REASON_DEVICE_THERMAL,
+ "cancelled due to thermal condition");
}
}
}
@@ -2084,6 +2128,10 @@
return false;
}
+ if (isJobThermalConstrainedLocked(job)) {
+ return false;
+ }
+
final boolean jobPending = mPendingJobs.contains(job);
final boolean jobActive = isCurrentlyActiveLocked(job);
@@ -3033,6 +3081,9 @@
pw.print(" In parole?: ");
pw.print(mInParole);
pw.println();
+ pw.print(" In thermal throttling?: ");
+ pw.print(mThermalConstraint);
+ pw.println();
pw.println();
pw.println("Started users: " + Arrays.toString(mStartedUsers));
@@ -3208,6 +3259,7 @@
proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT_TIME_MILLIS,
mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME - nowUptime);
proto.write(JobSchedulerServiceDumpProto.IN_PAROLE, mInParole);
+ proto.write(JobSchedulerServiceDumpProto.IN_THERMAL, mThermalConstraint);
for (int u : mStartedUsers) {
proto.write(JobSchedulerServiceDumpProto.STARTED_USERS, u);
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index d32c299..0e195bc 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.os.UserManager;
import android.security.GateKeeper;
+import android.security.Scrypt;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.util.ArrayMap;
@@ -1173,11 +1174,10 @@
}
protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
- return nativeScrypt(password.getBytes(), salt, N, r, p, outLen);
+ return new Scrypt().scrypt(password.getBytes(), salt, N, r, p, outLen);
}
native long nativeSidFromPasswordHandle(byte[] handle);
- native byte[] nativeScrypt(byte[] password, byte[] salt, int N, int r, int p, int outLen);
protected static ArrayList<Byte> toByteArrayList(byte[] data) {
ArrayList<Byte> result = new ArrayList<Byte>(data.length);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 8ce3838..8711ddf 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -156,21 +156,16 @@
@MainThread
private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
RoleUserState userState;
- synchronized (mLock) {
- userState = getUserStateLocked(userId);
- }
+ userState = getOrCreateUserState(userId);
String packagesHash = computeComponentStateHash(userId);
- String oldPackagesHash;
- synchronized (mLock) {
- oldPackagesHash = userState.getPackagesHashLocked();
- }
+ String oldPackagesHash = userState.getPackagesHash();
boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
if (needGrant) {
// Some vital packages state has changed since last role grant
// Run grants again
Slog.i(LOG_TAG, "Granting default permissions...");
CompletableFuture<Void> result = new CompletableFuture<>();
- getControllerService(userId).onGrantDefaultRoles(
+ getOrCreateControllerService(userId).onGrantDefaultRoles(
new IRoleManagerCallback.Stub() {
@Override
public void onSuccess() {
@@ -183,9 +178,7 @@
});
try {
result.get(5, TimeUnit.SECONDS);
- synchronized (mLock) {
- userState.setPackagesHashLocked(packagesHash);
- }
+ userState.setPackagesHash(packagesHash);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e);
}
@@ -225,35 +218,38 @@
return PackageUtils.computeSha256Digest(out.toByteArray());
}
- @GuardedBy("mLock")
@NonNull
- private RoleUserState getUserStateLocked(@UserIdInt int userId) {
- RoleUserState userState = mUserStates.get(userId);
- if (userState == null) {
- userState = RoleUserState.newInstanceLocked(userId);
- mUserStates.put(userId, userState);
+ private RoleUserState getOrCreateUserState(@UserIdInt int userId) {
+ synchronized (mLock) {
+ RoleUserState userState = mUserStates.get(userId);
+ if (userState == null) {
+ userState = new RoleUserState(userId);
+ mUserStates.put(userId, userState);
+ }
+ return userState;
}
- return userState;
}
- @GuardedBy("mLock")
@NonNull
- private RemoteRoleControllerService getControllerService(@UserIdInt int userId) {
- RemoteRoleControllerService controllerService = mControllerServices.get(userId);
- if (controllerService == null) {
- controllerService = new RemoteRoleControllerService(userId, getContext());
- mControllerServices.put(userId, controllerService);
+ private RemoteRoleControllerService getOrCreateControllerService(@UserIdInt int userId) {
+ synchronized (mLock) {
+ RemoteRoleControllerService controllerService = mControllerServices.get(userId);
+ if (controllerService == null) {
+ controllerService = new RemoteRoleControllerService(userId, getContext());
+ mControllerServices.put(userId, controllerService);
+ }
+ return controllerService;
}
- return controllerService;
}
private void onRemoveUser(@UserIdInt int userId) {
+ RoleUserState userState;
synchronized (mLock) {
mControllerServices.remove(userId);
- RoleUserState userState = mUserStates.removeReturnOld(userId);
- if (userState != null) {
- userState.destroyLocked();
- }
+ userState = mUserStates.removeReturnOld(userId);
+ }
+ if (userState != null) {
+ userState.destroy();
}
}
@@ -264,10 +260,8 @@
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
int userId = UserHandle.getUserId(getCallingUid());
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- return userState.isRoleAvailableLocked(roleName);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ return userState.isRoleAvailable(roleName);
}
@Override
@@ -307,10 +301,8 @@
@Nullable
private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName,
@UserIdInt int userId) {
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- return userState.getRoleHoldersLocked(roleName);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ return userState.getRoleHolders(roleName);
}
@Override
@@ -327,7 +319,7 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"addRoleHolderAsUser");
- getControllerService(userId).onAddRoleHolder(roleName, packageName, callback);
+ getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, callback);
}
@Override
@@ -344,7 +336,7 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"removeRoleHolderAsUser");
- getControllerService(userId).onRemoveRoleHolder(roleName, packageName,
+ getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName,
callback);
}
@@ -361,7 +353,7 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"clearRoleHoldersAsUser");
- getControllerService(userId).onClearRoleHolders(roleName, callback);
+ getOrCreateControllerService(userId).onClearRoleHolders(roleName, callback);
}
@Override
@@ -372,10 +364,8 @@
"setRoleNamesFromController");
int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- userState.setRoleNamesLocked(roleNames);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ userState.setRoleNames(roleNames);
}
@Override
@@ -388,10 +378,8 @@
"addRoleHolderFromController");
int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- return userState.addRoleHolderLocked(roleName, packageName);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ return userState.addRoleHolder(roleName, packageName);
}
@Override
@@ -404,10 +392,8 @@
"removeRoleHolderFromController");
int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- return userState.removeRoleHolderLocked(roleName, packageName);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ return userState.removeRoleHolder(roleName, packageName);
}
@CheckResult
@@ -440,16 +426,14 @@
dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " "));
}
- synchronized (mLock) {
- int[] userIds = mUserManagerInternal.getUserIds();
- int userIdsLength = userIds.length;
- for (int i = 0; i < userIdsLength; i++) {
- int userId = userIds[i];
+ int[] userIds = mUserManagerInternal.getUserIds();
+ int userIdsLength = userIds.length;
+ for (int i = 0; i < userIdsLength; i++) {
+ int userId = userIds[i];
- RoleUserState userState = getUserStateLocked(userId);
- userState.dumpLocked(dumpOutputStream, "user_states",
- RoleManagerServiceDumpProto.USER_STATES);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ userState.dump(dumpOutputStream, "user_states",
+ RoleManagerServiceDumpProto.USER_STATES);
}
dumpOutputStream.flush();
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 327debf..81adb11 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -74,54 +74,51 @@
@UserIdInt
private final int mUserId;
- @GuardedBy("RoleManagerService.mLock")
+ @NonNull
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
private int mVersion = VERSION_UNDEFINED;
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
@Nullable
private String mPackagesHash;
/**
* Maps role names to its holders' package names. The values should never be null.
*/
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
@NonNull
private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>();
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
private long mWritePendingSinceMillis;
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
private boolean mDestroyed;
@NonNull
private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper());
- private RoleUserState(@UserIdInt int userId) {
- mUserId = userId;
-
- readLocked();
- }
-
/**
* Create a new instance of user state, and read its state from disk if previously persisted.
*
* @param userId the user id for the new user state
- *
- * @return the new user state
*/
- @GuardedBy("RoleManagerService.mLock")
- public static RoleUserState newInstanceLocked(@UserIdInt int userId) {
- return new RoleUserState(userId);
+ public RoleUserState(@UserIdInt int userId) {
+ mUserId = userId;
+
+ readFile();
}
/**
* Get the version of this user state.
*/
- @GuardedBy("RoleManagerService.mLock")
- public int getVersionLocked() {
- throwIfDestroyedLocked();
- return mVersion;
+ public int getVersion() {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ return mVersion;
+ }
}
/**
@@ -129,14 +126,15 @@
*
* @param version the version to set
*/
- @GuardedBy("RoleManagerService.mLock")
- public void setVersionLocked(int version) {
- throwIfDestroyedLocked();
- if (mVersion == version) {
- return;
+ public void setVersion(int version) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mVersion == version) {
+ return;
+ }
+ mVersion = version;
+ scheduleWriteFileLocked();
}
- mVersion = version;
- writeAsyncLocked();
}
/**
@@ -144,9 +142,11 @@
*
* @return the hash representing the state of packages
*/
- @GuardedBy("RoleManagerService.mLock")
- public String getPackagesHashLocked() {
- return mPackagesHash;
+ @Nullable
+ public String getPackagesHash() {
+ synchronized (mLock) {
+ return mPackagesHash;
+ }
}
/**
@@ -154,14 +154,15 @@
*
* @param packagesHash the hash representing the state of packages
*/
- @GuardedBy("RoleManagerService.mLock")
- public void setPackagesHashLocked(@Nullable String packagesHash) {
- throwIfDestroyedLocked();
- if (Objects.equals(mPackagesHash, packagesHash)) {
- return;
+ public void setPackagesHash(@Nullable String packagesHash) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (Objects.equals(mPackagesHash, packagesHash)) {
+ return;
+ }
+ mPackagesHash = packagesHash;
+ scheduleWriteFileLocked();
}
- mPackagesHash = packagesHash;
- writeAsyncLocked();
}
/**
@@ -171,10 +172,11 @@
*
* @return whether the role is available
*/
- @GuardedBy("RoleManagerService.mLock")
- public boolean isRoleAvailableLocked(@NonNull String roleName) {
- throwIfDestroyedLocked();
- return mRoles.containsKey(roleName);
+ public boolean isRoleAvailable(@NonNull String roleName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ return mRoles.containsKey(roleName);
+ }
}
/**
@@ -184,11 +186,12 @@
*
* @return the set of role holders. {@code null} should not be returned and indicates an issue.
*/
- @GuardedBy("RoleManagerService.mLock")
@Nullable
- public ArraySet<String> getRoleHoldersLocked(@NonNull String roleName) {
- throwIfDestroyedLocked();
- return mRoles.get(roleName);
+ public ArraySet<String> getRoleHolders(@NonNull String roleName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ return new ArraySet<>(mRoles.get(roleName));
+ }
}
/**
@@ -196,33 +199,35 @@
*
* @param roleNames the names of all the available roles
*/
- @GuardedBy("RoleManagerService.mLock")
- public void setRoleNamesLocked(@NonNull List<String> roleNames) {
- throwIfDestroyedLocked();
- boolean changed = false;
- for (int i = mRoles.size() - 1; i >= 0; i--) {
- String roleName = mRoles.keyAt(i);
- if (!roleNames.contains(roleName)) {
- ArraySet<String> packageNames = mRoles.valueAt(i);
- if (!packageNames.isEmpty()) {
- Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up, role: "
- + roleName + ", holders: " + packageNames);
+ public void setRoleNames(@NonNull List<String> roleNames) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ boolean changed = false;
+ for (int i = mRoles.size() - 1; i >= 0; i--) {
+ String roleName = mRoles.keyAt(i);
+ if (!roleNames.contains(roleName)) {
+ ArraySet<String> packageNames = mRoles.valueAt(i);
+ if (!packageNames.isEmpty()) {
+ Slog.e(LOG_TAG,
+ "Holders of a removed role should have been cleaned up, role: "
+ + roleName + ", holders: " + packageNames);
+ }
+ mRoles.removeAt(i);
+ changed = true;
}
- mRoles.removeAt(i);
- changed = true;
}
- }
- int roleNamesSize = roleNames.size();
- for (int i = 0; i < roleNamesSize; i++) {
- String roleName = roleNames.get(i);
- if (!mRoles.containsKey(roleName)) {
- mRoles.put(roleName, new ArraySet<>());
- Slog.i(LOG_TAG, "Added new role: " + roleName);
- changed = true;
+ int roleNamesSize = roleNames.size();
+ for (int i = 0; i < roleNamesSize; i++) {
+ String roleName = roleNames.get(i);
+ if (!mRoles.containsKey(roleName)) {
+ mRoles.put(roleName, new ArraySet<>());
+ Slog.i(LOG_TAG, "Added new role: " + roleName);
+ changed = true;
+ }
}
- }
- if (changed) {
- writeAsyncLocked();
+ if (changed) {
+ scheduleWriteFileLocked();
+ }
}
}
@@ -236,20 +241,21 @@
* indicates an issue.
*/
@CheckResult
- @GuardedBy("RoleManagerService.mLock")
- public boolean addRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) {
- throwIfDestroyedLocked();
- ArraySet<String> roleHolders = mRoles.get(roleName);
- if (roleHolders == null) {
- Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
- + ", package: " + packageName);
- return false;
+ public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ ArraySet<String> roleHolders = mRoles.get(roleName);
+ if (roleHolders == null) {
+ Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
+ + ", package: " + packageName);
+ return false;
+ }
+ boolean changed = roleHolders.add(packageName);
+ if (changed) {
+ scheduleWriteFileLocked();
+ }
+ return true;
}
- boolean changed = roleHolders.add(packageName);
- if (changed) {
- writeAsyncLocked();
- }
- return true;
}
/**
@@ -262,38 +268,30 @@
* indicates an issue.
*/
@CheckResult
- @GuardedBy("RoleManagerService.mLock")
- public boolean removeRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) {
- throwIfDestroyedLocked();
- ArraySet<String> roleHolders = mRoles.get(roleName);
- if (roleHolders == null) {
- Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
- + ", package: " + packageName);
- return false;
+ public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ ArraySet<String> roleHolders = mRoles.get(roleName);
+ if (roleHolders == null) {
+ Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
+ + ", package: " + packageName);
+ return false;
+ }
+ boolean changed = roleHolders.remove(packageName);
+ if (changed) {
+ scheduleWriteFileLocked();
+ }
+ return true;
}
- boolean changed = roleHolders.remove(packageName);
- if (changed) {
- writeAsyncLocked();
- }
- return true;
}
/**
* Schedule writing the state to file.
*/
- @GuardedBy("RoleManagerService.mLock")
- private void writeAsyncLocked() {
+ @GuardedBy("mLock")
+ private void scheduleWriteFileLocked() {
throwIfDestroyedLocked();
- ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
- for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
- String roleName = mRoles.keyAt(i);
- ArraySet<String> roleHolders = mRoles.valueAt(i);
-
- roleHolders = new ArraySet<>(roleHolders);
- roles.put(roleName, roleHolders);
- }
-
long currentTimeMillis = System.currentTimeMillis();
long writeDelayMillis;
if (!mWriteHandler.hasMessagesOrCallbacks()) {
@@ -311,14 +309,26 @@
}
}
- mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this,
- mVersion, mPackagesHash, roles), writeDelayMillis);
+ mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeFile, this),
+ writeDelayMillis);
Slog.i(LOG_TAG, "Scheduled writing roles.xml");
}
@WorkerThread
- private void writeSync(int version, @Nullable String packagesHash,
- @NonNull ArrayMap<String, ArraySet<String>> roles) {
+ private void writeFile() {
+ int version;
+ String packagesHash;
+ ArrayMap<String, ArraySet<String>> roles;
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+
+ version = mVersion;
+ packagesHash = mPackagesHash;
+ roles = snapshotRolesLocked();
+ }
+
AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId);
FileOutputStream out = null;
try {
@@ -385,18 +395,19 @@
/**
* Read the state from file.
*/
- @GuardedBy("RoleManagerService.mLock")
- private void readLocked() {
- File file = getFile(mUserId);
- try (FileInputStream in = new AtomicFile(file).openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
- parseXmlLocked(parser);
- Slog.i(LOG_TAG, "Read roles.xml successfully");
- } catch (FileNotFoundException e) {
- Slog.i(LOG_TAG, "roles.xml not found");
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed to parse roles.xml: " + file, e);
+ private void readFile() {
+ synchronized (mLock) {
+ File file = getFile(mUserId);
+ try (FileInputStream in = new AtomicFile(file).openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parseXmlLocked(parser);
+ Slog.i(LOG_TAG, "Read roles.xml successfully");
+ } catch (FileNotFoundException e) {
+ Slog.i(LOG_TAG, "roles.xml not found");
+ } catch (XmlPullParserException | IOException e) {
+ throw new IllegalStateException("Failed to parse roles.xml: " + file, e);
+ }
}
}
@@ -470,20 +481,28 @@
*
* @param dumpOutputStream the output stream to dump to
*/
- @GuardedBy("RoleManagerService.mLock")
- public void dumpLocked(@NonNull DualDumpOutputStream dumpOutputStream,
- @NonNull String fieldName, long fieldId) {
- throwIfDestroyedLocked();
+ public void dump(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName,
+ long fieldId) {
+ int version;
+ String packagesHash;
+ ArrayMap<String, ArraySet<String>> roles;
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+
+ version = mVersion;
+ packagesHash = mPackagesHash;
+ roles = snapshotRolesLocked();
+ }
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
dumpOutputStream.write("user_id", RoleUserStateProto.USER_ID, mUserId);
- dumpOutputStream.write("version", RoleUserStateProto.VERSION, mVersion);
- dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, mPackagesHash);
+ dumpOutputStream.write("version", RoleUserStateProto.VERSION, version);
+ dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, packagesHash);
- int rolesSize = mRoles.size();
+ int rolesSize = roles.size();
for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) {
- String roleName = mRoles.keyAt(rolesIndex);
- ArraySet<String> roleHolders = mRoles.valueAt(rolesIndex);
+ String roleName = roles.keyAt(rolesIndex);
+ ArraySet<String> roleHolders = roles.valueAt(rolesIndex);
long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES);
dumpOutputStream.write("name", RoleProto.NAME, roleName);
@@ -501,19 +520,33 @@
dumpOutputStream.end(fieldToken);
}
+ @GuardedBy("mLock")
+ private ArrayMap<String, ArraySet<String>> snapshotRolesLocked() {
+ ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
+ for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
+ String roleName = mRoles.keyAt(i);
+ ArraySet<String> roleHolders = mRoles.valueAt(i);
+
+ roleHolders = new ArraySet<>(roleHolders);
+ roles.put(roleName, roleHolders);
+ }
+ return roles;
+ }
+
/**
* Destroy this state and delete the corresponding file. Any pending writes to the file will be
* cancelled and any future interaction with this state will throw an exception.
*/
- @GuardedBy("RoleManagerService.mLock")
- public void destroyLocked() {
- throwIfDestroyedLocked();
- mWriteHandler.removeCallbacksAndMessages(null);
- getFile(mUserId).delete();
- mDestroyed = true;
+ public void destroy() {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mWriteHandler.removeCallbacksAndMessages(null);
+ getFile(mUserId).delete();
+ mDestroyed = true;
+ }
}
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
private void throwIfDestroyedLocked() {
if (mDestroyed) {
throw new IllegalStateException("This RoleUserState has already been destroyed");
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index b85489a..6d72191 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -126,7 +126,6 @@
static_libs: [
"android.hardware.broadcastradio@common-utils-1x-lib",
- "libscrypt_static",
],
product_variables: {
diff --git a/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp b/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
index bc13fde..9dd6032 100644
--- a/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
+++ b/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
@@ -27,10 +27,6 @@
#include <gatekeeper/password_handle.h>
-extern "C" {
-#include "crypto_scrypt.h"
-}
-
namespace android {
static jlong android_server_SyntheticPasswordManager_nativeSidFromPasswordHandle(JNIEnv* env, jobject, jbyteArray handleArray) {
@@ -48,38 +44,9 @@
}
}
-static jbyteArray android_server_SyntheticPasswordManager_nativeScrypt(JNIEnv* env, jobject, jbyteArray password, jbyteArray salt, jint N, jint r, jint p, jint outLen) {
- if (!password || !salt) {
- return NULL;
- }
-
- int passwordLen = env->GetArrayLength(password);
- int saltLen = env->GetArrayLength(salt);
- jbyteArray ret = env->NewByteArray(outLen);
-
- jbyte* passwordPtr = (jbyte*)env->GetByteArrayElements(password, NULL);
- jbyte* saltPtr = (jbyte*)env->GetByteArrayElements(salt, NULL);
- jbyte* retPtr = (jbyte*)env->GetByteArrayElements(ret, NULL);
-
- int rc = crypto_scrypt((const uint8_t *)passwordPtr, passwordLen,
- (const uint8_t *)saltPtr, saltLen, N, r, p, (uint8_t *)retPtr,
- outLen);
- env->ReleaseByteArrayElements(password, passwordPtr, JNI_ABORT);
- env->ReleaseByteArrayElements(salt, saltPtr, JNI_ABORT);
- env->ReleaseByteArrayElements(ret, retPtr, 0);
-
- if (!rc) {
- return ret;
- } else {
- SLOGE("scrypt failed");
- return NULL;
- }
-}
-
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"nativeSidFromPasswordHandle", "([B)J", (void*)android_server_SyntheticPasswordManager_nativeSidFromPasswordHandle},
- {"nativeScrypt", "([B[BIIII)[B", (void*)android_server_SyntheticPasswordManager_nativeScrypt},
};
int register_android_server_SyntheticPasswordManager(JNIEnv* env) {