diff options
5 files changed, 391 insertions, 79 deletions
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java index 7eef63efd14d..d051ed84dd7c 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 @@ public class KeyValueListParser { } 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 b01117c438f0..d7a23650d811 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 @@ public class UserBackupManagerService { 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); - - BroadcastReceiver mRunInitReceiver = new RunInitializeReceiver(this); + context.registerReceiverAsUser( + runBackupReceiver, + UserHandle.of(userId), + filter, + android.Manifest.permission.BACKUP, + /* scheduler */ null); + + 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 3b877241f7f4..d37b106c2b26 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.app.PendingIntent; 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; + } + + 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; + } - // Acquire the wakelock and pass it to the backup thread. it will - // be released once backup concludes. - backupManagerService.setBackupRunning(true); - backupManagerService.getWakelock().acquire(); + // Don't run backups if one is already running. + if (mUserBackupManagerService.isBackupRunning()) { + Slog.i(TAG, "Backup time but one already running"); + return; + } - 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()); - } + 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 38870cba4812..97711e3c27ed 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.BroadcastReceiver; 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; +import java.util.Set; + +/** + * 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 mBackupManagerService; + private final UserBackupManagerService mUserBackupManagerService; - public RunInitializeReceiver(UserBackupManagerService backupManagerService) { - mBackupManagerService = backupManagerService; + 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; + } + + synchronized (mUserBackupManagerService.getQueueLock()) { + Set<String> pendingInits = mUserBackupManagerService.getPendingInits(); + if (DEBUG) { + Slog.v(TAG, "Running a device init; " + pendingInits.size() + " pending"); + } - if (pendingInits.size() > 0) { - final String[] transports = - pendingInits.toArray(new String[pendingInits.size()]); + if (pendingInits.size() > 0) { + String[] transports = pendingInits.toArray(new String[pendingInits.size()]); - mBackupManagerService.clearPendingInits(); + mUserBackupManagerService.clearPendingInits(); - PowerManager.WakeLock wakelock = mBackupManagerService.getWakelock(); - wakelock.acquire(); - OnTaskFinishedListener listener = caller -> wakelock.release(); + PowerManager.WakeLock wakelock = mUserBackupManagerService.getWakelock(); + wakelock.acquire(); + OnTaskFinishedListener listener = caller -> wakelock.release(); - Runnable task = - new PerformInitializeTask( - mBackupManagerService, transports, null, listener); - mBackupManagerService.getBackupHandler().post(task); - } + 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 3f9d928e1986..2464ca782b6e 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 @@ public class JobSchedulerService extends com.android.server.SystemService } } + 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 @@ public class JobSchedulerService extends com.android.server.SystemService * 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 @@ public class JobSchedulerService extends com.android.server.SystemService /** * 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 @@ public class JobSchedulerService extends com.android.server.SystemService /** * 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 @@ public class JobSchedulerService extends com.android.server.SystemService /** * 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 @@ public class JobSchedulerService extends com.android.server.SystemService /** * 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 @@ public class JobSchedulerService extends com.android.server.SystemService 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 @@ public class JobSchedulerService extends com.android.server.SystemService 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 @@ public class JobSchedulerService extends com.android.server.SystemService 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); |