Merge "Merge "Move DhcpServer to NetworkStack app" am: 94e5b22985 am: d495691bd5 am: 4bdc06e174"
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
index 7eef63e..d051ed8 100644
--- a/core/java/android/util/KeyValueListParser.java
+++ b/core/java/android/util/KeyValueListParser.java
@@ -16,7 +16,9 @@
package android.util;
import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
+import java.io.PrintWriter;
import java.time.Duration;
import java.time.format.DateTimeParseException;
@@ -212,4 +214,163 @@
}
return def;
}
+
+ /** Represents an integer config value. */
+ public static class IntValue {
+ private final String mKey;
+ private final int mDefaultValue;
+ private int mValue;
+
+ /** Constructor, initialize with a config key and a default value. */
+ public IntValue(String key, int defaultValue) {
+ mKey = key;
+ mDefaultValue = defaultValue;
+ mValue = mDefaultValue;
+ }
+
+ /** Read a value from {@link KeyValueListParser} */
+ public void parse(KeyValueListParser parser) {
+ mValue = parser.getInt(mKey, mDefaultValue);
+ }
+
+ /** Return the config key. */
+ public String getKey() {
+ return mKey;
+ }
+
+ /** Return the default value. */
+ public int getDefaultValue() {
+ return mDefaultValue;
+ }
+
+ /** Return the actual config value. */
+ public int getValue() {
+ return mValue;
+ }
+
+ /** Overwrites with a value. */
+ public void setValue(int value) {
+ mValue = value;
+ }
+
+ /** Used for dumpsys */
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.print(mKey);
+ pw.print("=");
+ pw.print(mValue);
+ pw.println();
+ }
+
+ /** Used for proto dumpsys */
+ public void dumpProto(ProtoOutputStream proto, long tag) {
+ proto.write(tag, mValue);
+ }
+ }
+
+ /** Represents an long config value. */
+ public static class LongValue {
+ private final String mKey;
+ private final long mDefaultValue;
+ private long mValue;
+
+ /** Constructor, initialize with a config key and a default value. */
+ public LongValue(String key, long defaultValue) {
+ mKey = key;
+ mDefaultValue = defaultValue;
+ mValue = mDefaultValue;
+ }
+
+ /** Read a value from {@link KeyValueListParser} */
+ public void parse(KeyValueListParser parser) {
+ mValue = parser.getLong(mKey, mDefaultValue);
+ }
+
+ /** Return the config key. */
+ public String getKey() {
+ return mKey;
+ }
+
+ /** Return the default value. */
+ public long getDefaultValue() {
+ return mDefaultValue;
+ }
+
+ /** Return the actual config value. */
+ public long getValue() {
+ return mValue;
+ }
+
+ /** Overwrites with a value. */
+ public void setValue(long value) {
+ mValue = value;
+ }
+
+ /** Used for dumpsys */
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.print(mKey);
+ pw.print("=");
+ pw.print(mValue);
+ pw.println();
+ }
+
+ /** Used for proto dumpsys */
+ public void dumpProto(ProtoOutputStream proto, long tag) {
+ proto.write(tag, mValue);
+ }
+ }
+
+ /** Represents an string config value. */
+ public static class StringValue {
+ private final String mKey;
+ private final String mDefaultValue;
+ private String mValue;
+
+ /** Constructor, initialize with a config key and a default value. */
+ public StringValue(String key, String defaultValue) {
+ mKey = key;
+ mDefaultValue = defaultValue;
+ mValue = mDefaultValue;
+ }
+
+ /** Read a value from {@link KeyValueListParser} */
+ public void parse(KeyValueListParser parser) {
+ mValue = parser.getString(mKey, mDefaultValue);
+ }
+
+ /** Return the config key. */
+ public String getKey() {
+ return mKey;
+ }
+
+ /** Return the default value. */
+ public String getDefaultValue() {
+ return mDefaultValue;
+ }
+
+ /** Return the actual config value. */
+ public String getValue() {
+ return mValue;
+ }
+
+ /** Overwrites with a value. */
+ public void setValue(String value) {
+ mValue = value;
+ }
+
+ /** Used for dumpsys */
+ public void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix);
+ pw.print(mKey);
+ pw.print("=");
+ pw.print(mValue);
+ pw.println();
+ }
+
+ /** Used for proto dumpsys */
+ public void dumpProto(ProtoOutputStream proto, long tag) {
+ proto.write(tag, mValue);
+ }
+ }
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index b01117c..d7a2365 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -503,26 +503,46 @@
mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
- // Alarm receivers for scheduled backups & initialization operations
- BroadcastReceiver mRunBackupReceiver = new RunBackupReceiver(this);
+ // Receivers for scheduled backups and transport initialization operations.
+ BroadcastReceiver runBackupReceiver = new RunBackupReceiver(this);
IntentFilter filter = new IntentFilter();
filter.addAction(RUN_BACKUP_ACTION);
- context.registerReceiver(mRunBackupReceiver, filter,
- android.Manifest.permission.BACKUP, null);
+ context.registerReceiverAsUser(
+ runBackupReceiver,
+ UserHandle.of(userId),
+ filter,
+ android.Manifest.permission.BACKUP,
+ /* scheduler */ null);
- BroadcastReceiver mRunInitReceiver = new RunInitializeReceiver(this);
+ BroadcastReceiver runInitReceiver = new RunInitializeReceiver(this);
filter = new IntentFilter();
filter.addAction(RUN_INITIALIZE_ACTION);
- context.registerReceiver(mRunInitReceiver, filter,
- android.Manifest.permission.BACKUP, null);
+ context.registerReceiverAsUser(
+ runInitReceiver,
+ UserHandle.of(userId),
+ filter,
+ android.Manifest.permission.BACKUP,
+ /* scheduler */ null);
Intent backupIntent = new Intent(RUN_BACKUP_ACTION);
backupIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mRunBackupIntent = PendingIntent.getBroadcast(context, 0, backupIntent, 0);
+ mRunBackupIntent =
+ PendingIntent.getBroadcastAsUser(
+ context,
+ /* requestCode */ 0,
+ backupIntent,
+ /* flags */ 0,
+ UserHandle.of(userId));
Intent initIntent = new Intent(RUN_INITIALIZE_ACTION);
initIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mRunInitIntent = PendingIntent.getBroadcast(context, 0, initIntent, 0);
+ mRunInitIntent =
+ PendingIntent.getBroadcastAsUser(
+ context,
+ /* requestCode */ 0,
+ initIntent,
+ /* flags */ 0,
+ UserHandle.of(userId));
// Set up the backup-request journaling
mJournalDir = new File(mBaseStateDir, "pending");
diff --git a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java
index 3b87724..d37b106 100644
--- a/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java
+++ b/services/backup/java/com/android/server/backup/internal/RunBackupReceiver.java
@@ -26,62 +26,84 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.os.Handler;
import android.os.Message;
import android.util.Slog;
import com.android.server.backup.UserBackupManagerService;
+/**
+ * A {@link BroadcastReceiver} for the action {@link UserBackupManagerService#RUN_BACKUP_ACTION}
+ * that runs an immediate backup operation if eligible.
+ */
public class RunBackupReceiver extends BroadcastReceiver {
+ private final UserBackupManagerService mUserBackupManagerService;
- private UserBackupManagerService backupManagerService;
-
- public RunBackupReceiver(UserBackupManagerService backupManagerService) {
- this.backupManagerService = backupManagerService;
+ public RunBackupReceiver(UserBackupManagerService userBackupManagerService) {
+ mUserBackupManagerService = userBackupManagerService;
}
+ /**
+ * Run a backup pass if we're eligible. We're eligible if the following conditions are met:
+ *
+ * <ul>
+ * <li>No transports are pending initialization (otherwise we kick off an initialization
+ * operation instead).
+ * <li>Backup is enabled for the user.
+ * <li>The user has completed setup.
+ * <li>No backup operation is currently running for the user.
+ * </ul>
+ */
public void onReceive(Context context, Intent intent) {
- if (RUN_BACKUP_ACTION.equals(intent.getAction())) {
- synchronized (backupManagerService.getQueueLock()) {
- if (backupManagerService.getPendingInits().size() > 0) {
- // If there are pending init operations, we process those
- // and then settle into the usual periodic backup schedule.
- if (MORE_DEBUG) {
- Slog.v(TAG, "Init pending at scheduled backup");
- }
- try {
- backupManagerService.getAlarmManager().cancel(
- backupManagerService.getRunInitIntent());
- backupManagerService.getRunInitIntent().send();
- } catch (PendingIntent.CanceledException ce) {
- Slog.e(TAG, "Run init intent cancelled");
- // can't really do more than bail here
- }
- } else {
- // Don't run backups now if we're disabled or not yet
- // fully set up.
- if (backupManagerService.isEnabled()
- && backupManagerService.isSetupComplete()) {
- if (!backupManagerService.isBackupRunning()) {
- if (DEBUG) {
- Slog.v(TAG, "Running a backup pass");
- }
+ if (!RUN_BACKUP_ACTION.equals(intent.getAction())) {
+ return;
+ }
- // Acquire the wakelock and pass it to the backup thread. it will
- // be released once backup concludes.
- backupManagerService.setBackupRunning(true);
- backupManagerService.getWakelock().acquire();
-
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
- MSG_RUN_BACKUP);
- backupManagerService.getBackupHandler().sendMessage(msg);
- } else {
- Slog.i(TAG, "Backup time but one already running");
- }
- } else {
- Slog.w(TAG, "Backup pass but enabled=" + backupManagerService.isEnabled()
- + " setupComplete=" + backupManagerService.isSetupComplete());
- }
+ synchronized (mUserBackupManagerService.getQueueLock()) {
+ if (mUserBackupManagerService.getPendingInits().size() > 0) {
+ // If there are pending init operations, we process those and then settle into the
+ // usual periodic backup schedule.
+ if (MORE_DEBUG) {
+ Slog.v(TAG, "Init pending at scheduled backup");
}
+ try {
+ PendingIntent runInitIntent = mUserBackupManagerService.getRunInitIntent();
+ mUserBackupManagerService.getAlarmManager().cancel(runInitIntent);
+ runInitIntent.send();
+ } catch (PendingIntent.CanceledException ce) {
+ Slog.w(TAG, "Run init intent cancelled");
+ }
+ } else {
+ // Don't run backups if we're disabled or not yet set up.
+ if (!mUserBackupManagerService.isEnabled()
+ || !mUserBackupManagerService.isSetupComplete()) {
+ Slog.w(
+ TAG,
+ "Backup pass but enabled="
+ + mUserBackupManagerService.isEnabled()
+ + " setupComplete="
+ + mUserBackupManagerService.isSetupComplete());
+ return;
+ }
+
+ // Don't run backups if one is already running.
+ if (mUserBackupManagerService.isBackupRunning()) {
+ Slog.i(TAG, "Backup time but one already running");
+ return;
+ }
+
+ if (DEBUG) {
+ Slog.v(TAG, "Running a backup pass");
+ }
+
+ // Acquire the wakelock and pass it to the backup thread. It will be released once
+ // backup concludes.
+ mUserBackupManagerService.setBackupRunning(true);
+ mUserBackupManagerService.getWakelock().acquire();
+
+ Handler backupHandler = mUserBackupManagerService.getBackupHandler();
+ Message message = backupHandler.obtainMessage(MSG_RUN_BACKUP);
+ backupHandler.sendMessage(message);
}
}
}
diff --git a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
index 38870cb..97711e3 100644
--- a/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
+++ b/services/backup/java/com/android/server/backup/internal/RunInitializeReceiver.java
@@ -24,41 +24,50 @@
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
-import android.util.ArraySet;
import android.util.Slog;
import com.android.server.backup.UserBackupManagerService;
-public class RunInitializeReceiver extends BroadcastReceiver {
- private final UserBackupManagerService mBackupManagerService;
+import java.util.Set;
- public RunInitializeReceiver(UserBackupManagerService backupManagerService) {
- mBackupManagerService = backupManagerService;
+/**
+ * A {@link BroadcastReceiver} for the action {@link UserBackupManagerService#RUN_INITIALIZE_ACTION}
+ * that runs an initialization operation on all pending transports.
+ */
+public class RunInitializeReceiver extends BroadcastReceiver {
+ private final UserBackupManagerService mUserBackupManagerService;
+
+ public RunInitializeReceiver(UserBackupManagerService userBackupManagerService) {
+ mUserBackupManagerService = userBackupManagerService;
}
public void onReceive(Context context, Intent intent) {
- if (RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
- synchronized (mBackupManagerService.getQueueLock()) {
- final ArraySet<String> pendingInits = mBackupManagerService.getPendingInits();
- if (DEBUG) {
- Slog.v(TAG, "Running a device init; " + pendingInits.size() + " pending");
- }
+ if (!RUN_INITIALIZE_ACTION.equals(intent.getAction())) {
+ return;
+ }
- if (pendingInits.size() > 0) {
- final String[] transports =
- pendingInits.toArray(new String[pendingInits.size()]);
+ synchronized (mUserBackupManagerService.getQueueLock()) {
+ Set<String> pendingInits = mUserBackupManagerService.getPendingInits();
+ if (DEBUG) {
+ Slog.v(TAG, "Running a device init; " + pendingInits.size() + " pending");
+ }
- mBackupManagerService.clearPendingInits();
+ if (pendingInits.size() > 0) {
+ String[] transports = pendingInits.toArray(new String[pendingInits.size()]);
- PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock();
- wakelock.acquire();
- OnTaskFinishedListener listener = caller -> wakelock.release();
+ mUserBackupManagerService.clearPendingInits();
- Runnable task =
- new PerformInitializeTask(
- mBackupManagerService, transports, null, listener);
- mBackupManagerService.getBackupHandler().post(task);
- }
+ PowerManager.WakeLock wakelock = mUserBackupManagerService.getWakelock();
+ wakelock.acquire();
+ OnTaskFinishedListener listener = caller -> wakelock.release();
+
+ Runnable task =
+ new PerformInitializeTask(
+ mUserBackupManagerService,
+ transports,
+ /* observer */ null,
+ listener);
+ mUserBackupManagerService.getBackupHandler().post(task);
}
}
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 3f9d928..2464ca7 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -332,6 +332,44 @@
}
}
+ private static class MaxJobCounts {
+ private final KeyValueListParser.IntValue mTotal;
+ private final KeyValueListParser.IntValue mBg;
+
+ private MaxJobCounts(int totalDefault, String totalKey, int bgDefault, String bgKey) {
+ mTotal = new KeyValueListParser.IntValue(totalKey, totalDefault);
+ mBg = new KeyValueListParser.IntValue(bgKey, bgDefault);
+ }
+
+ public void parse(KeyValueListParser parser) {
+ mTotal.parse(parser);
+ mBg.parse(parser);
+
+ if (mBg.getValue() > mTotal.getValue()) {
+ mBg.setValue(mTotal.getValue());
+ }
+
+ }
+
+ public int getTotalMax() {
+ return mTotal.getValue();
+ }
+
+ public int getBgMax() {
+ return mBg.getValue();
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ mTotal.dump(pw, prefix);
+ mBg.dump(pw, prefix);
+ }
+
+ public void dumpProto(ProtoOutputStream proto, long tagTotal, long tagBg) {
+ mTotal.dumpProto(proto, tagTotal);
+ mBg.dumpProto(proto, tagBg);
+ }
+ }
+
/**
* 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
@@ -492,6 +530,43 @@
* memory state.
*/
int BG_CRITICAL_JOB_COUNT = DEFAULT_BG_CRITICAL_JOB_COUNT;
+
+ // Max job counts for screen on / off, for each memory trim level.
+ // TODO Remove the old configs such as FG_JOB_COUNT and BG_*_COUNT, once the code switches
+ // to the below configs.
+
+ final MaxJobCounts MAX_JOB_COUNTS_ON_NORMAL = new MaxJobCounts(
+ 4, "max_job_total_on_normal",
+ 2, "max_job_bg_on_normal");
+
+ final MaxJobCounts MAX_JOB_COUNTS_ON_MODERATE = new MaxJobCounts(
+ 4, "max_job_total_on_moderate",
+ 1, "max_job_bg_on_moderate");
+
+ final MaxJobCounts MAX_JOB_COUNTS_ON_LOW = new MaxJobCounts(
+ 4, "max_job_total_on_low",
+ 1, "max_job_bg_on_low");
+
+ final MaxJobCounts MAX_JOB_COUNTS_ON_CRITICAL = new MaxJobCounts(
+ 2, "max_job_total_on_critical",
+ 1, "max_job_bg_on_critical");
+
+ final MaxJobCounts MAX_JOB_COUNTS_OFF_NORMAL = new MaxJobCounts(
+ 8, "max_job_total_off_normal",
+ 4, "max_job_bg_off_normal");
+
+ final MaxJobCounts MAX_JOB_COUNTS_OFF_MODERATE = new MaxJobCounts(
+ 6, "max_job_total_off_moderate",
+ 4, "max_job_bg_off_moderate");
+
+ final MaxJobCounts MAX_JOB_COUNTS_OFF_LOW = new MaxJobCounts(
+ 4, "max_job_total_off_low",
+ 1, "max_job_bg_off_low");
+
+ final MaxJobCounts MAX_JOB_COUNTS_OFF_CRITICAL = new MaxJobCounts(
+ 2, "max_job_total_off_critical",
+ 1, "max_job_bg_off_critical");
+
/**
* The maximum number of times we allow a job to have itself rescheduled before
* giving up on it, for standard jobs.
@@ -566,7 +641,7 @@
/**
* The quota window size of the particular standby bucket. Apps in this standby bucket are
- * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
* WINDOW_SIZE_MS.
*/
public long QUOTA_CONTROLLER_WINDOW_SIZE_ACTIVE_MS =
@@ -574,7 +649,7 @@
/**
* The quota window size of the particular standby bucket. Apps in this standby bucket are
- * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
* WINDOW_SIZE_MS.
*/
public long QUOTA_CONTROLLER_WINDOW_SIZE_WORKING_MS =
@@ -582,7 +657,7 @@
/**
* The quota window size of the particular standby bucket. Apps in this standby bucket are
- * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
* WINDOW_SIZE_MS.
*/
public long QUOTA_CONTROLLER_WINDOW_SIZE_FREQUENT_MS =
@@ -590,7 +665,7 @@
/**
* The quota window size of the particular standby bucket. Apps in this standby bucket are
- * expected to run only {@link QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
+ * expected to run only {@link #QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS} within the past
* WINDOW_SIZE_MS.
*/
public long QUOTA_CONTROLLER_WINDOW_SIZE_RARE_MS =
@@ -653,6 +728,17 @@
if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
}
+
+ MAX_JOB_COUNTS_ON_NORMAL.parse(mParser);
+ MAX_JOB_COUNTS_ON_MODERATE.parse(mParser);
+ MAX_JOB_COUNTS_ON_LOW.parse(mParser);
+ MAX_JOB_COUNTS_ON_CRITICAL.parse(mParser);
+
+ MAX_JOB_COUNTS_OFF_NORMAL.parse(mParser);
+ MAX_JOB_COUNTS_OFF_MODERATE.parse(mParser);
+ MAX_JOB_COUNTS_OFF_LOW.parse(mParser);
+ MAX_JOB_COUNTS_OFF_CRITICAL.parse(mParser);
+
MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
@@ -717,6 +803,17 @@
pw.printPair(KEY_BG_MODERATE_JOB_COUNT, BG_MODERATE_JOB_COUNT).println();
pw.printPair(KEY_BG_LOW_JOB_COUNT, BG_LOW_JOB_COUNT).println();
pw.printPair(KEY_BG_CRITICAL_JOB_COUNT, BG_CRITICAL_JOB_COUNT).println();
+
+ MAX_JOB_COUNTS_ON_NORMAL.dump(pw, "");
+ MAX_JOB_COUNTS_ON_MODERATE.dump(pw, "");
+ MAX_JOB_COUNTS_ON_LOW.dump(pw, "");
+ MAX_JOB_COUNTS_ON_CRITICAL.dump(pw, "");
+
+ MAX_JOB_COUNTS_OFF_NORMAL.dump(pw, "");
+ MAX_JOB_COUNTS_OFF_MODERATE.dump(pw, "");
+ MAX_JOB_COUNTS_OFF_LOW.dump(pw, "");
+ MAX_JOB_COUNTS_OFF_CRITICAL.dump(pw, "");
+
pw.printPair(KEY_MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT).println();
pw.printPair(KEY_MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT).println();
pw.printPair(KEY_MIN_LINEAR_BACKOFF_TIME, MIN_LINEAR_BACKOFF_TIME).println();
@@ -767,6 +864,9 @@
proto.write(ConstantsProto.BG_MODERATE_JOB_COUNT, BG_MODERATE_JOB_COUNT);
proto.write(ConstantsProto.BG_LOW_JOB_COUNT, BG_LOW_JOB_COUNT);
proto.write(ConstantsProto.BG_CRITICAL_JOB_COUNT, BG_CRITICAL_JOB_COUNT);
+
+ // TODO Dump max job counts.
+
proto.write(ConstantsProto.MAX_STANDARD_RESCHEDULE_COUNT, MAX_STANDARD_RESCHEDULE_COUNT);
proto.write(ConstantsProto.MAX_WORK_RESCHEDULE_COUNT, MAX_WORK_RESCHEDULE_COUNT);
proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME);