diff options
| author | 2018-02-23 16:26:29 +0000 | |
|---|---|---|
| committer | 2018-02-23 16:26:29 +0000 | |
| commit | f6ff0f88eed8fa3b1e12bb6d95fe2c7ca625330c (patch) | |
| tree | 77f986a7448f18fbdd7fb9092e2b986735f69fb1 | |
| parent | d0f119f8c7508be1556f3b3dedb0c974ac6209e0 (diff) | |
| parent | ac2e8efa4395d30ebeda5885dcb7cb679f793d4c (diff) | |
Merge changes Icdb40ee3,I4c239844
* changes:
Knobs for connectivity experiments.
Mechanical refactoring to improve job dumping.
18 files changed, 557 insertions, 677 deletions
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java index 696667c6202b..e453866b05af 100644 --- a/core/java/com/android/internal/util/IndentingPrintWriter.java +++ b/core/java/com/android/internal/util/IndentingPrintWriter.java @@ -57,26 +57,46 @@ public class IndentingPrintWriter extends PrintWriter { mWrapLength = wrapLength; } - public void increaseIndent() { + public IndentingPrintWriter setIndent(String indent) { + mIndentBuilder.setLength(0); + mIndentBuilder.append(indent); + mCurrentIndent = null; + return this; + } + + public IndentingPrintWriter setIndent(int indent) { + mIndentBuilder.setLength(0); + for (int i = 0; i < indent; i++) { + increaseIndent(); + } + return this; + } + + public IndentingPrintWriter increaseIndent() { mIndentBuilder.append(mSingleIndent); mCurrentIndent = null; + return this; } - public void decreaseIndent() { + public IndentingPrintWriter decreaseIndent() { mIndentBuilder.delete(0, mSingleIndent.length()); mCurrentIndent = null; + return this; } - public void printPair(String key, Object value) { + public IndentingPrintWriter printPair(String key, Object value) { print(key + "=" + String.valueOf(value) + " "); + return this; } - public void printPair(String key, Object[] value) { + public IndentingPrintWriter printPair(String key, Object[] value) { print(key + "=" + Arrays.toString(value) + " "); + return this; } - public void printHexPair(String key, int value) { + public IndentingPrintWriter printHexPair(String key, int value) { print(key + "=0x" + Integer.toHexString(value) + " "); + return this; } @Override diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 304e63f28151..2d31c5ad6696 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -201,6 +201,12 @@ message ConstantsProto { // be indices into this array, rather than the raw constants used by // AppIdleHistory. repeated int32 standby_beats = 20; + // The fraction of a job's running window that must pass before we + // consider running it when the network is congested. + optional double conn_congestion_delay_frac = 21; + // The fraction of a prefetch job's running window that must pass before + // we consider matching it against a metered network. + optional double conn_prefetch_relax_frac = 22; } message StateControllerProto { diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java index 9b29b3212b44..fc4d4638491f 100644 --- a/services/core/java/com/android/server/AppStateTracker.java +++ b/services/core/java/com/android/server/AppStateTracker.java @@ -53,6 +53,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage; import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages; @@ -1182,72 +1183,67 @@ public class AppStateTracker { } } - public void dump(PrintWriter pw, String indent) { + @Deprecated + public void dump(PrintWriter pw, String prefix) { + dump(new IndentingPrintWriter(pw, " ").setIndent(prefix)); + } + + public void dump(IndentingPrintWriter pw) { synchronized (mLock) { - pw.print(indent); pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled); - pw.print(indent); pw.print("Force all apps standby: "); pw.println(isForceAllAppsStandbyEnabled()); - pw.print(indent); pw.print("Small Battery Device: "); pw.println(isSmallBatteryDevice()); - pw.print(indent); pw.print("Force all apps standby for small battery device: "); pw.println(mForceAllAppStandbyForSmallBattery); - pw.print(indent); pw.print("Plugged In: "); pw.println(mIsPluggedIn); - pw.print(indent); pw.print("Active uids: "); dumpUids(pw, mActiveUids); - pw.print(indent); pw.print("Foreground uids: "); dumpUids(pw, mForegroundUids); - pw.print(indent); pw.print("Whitelist appids: "); pw.println(Arrays.toString(mPowerWhitelistedAllAppIds)); - pw.print(indent); pw.print("Temp whitelist appids: "); pw.println(Arrays.toString(mTempWhitelistedAppIds)); - pw.print(indent); pw.println("Exempted packages:"); + pw.increaseIndent(); for (int i = 0; i < mExemptedPackages.size(); i++) { - pw.print(indent); - pw.print(" User "); + pw.print("User "); pw.print(mExemptedPackages.keyAt(i)); pw.println(); + pw.increaseIndent(); for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) { - pw.print(indent); - pw.print(" "); pw.print(mExemptedPackages.valueAt(i, j)); pw.println(); } + pw.decreaseIndent(); } + pw.decreaseIndent(); pw.println(); - pw.print(indent); pw.println("Restricted packages:"); + pw.increaseIndent(); for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) { - pw.print(indent); - pw.print(" "); pw.print(UserHandle.formatUid(uidAndPackage.first)); pw.print(" "); pw.print(uidAndPackage.second); pw.println(); } + pw.decreaseIndent(); - mStatLogger.dump(pw, indent); + mStatLogger.dump(pw); } } diff --git a/services/core/java/com/android/server/StatLogger.java b/services/core/java/com/android/server/StatLogger.java index 0e6f5e2338c7..d85810d31e73 100644 --- a/services/core/java/com/android/server/StatLogger.java +++ b/services/core/java/com/android/server/StatLogger.java @@ -21,6 +21,7 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.StatLoggerProto.Event; import java.io.PrintWriter; @@ -78,19 +79,23 @@ public class StatLogger { } } + @Deprecated public void dump(PrintWriter pw, String prefix) { + dump(new IndentingPrintWriter(pw, " ").setIndent(prefix)); + } + + public void dump(IndentingPrintWriter pw) { synchronized (mLock) { - pw.print(prefix); pw.println("Stats:"); + pw.increaseIndent(); for (int i = 0; i < SIZE; i++) { - pw.print(prefix); - pw.print(" "); final int count = mCountStats[i]; final double durationMs = mDurationStats[i] / 1000.0; pw.println(String.format("%s: count=%d, total=%.1fms, avg=%.3fms", mLabels[i], count, durationMs, (count == 0 ? 0 : ((double) durationMs) / count))); } + pw.decreaseIndent(); } } diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index f3f4dfda82c8..740866c9aec3 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -79,6 +79,7 @@ import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.AppStateTracker; import com.android.server.DeviceIdleController; @@ -86,7 +87,6 @@ import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob; import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob; -import com.android.server.job.JobStore.JobStatusFunctor; import com.android.server.job.controllers.AppIdleController; import com.android.server.job.controllers.BackgroundJobsController; import com.android.server.job.controllers.BatteryController; @@ -110,6 +110,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.function.Consumer; import java.util.function.Predicate; /** @@ -163,15 +164,16 @@ public final class JobSchedulerService extends com.android.server.SystemService * {@link JobStatus#getServiceToken()} */ final List<JobServiceContext> mActiveServices = new ArrayList<>(); + /** List of controllers that will notify this service of updates to jobs. */ - List<StateController> mControllers; + private final List<StateController> mControllers; /** Need direct access to this for testing. */ - BatteryController mBatteryController; + private final BatteryController mBatteryController; /** Need direct access to this for testing. */ - StorageController mStorageController; + private final StorageController mStorageController; /** Need directly for sending uid state changes */ - private BackgroundJobsController mBackgroundJobsController; - private DeviceIdleJobsController mDeviceIdleJobsController; + private final DeviceIdleJobsController mDeviceIdleJobsController; + /** * Queue of pending jobs. The JobServiceContext class will receive jobs from this list * when ready to execute them. @@ -253,12 +255,48 @@ public final class JobSchedulerService extends com.android.server.SystemService */ int[] mTmpAssignPreferredUidForContext = new int[MAX_JOB_CONTEXTS_COUNT]; + private class ConstantsObserver extends ContentObserver { + private ContentResolver mResolver; + + public ConstantsObserver(Handler handler) { + super(handler); + } + + public void start(ContentResolver resolver) { + mResolver = resolver; + mResolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.JOB_SCHEDULER_CONSTANTS), false, this); + updateConstants(); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + updateConstants(); + } + + private void updateConstants() { + synchronized (mLock) { + try { + mConstants.updateConstantsLocked(Settings.Global.getString(mResolver, + Settings.Global.JOB_SCHEDULER_CONSTANTS)); + } catch (IllegalArgumentException e) { + // Failed to parse the settings string, log this and move on + // with defaults. + Slog.e(TAG, "Bad jobscheduler settings", e); + } + } + + // Reset the heartbeat alarm based on the new heartbeat duration + setNextHeartbeatAlarm(); + } + } + /** * 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. */ - private final class Constants extends ContentObserver { + public static class Constants { // Key names stored in the settings value. private static final String KEY_MIN_IDLE_COUNT = "min_idle_count"; private static final String KEY_MIN_CHARGING_COUNT = "min_charging_count"; @@ -283,6 +321,8 @@ public final class JobSchedulerService extends com.android.server.SystemService private static final String KEY_STANDBY_WORKING_BEATS = "standby_working_beats"; private static final String KEY_STANDBY_FREQUENT_BEATS = "standby_frequent_beats"; private static final String KEY_STANDBY_RARE_BEATS = "standby_rare_beats"; + private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac"; + private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac"; private static final int DEFAULT_MIN_IDLE_COUNT = 1; private static final int DEFAULT_MIN_CHARGING_COUNT = 1; @@ -306,6 +346,8 @@ public final class JobSchedulerService extends com.android.server.SystemService private static final int DEFAULT_STANDBY_WORKING_BEATS = 11; // ~ 2 hours, with 11min beats private static final int DEFAULT_STANDBY_FREQUENT_BEATS = 43; // ~ 8 hours private static final int DEFAULT_STANDBY_RARE_BEATS = 130; // ~ 24 hours + private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f; + private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f; /** * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things @@ -400,7 +442,6 @@ public final class JobSchedulerService extends com.android.server.SystemService * hour or day, so that the heartbeat drifts relative to wall-clock milestones. */ long STANDBY_HEARTBEAT_TIME = DEFAULT_STANDBY_HEARTBEAT_TIME; - /** * Mapping: standby bucket -> number of heartbeats between each sweep of that * bucket's jobs. @@ -415,171 +456,126 @@ public final class JobSchedulerService extends com.android.server.SystemService DEFAULT_STANDBY_FREQUENT_BEATS, DEFAULT_STANDBY_RARE_BEATS }; + /** + * The fraction of a job's running window that must pass before we + * consider running it when the network is congested. + */ + public float CONN_CONGESTION_DELAY_FRAC = DEFAULT_CONN_CONGESTION_DELAY_FRAC; + /** + * The fraction of a prefetch job's running window that must pass before + * we consider matching it against a metered network. + */ + public float CONN_PREFETCH_RELAX_FRAC = DEFAULT_CONN_PREFETCH_RELAX_FRAC; - private ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); - public Constants(Handler handler) { - super(handler); - } - - public void start(ContentResolver resolver) { - mResolver = resolver; - mResolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.JOB_SCHEDULER_CONSTANTS), false, this); - updateConstants(); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - updateConstants(); - } - - private void updateConstants() { - synchronized (mLock) { - try { - mParser.setString(Settings.Global.getString(mResolver, - Settings.Global.JOB_SCHEDULER_CONSTANTS)); - } catch (IllegalArgumentException e) { - // Failed to parse the settings string, log this and move on - // with defaults. - Slog.e(TAG, "Bad jobscheduler settings", e); - } - - MIN_IDLE_COUNT = mParser.getInt(KEY_MIN_IDLE_COUNT, - DEFAULT_MIN_IDLE_COUNT); - MIN_CHARGING_COUNT = mParser.getInt(KEY_MIN_CHARGING_COUNT, - DEFAULT_MIN_CHARGING_COUNT); - MIN_BATTERY_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_BATTERY_NOT_LOW_COUNT, - DEFAULT_MIN_BATTERY_NOT_LOW_COUNT); - MIN_STORAGE_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_STORAGE_NOT_LOW_COUNT, - DEFAULT_MIN_STORAGE_NOT_LOW_COUNT); - MIN_CONNECTIVITY_COUNT = mParser.getInt(KEY_MIN_CONNECTIVITY_COUNT, - DEFAULT_MIN_CONNECTIVITY_COUNT); - MIN_CONTENT_COUNT = mParser.getInt(KEY_MIN_CONTENT_COUNT, - DEFAULT_MIN_CONTENT_COUNT); - MIN_READY_JOBS_COUNT = mParser.getInt(KEY_MIN_READY_JOBS_COUNT, - DEFAULT_MIN_READY_JOBS_COUNT); - HEAVY_USE_FACTOR = mParser.getFloat(KEY_HEAVY_USE_FACTOR, - DEFAULT_HEAVY_USE_FACTOR); - MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR, - DEFAULT_MODERATE_USE_FACTOR); - FG_JOB_COUNT = mParser.getInt(KEY_FG_JOB_COUNT, - DEFAULT_FG_JOB_COUNT); - BG_NORMAL_JOB_COUNT = mParser.getInt(KEY_BG_NORMAL_JOB_COUNT, - DEFAULT_BG_NORMAL_JOB_COUNT); - if ((FG_JOB_COUNT+BG_NORMAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { - BG_NORMAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; - } - BG_MODERATE_JOB_COUNT = mParser.getInt(KEY_BG_MODERATE_JOB_COUNT, - DEFAULT_BG_MODERATE_JOB_COUNT); - if ((FG_JOB_COUNT+BG_MODERATE_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { - BG_MODERATE_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; - } - BG_LOW_JOB_COUNT = mParser.getInt(KEY_BG_LOW_JOB_COUNT, - DEFAULT_BG_LOW_JOB_COUNT); - if ((FG_JOB_COUNT+BG_LOW_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { - BG_LOW_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; - } - BG_CRITICAL_JOB_COUNT = mParser.getInt(KEY_BG_CRITICAL_JOB_COUNT, - DEFAULT_BG_CRITICAL_JOB_COUNT); - if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { - BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; - } - 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, - DEFAULT_MAX_WORK_RESCHEDULE_COUNT); - MIN_LINEAR_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_LINEAR_BACKOFF_TIME, - DEFAULT_MIN_LINEAR_BACKOFF_TIME); - MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME, - DEFAULT_MIN_EXP_BACKOFF_TIME); - STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME, - DEFAULT_STANDBY_HEARTBEAT_TIME); - STANDBY_BEATS[1] = mParser.getInt(KEY_STANDBY_WORKING_BEATS, - DEFAULT_STANDBY_WORKING_BEATS); - STANDBY_BEATS[2] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS, - DEFAULT_STANDBY_FREQUENT_BEATS); - STANDBY_BEATS[3] = mParser.getInt(KEY_STANDBY_RARE_BEATS, - DEFAULT_STANDBY_RARE_BEATS); - } - - // Reset the heartbeat alarm based on the new heartbeat duration - setNextHeartbeatAlarm(); - } - - void dump(PrintWriter pw) { - pw.println(" Settings:"); - - pw.print(" "); pw.print(KEY_MIN_IDLE_COUNT); pw.print("="); - pw.print(MIN_IDLE_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MIN_CHARGING_COUNT); pw.print("="); - pw.print(MIN_CHARGING_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MIN_BATTERY_NOT_LOW_COUNT); pw.print("="); - pw.print(MIN_BATTERY_NOT_LOW_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MIN_STORAGE_NOT_LOW_COUNT); pw.print("="); - pw.print(MIN_STORAGE_NOT_LOW_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MIN_CONNECTIVITY_COUNT); pw.print("="); - pw.print(MIN_CONNECTIVITY_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MIN_CONTENT_COUNT); pw.print("="); - pw.print(MIN_CONTENT_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MIN_READY_JOBS_COUNT); pw.print("="); - pw.print(MIN_READY_JOBS_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_HEAVY_USE_FACTOR); pw.print("="); - pw.print(HEAVY_USE_FACTOR); pw.println(); - - pw.print(" "); pw.print(KEY_MODERATE_USE_FACTOR); pw.print("="); - pw.print(MODERATE_USE_FACTOR); pw.println(); - - pw.print(" "); pw.print(KEY_FG_JOB_COUNT); pw.print("="); - pw.print(FG_JOB_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_BG_NORMAL_JOB_COUNT); pw.print("="); - pw.print(BG_NORMAL_JOB_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_BG_MODERATE_JOB_COUNT); pw.print("="); - pw.print(BG_MODERATE_JOB_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_BG_LOW_JOB_COUNT); pw.print("="); - pw.print(BG_LOW_JOB_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_BG_CRITICAL_JOB_COUNT); pw.print("="); - pw.print(BG_CRITICAL_JOB_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MAX_STANDARD_RESCHEDULE_COUNT); pw.print("="); - pw.print(MAX_STANDARD_RESCHEDULE_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MAX_WORK_RESCHEDULE_COUNT); pw.print("="); - pw.print(MAX_WORK_RESCHEDULE_COUNT); pw.println(); - - pw.print(" "); pw.print(KEY_MIN_LINEAR_BACKOFF_TIME); pw.print("="); - pw.print(MIN_LINEAR_BACKOFF_TIME); pw.println(); - - pw.print(" "); pw.print(KEY_MIN_EXP_BACKOFF_TIME); pw.print("="); - pw.print(MIN_EXP_BACKOFF_TIME); pw.println(); - - pw.print(" "); pw.print(KEY_STANDBY_HEARTBEAT_TIME); pw.print("="); - pw.print(STANDBY_HEARTBEAT_TIME); pw.println(); - - pw.print(" standby_beats={"); + void updateConstantsLocked(String value) { + try { + mParser.setString(value); + } catch (Exception e) { + // Failed to parse the settings string, log this and move on + // with defaults. + Slog.e(TAG, "Bad jobscheduler settings", e); + } + + MIN_IDLE_COUNT = mParser.getInt(KEY_MIN_IDLE_COUNT, + DEFAULT_MIN_IDLE_COUNT); + MIN_CHARGING_COUNT = mParser.getInt(KEY_MIN_CHARGING_COUNT, + DEFAULT_MIN_CHARGING_COUNT); + MIN_BATTERY_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_BATTERY_NOT_LOW_COUNT, + DEFAULT_MIN_BATTERY_NOT_LOW_COUNT); + MIN_STORAGE_NOT_LOW_COUNT = mParser.getInt(KEY_MIN_STORAGE_NOT_LOW_COUNT, + DEFAULT_MIN_STORAGE_NOT_LOW_COUNT); + MIN_CONNECTIVITY_COUNT = mParser.getInt(KEY_MIN_CONNECTIVITY_COUNT, + DEFAULT_MIN_CONNECTIVITY_COUNT); + MIN_CONTENT_COUNT = mParser.getInt(KEY_MIN_CONTENT_COUNT, + DEFAULT_MIN_CONTENT_COUNT); + MIN_READY_JOBS_COUNT = mParser.getInt(KEY_MIN_READY_JOBS_COUNT, + DEFAULT_MIN_READY_JOBS_COUNT); + HEAVY_USE_FACTOR = mParser.getFloat(KEY_HEAVY_USE_FACTOR, + DEFAULT_HEAVY_USE_FACTOR); + MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR, + DEFAULT_MODERATE_USE_FACTOR); + FG_JOB_COUNT = mParser.getInt(KEY_FG_JOB_COUNT, + DEFAULT_FG_JOB_COUNT); + BG_NORMAL_JOB_COUNT = mParser.getInt(KEY_BG_NORMAL_JOB_COUNT, + DEFAULT_BG_NORMAL_JOB_COUNT); + if ((FG_JOB_COUNT+BG_NORMAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { + BG_NORMAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; + } + BG_MODERATE_JOB_COUNT = mParser.getInt(KEY_BG_MODERATE_JOB_COUNT, + DEFAULT_BG_MODERATE_JOB_COUNT); + if ((FG_JOB_COUNT+BG_MODERATE_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { + BG_MODERATE_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; + } + BG_LOW_JOB_COUNT = mParser.getInt(KEY_BG_LOW_JOB_COUNT, + DEFAULT_BG_LOW_JOB_COUNT); + if ((FG_JOB_COUNT+BG_LOW_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { + BG_LOW_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; + } + BG_CRITICAL_JOB_COUNT = mParser.getInt(KEY_BG_CRITICAL_JOB_COUNT, + DEFAULT_BG_CRITICAL_JOB_COUNT); + if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) { + BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT; + } + 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, + DEFAULT_MAX_WORK_RESCHEDULE_COUNT); + MIN_LINEAR_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_LINEAR_BACKOFF_TIME, + DEFAULT_MIN_LINEAR_BACKOFF_TIME); + MIN_EXP_BACKOFF_TIME = mParser.getDurationMillis(KEY_MIN_EXP_BACKOFF_TIME, + DEFAULT_MIN_EXP_BACKOFF_TIME); + STANDBY_HEARTBEAT_TIME = mParser.getDurationMillis(KEY_STANDBY_HEARTBEAT_TIME, + DEFAULT_STANDBY_HEARTBEAT_TIME); + STANDBY_BEATS[1] = mParser.getInt(KEY_STANDBY_WORKING_BEATS, + DEFAULT_STANDBY_WORKING_BEATS); + STANDBY_BEATS[2] = mParser.getInt(KEY_STANDBY_FREQUENT_BEATS, + DEFAULT_STANDBY_FREQUENT_BEATS); + STANDBY_BEATS[3] = mParser.getInt(KEY_STANDBY_RARE_BEATS, + DEFAULT_STANDBY_RARE_BEATS); + CONN_CONGESTION_DELAY_FRAC = mParser.getFloat(KEY_CONN_CONGESTION_DELAY_FRAC, + DEFAULT_CONN_CONGESTION_DELAY_FRAC); + CONN_PREFETCH_RELAX_FRAC = mParser.getFloat(KEY_CONN_PREFETCH_RELAX_FRAC, + DEFAULT_CONN_PREFETCH_RELAX_FRAC); + } + + void dump(IndentingPrintWriter pw) { + pw.println("Settings:"); + pw.increaseIndent(); + pw.printPair(KEY_MIN_IDLE_COUNT, MIN_IDLE_COUNT).println(); + pw.printPair(KEY_MIN_CHARGING_COUNT, MIN_CHARGING_COUNT).println(); + pw.printPair(KEY_MIN_BATTERY_NOT_LOW_COUNT, MIN_BATTERY_NOT_LOW_COUNT).println(); + pw.printPair(KEY_MIN_STORAGE_NOT_LOW_COUNT, MIN_STORAGE_NOT_LOW_COUNT).println(); + pw.printPair(KEY_MIN_CONNECTIVITY_COUNT, MIN_CONNECTIVITY_COUNT).println(); + pw.printPair(KEY_MIN_CONTENT_COUNT, MIN_CONTENT_COUNT).println(); + pw.printPair(KEY_MIN_READY_JOBS_COUNT, MIN_READY_JOBS_COUNT).println(); + pw.printPair(KEY_HEAVY_USE_FACTOR, HEAVY_USE_FACTOR).println(); + pw.printPair(KEY_MODERATE_USE_FACTOR, MODERATE_USE_FACTOR).println(); + pw.printPair(KEY_FG_JOB_COUNT, FG_JOB_COUNT).println(); + pw.printPair(KEY_BG_NORMAL_JOB_COUNT, BG_NORMAL_JOB_COUNT).println(); + 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(); + 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(); + pw.printPair(KEY_MIN_EXP_BACKOFF_TIME, MIN_EXP_BACKOFF_TIME).println(); + pw.printPair(KEY_STANDBY_HEARTBEAT_TIME, STANDBY_HEARTBEAT_TIME).println(); + pw.print("standby_beats={"); pw.print(STANDBY_BEATS[0]); for (int i = 1; i < STANDBY_BEATS.length; i++) { pw.print(", "); pw.print(STANDBY_BEATS[i]); } pw.println('}'); + pw.printPair(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println(); + pw.printPair(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println(); + pw.decreaseIndent(); } void dump(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); - proto.write(ConstantsProto.MIN_IDLE_COUNT, MIN_IDLE_COUNT); proto.write(ConstantsProto.MIN_CHARGING_COUNT, MIN_CHARGING_COUNT); proto.write(ConstantsProto.MIN_BATTERY_NOT_LOW_COUNT, MIN_BATTERY_NOT_LOW_COUNT); @@ -599,16 +595,17 @@ public final class JobSchedulerService extends com.android.server.SystemService proto.write(ConstantsProto.MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME); proto.write(ConstantsProto.MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME); proto.write(ConstantsProto.STANDBY_HEARTBEAT_TIME_MS, STANDBY_HEARTBEAT_TIME); - for (int period : STANDBY_BEATS) { proto.write(ConstantsProto.STANDBY_BEATS, period); } - + proto.write(ConstantsProto.CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC); + proto.write(ConstantsProto.CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC); proto.end(token); } } final Constants mConstants; + final ConstantsObserver mConstantsObserver; static final Comparator<JobStatus> mEnqueueTimeComparator = (o1, o2) -> { if (o1.enqueueTime < o2.enqueueTime) { @@ -778,6 +775,10 @@ public final class JobSchedulerService extends com.android.server.SystemService return mJobs; } + public Constants getConstants() { + return mConstants; + } + @Override public void onStartUser(int userHandle) { mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle); @@ -1097,7 +1098,8 @@ public final class JobSchedulerService extends com.android.server.SystemService LocalServices.getService(ActivityManagerInternal.class)); mHandler = new JobHandler(context.getMainLooper()); - mConstants = new Constants(mHandler); + mConstants = new Constants(); + mConstantsObserver = new ConstantsObserver(mHandler); mJobSchedulerStub = new JobSchedulerStub(); // Set up the app standby bucketing tracker @@ -1113,17 +1115,17 @@ public final class JobSchedulerService extends com.android.server.SystemService // Create the controllers. mControllers = new ArrayList<StateController>(); - mControllers.add(ConnectivityController.get(this)); - mControllers.add(TimeController.get(this)); - mControllers.add(IdleController.get(this)); - mBatteryController = BatteryController.get(this); + mControllers.add(new ConnectivityController(this)); + mControllers.add(new TimeController(this)); + mControllers.add(new IdleController(this)); + mBatteryController = new BatteryController(this); mControllers.add(mBatteryController); - mStorageController = StorageController.get(this); + mStorageController = new StorageController(this); mControllers.add(mStorageController); - mControllers.add(BackgroundJobsController.get(this)); - mControllers.add(AppIdleController.get(this)); - mControllers.add(ContentObserverController.get(this)); - mDeviceIdleJobsController = DeviceIdleJobsController.get(this); + mControllers.add(new BackgroundJobsController(this)); + mControllers.add(new AppIdleController(this)); + mControllers.add(new ContentObserverController(this)); + mDeviceIdleJobsController = new DeviceIdleJobsController(this); mControllers.add(mDeviceIdleJobsController); // If the job store determined that it can't yet reschedule persisted jobs, @@ -1184,7 +1186,7 @@ public final class JobSchedulerService extends com.android.server.SystemService @Override public void onBootPhase(int phase) { if (PHASE_SYSTEM_SERVICES_READY == phase) { - mConstants.start(getContext().getContentResolver()); + mConstantsObserver.start(getContext().getContentResolver()); mAppStateTracker = Preconditions.checkNotNull( LocalServices.getService(AppStateTracker.class)); @@ -1227,13 +1229,10 @@ public final class JobSchedulerService extends com.android.server.SystemService getContext().getMainLooper())); } // Attach jobs to their controllers. - mJobs.forEachJob(new JobStatusFunctor() { - @Override - public void process(JobStatus job) { - for (int controller = 0; controller < mControllers.size(); controller++) { - final StateController sc = mControllers.get(controller); - sc.maybeStartTrackingJobLocked(job, null); - } + mJobs.forEachJob((job) -> { + for (int controller = 0; controller < mControllers.size(); controller++) { + final StateController sc = mControllers.get(controller); + sc.maybeStartTrackingJobLocked(job, null); } }); // GO GO GO! @@ -1602,11 +1601,11 @@ public final class JobSchedulerService extends com.android.server.SystemService } } - final class ReadyJobQueueFunctor implements JobStatusFunctor { + final class ReadyJobQueueFunctor implements Consumer<JobStatus> { ArrayList<JobStatus> newReadyJobs; @Override - public void process(JobStatus job) { + public void accept(JobStatus job) { if (isReadyToBeExecutedLocked(job)) { if (DEBUG) { Slog.d(TAG, " queued " + job.toShortString()); @@ -1640,7 +1639,7 @@ public final class JobSchedulerService extends com.android.server.SystemService * If more than 4 jobs total are ready we send them all off. * TODO: It would be nice to consolidate these sort of high-level policies somewhere. */ - final class MaybeReadyJobQueueFunctor implements JobStatusFunctor { + final class MaybeReadyJobQueueFunctor implements Consumer<JobStatus> { int chargingCount; int batteryNotLowCount; int storageNotLowCount; @@ -1656,7 +1655,7 @@ public final class JobSchedulerService extends com.android.server.SystemService // Functor method invoked for each job via JobStore.forEachJob() @Override - public void process(JobStatus job) { + public void accept(JobStatus job) { if (isReadyToBeExecutedLocked(job)) { try { if (ActivityManager.getService().isAppStartModeDisabled(job.getUid(), @@ -2173,12 +2172,9 @@ public final class JobSchedulerService extends com.android.server.SystemService public List<JobInfo> getSystemScheduledPendingJobs() { synchronized (mLock) { final List<JobInfo> pendingJobs = new ArrayList<JobInfo>(); - mJobs.forEachJob(Process.SYSTEM_UID, new JobStatusFunctor() { - @Override - public void process(JobStatus job) { - if (job.getJob().isPeriodic() || !isCurrentlyActiveLocked(job)) { - pendingJobs.add(job.getJob()); - } + mJobs.forEachJob(Process.SYSTEM_UID, (job) -> { + if (job.getJob().isPeriodic() || !isCurrentlyActiveLocked(job)) { + pendingJobs.add(job.getJob()); } }); return pendingJobs; @@ -2307,7 +2303,7 @@ public final class JobSchedulerService extends com.android.server.SystemService } } - static class DeferredJobCounter implements JobStatusFunctor { + static class DeferredJobCounter implements Consumer<JobStatus> { private int mDeferred = 0; public int numDeferred() { @@ -2315,7 +2311,7 @@ public final class JobSchedulerService extends com.android.server.SystemService } @Override - public void process(JobStatus job) { + public void accept(JobStatus job) { if (job.getWhenStandbyDeferred() > 0) { mDeferred++; } @@ -2596,12 +2592,13 @@ public final class JobSchedulerService extends com.android.server.SystemService } } - long identityToken = Binder.clearCallingIdentity(); + final long identityToken = Binder.clearCallingIdentity(); try { if (proto) { JobSchedulerService.this.dumpInternalProto(fd, filterUid); } else { - JobSchedulerService.this.dumpInternal(pw, filterUid); + JobSchedulerService.this.dumpInternal(new IndentingPrintWriter(pw, " "), + filterUid); } } finally { Binder.restoreCallingIdentity(identityToken); @@ -2900,10 +2897,14 @@ public final class JobSchedulerService extends com.android.server.SystemService }); } - void dumpInternal(final PrintWriter pw, int filterUid) { + void dumpInternal(final IndentingPrintWriter pw, int filterUid) { final int filterUidFinal = UserHandle.getAppId(filterUid); final long nowElapsed = sElapsedRealtimeClock.millis(); final long nowUptime = sUptimeMillisClock.millis(); + final Predicate<JobStatus> predicate = (js) -> { + return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal + || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal; + }; synchronized (mLock) { mConstants.dump(pw); pw.println(); @@ -2919,7 +2920,7 @@ public final class JobSchedulerService extends com.android.server.SystemService pw.println(job.toShortStringExceptUniqueId()); // Skip printing details if the caller requested a filter - if (!job.shouldDump(filterUidFinal)) { + if (!predicate.test(job)) { continue; } @@ -2953,7 +2954,10 @@ public final class JobSchedulerService extends com.android.server.SystemService } for (int i=0; i<mControllers.size(); i++) { pw.println(); - mControllers.get(i).dumpControllerStateLocked(pw, filterUidFinal); + pw.println(mControllers.get(i).getClass().getSimpleName() + ":"); + pw.increaseIndent(); + mControllers.get(i).dumpControllerStateLocked(pw, predicate); + pw.decreaseIndent(); } pw.println(); pw.println("Uid priority overrides:"); @@ -3056,6 +3060,10 @@ public final class JobSchedulerService extends com.android.server.SystemService final int filterUidFinal = UserHandle.getAppId(filterUid); final long nowElapsed = sElapsedRealtimeClock.millis(); final long nowUptime = sUptimeMillisClock.millis(); + final Predicate<JobStatus> predicate = (js) -> { + return filterUidFinal == -1 || UserHandle.getAppId(js.getUid()) == filterUidFinal + || UserHandle.getAppId(js.getSourceUid()) == filterUidFinal; + }; synchronized (mLock) { mConstants.dump(proto, JobSchedulerServiceDumpProto.SETTINGS); @@ -3070,7 +3078,7 @@ public final class JobSchedulerService extends com.android.server.SystemService job.writeToShortProto(proto, JobSchedulerServiceDumpProto.RegisteredJob.INFO); // Skip printing details if the caller requested a filter - if (!job.shouldDump(filterUidFinal)) { + if (!predicate.test(job)) { continue; } @@ -3103,7 +3111,7 @@ public final class JobSchedulerService extends com.android.server.SystemService } for (StateController controller : mControllers) { controller.dumpControllerStateLocked( - proto, JobSchedulerServiceDumpProto.CONTROLLERS, filterUidFinal); + proto, JobSchedulerServiceDumpProto.CONTROLLERS, predicate); } for (int i=0; i< mUidPriorityOverride.size(); i++) { int uid = mUidPriorityOverride.keyAt(i); diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index cf2788255843..7235faa6ad50 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -19,6 +19,7 @@ package com.android.server.job; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import static com.android.server.job.JobSchedulerService.sSystemClock; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.IActivityManager; import android.app.job.JobInfo; @@ -62,6 +63,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.function.Consumer; import java.util.function.Predicate; /** @@ -286,20 +288,21 @@ public final class JobStore { * transient unified collections for them to iterate over and then discard, or creating * iterators every time a client needs to perform a sweep. */ - public void forEachJob(JobStatusFunctor functor) { - mJobSet.forEachJob(functor); + public void forEachJob(Consumer<JobStatus> functor) { + mJobSet.forEachJob(null, functor); } - public void forEachJob(int uid, JobStatusFunctor functor) { - mJobSet.forEachJob(uid, functor); + public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate, + Consumer<JobStatus> functor) { + mJobSet.forEachJob(filterPredicate, functor); } - public void forEachJobForSourceUid(int sourceUid, JobStatusFunctor functor) { - mJobSet.forEachJobForSourceUid(sourceUid, functor); + public void forEachJob(int uid, Consumer<JobStatus> functor) { + mJobSet.forEachJob(uid, functor); } - public interface JobStatusFunctor { - public void process(JobStatus jobStatus); + public void forEachJobForSourceUid(int sourceUid, Consumer<JobStatus> functor) { + mJobSet.forEachJobForSourceUid(sourceUid, functor); } /** Version of the db schema. */ @@ -342,12 +345,9 @@ public final class JobStore { final List<JobStatus> storeCopy = new ArrayList<JobStatus>(); synchronized (mLock) { // Clone the jobs so we can release the lock before writing. - mJobSet.forEachJob(new JobStatusFunctor() { - @Override - public void process(JobStatus job) { - if (job.isPersisted()) { - storeCopy.add(new JobStatus(job)); - } + mJobSet.forEachJob(null, (job) -> { + if (job.isPersisted()) { + storeCopy.add(new JobStatus(job)); } }); } @@ -1184,31 +1184,35 @@ public final class JobStore { return total; } - public void forEachJob(JobStatusFunctor functor) { + public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate, + Consumer<JobStatus> functor) { for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) { ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex); if (jobs != null) { for (int i = jobs.size() - 1; i >= 0; i--) { - functor.process(jobs.valueAt(i)); + final JobStatus jobStatus = jobs.valueAt(i); + if ((filterPredicate == null) || filterPredicate.test(jobStatus)) { + functor.accept(jobStatus); + } } } } } - public void forEachJob(int callingUid, JobStatusFunctor functor) { + public void forEachJob(int callingUid, Consumer<JobStatus> functor) { ArraySet<JobStatus> jobs = mJobs.get(callingUid); if (jobs != null) { for (int i = jobs.size() - 1; i >= 0; i--) { - functor.process(jobs.valueAt(i)); + functor.accept(jobs.valueAt(i)); } } } - public void forEachJobForSourceUid(int sourceUid, JobStatusFunctor functor) { + public void forEachJobForSourceUid(int sourceUid, Consumer<JobStatus> functor) { final ArraySet<JobStatus> jobs = mJobsPerSourceUid.get(sourceUid); if (jobs != null) { for (int i = jobs.size() - 1; i >= 0; i--) { - functor.process(jobs.valueAt(i)); + functor.accept(jobs.valueAt(i)); } } } diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java index 021eccd6d1cf..bd8fe289ddad 100644 --- a/services/core/java/com/android/server/job/controllers/AppIdleController.java +++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java @@ -17,18 +17,18 @@ package com.android.server.job.controllers; import android.app.usage.UsageStatsManagerInternal; -import android.content.Context; import android.os.UserHandle; import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; -import com.android.server.job.JobStore; import com.android.server.job.StateControllerProto; -import java.io.PrintWriter; +import java.util.function.Consumer; +import java.util.function.Predicate; /** * Controls when apps are considered idle and if jobs pertaining to those apps should @@ -41,18 +41,15 @@ public final class AppIdleController extends StateController { private static final boolean DEBUG = JobSchedulerService.DEBUG || Log.isLoggable(TAG, Log.DEBUG); - // Singleton factory - private static Object sCreationLock = new Object(); - private static volatile AppIdleController sController; - private final JobSchedulerService mJobSchedulerService; private final UsageStatsManagerInternal mUsageStatsInternal; private boolean mInitializedParoleOn; boolean mAppIdleParoleOn; - final class GlobalUpdateFunc implements JobStore.JobStatusFunctor { + final class GlobalUpdateFunc implements Consumer<JobStatus> { boolean mChanged; - @Override public void process(JobStatus jobStatus) { + @Override + public void accept(JobStatus jobStatus) { String packageName = jobStatus.getSourcePackageName(); final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName, jobStatus.getSourceUid(), jobStatus.getSourceUserId()); @@ -63,9 +60,9 @@ public final class AppIdleController extends StateController { mChanged = true; } } - }; + } - final static class PackageUpdateFunc implements JobStore.JobStatusFunctor { + final static class PackageUpdateFunc implements Consumer<JobStatus> { final int mUserId; final String mPackage; final boolean mIdle; @@ -77,7 +74,8 @@ public final class AppIdleController extends StateController { mIdle = idle; } - @Override public void process(JobStatus jobStatus) { + @Override + public void accept(JobStatus jobStatus) { if (jobStatus.getSourcePackageName().equals(mPackage) && jobStatus.getSourceUserId() == mUserId) { if (jobStatus.setAppNotIdleConstraintSatisfied(!mIdle)) { @@ -89,21 +87,10 @@ public final class AppIdleController extends StateController { } } } - }; - - public static AppIdleController get(JobSchedulerService service) { - synchronized (sCreationLock) { - if (sController == null) { - sController = new AppIdleController(service, service.getContext(), - service.getLock()); - } - return sController; - } } - private AppIdleController(JobSchedulerService service, Context context, Object lock) { - super(service, context, lock); - mJobSchedulerService = service; + public AppIdleController(JobSchedulerService service) { + super(service); mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class); mAppIdleParoleOn = true; mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener()); @@ -131,56 +118,46 @@ public final class AppIdleController extends StateController { } @Override - public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) { - pw.print("AppIdle: parole on = "); - pw.println(mAppIdleParoleOn); - mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() { - @Override public void process(JobStatus jobStatus) { - // Skip printing details if the caller requested a filter - if (!jobStatus.shouldDump(filterUid)) { - return; - } - pw.print(" #"); - jobStatus.printUniqueId(pw); - pw.print(" from "); - UserHandle.formatUid(pw, jobStatus.getSourceUid()); - pw.print(": "); - pw.print(jobStatus.getSourcePackageName()); - if ((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0) { - pw.println(" RUNNABLE"); - } else { - pw.println(" WAITING"); - } + public void dumpControllerStateLocked(final IndentingPrintWriter pw, + final Predicate<JobStatus> predicate) { + pw.println("Parole on: " + mAppIdleParoleOn); + pw.println(); + + mService.getJobStore().forEachJob(predicate, (jobStatus) -> { + pw.print("#"); + jobStatus.printUniqueId(pw); + pw.print(" from "); + UserHandle.formatUid(pw, jobStatus.getSourceUid()); + pw.print(": "); + pw.print(jobStatus.getSourcePackageName()); + if ((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0) { + pw.println(" RUNNABLE"); + } else { + pw.println(" WAITING"); } }); } @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.APP_IDLE); proto.write(StateControllerProto.AppIdleController.IS_PAROLE_ON, mAppIdleParoleOn); - mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() { - @Override public void process(JobStatus js) { - // Skip printing details if the caller requested a filter - if (!js.shouldDump(filterUid)) { - return; - } - - final long jsToken = - proto.start(StateControllerProto.AppIdleController.TRACKED_JOBS); - js.writeToShortProto(proto, StateControllerProto.AppIdleController.TrackedJob.INFO); - proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_UID, - js.getSourceUid()); - proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_PACKAGE_NAME, - js.getSourcePackageName()); - proto.write( - StateControllerProto.AppIdleController.TrackedJob.ARE_CONSTRAINTS_SATISFIED, - (js.satisfiedConstraints & JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0); - proto.end(jsToken); - } + mService.getJobStore().forEachJob(predicate, (js) -> { + final long jsToken = + proto.start(StateControllerProto.AppIdleController.TRACKED_JOBS); + js.writeToShortProto(proto, StateControllerProto.AppIdleController.TrackedJob.INFO); + proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_UID, + js.getSourceUid()); + proto.write(StateControllerProto.AppIdleController.TrackedJob.SOURCE_PACKAGE_NAME, + js.getSourcePackageName()); + proto.write( + StateControllerProto.AppIdleController.TrackedJob.ARE_CONSTRAINTS_SATISFIED, + (js.satisfiedConstraints & JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0); + proto.end(jsToken); }); proto.end(mToken); @@ -196,7 +173,7 @@ public final class AppIdleController extends StateController { } mAppIdleParoleOn = isAppIdleParoleOn; GlobalUpdateFunc update = new GlobalUpdateFunc(); - mJobSchedulerService.getJobStore().forEachJob(update); + mService.getJobStore().forEachJob(update); if (update.mChanged) { changed = true; } @@ -217,7 +194,7 @@ public final class AppIdleController extends StateController { } PackageUpdateFunc update = new PackageUpdateFunc(userId, packageName, idle); - mJobSchedulerService.getJobStore().forEachJob(update); + mService.getJobStore().forEachJob(update); if (update.mChanged) { changed = true; } diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java index 46ec5e5d1e1d..36e75115712c 100644 --- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java +++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java @@ -16,50 +16,33 @@ package com.android.server.job.controllers; -import android.content.Context; import android.os.SystemClock; import android.os.UserHandle; import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.AppStateTracker; import com.android.server.AppStateTracker.Listener; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; -import com.android.server.job.JobStore; import com.android.server.job.StateControllerProto; import com.android.server.job.StateControllerProto.BackgroundJobsController.TrackedJob; -import java.io.PrintWriter; +import java.util.function.Consumer; +import java.util.function.Predicate; public final class BackgroundJobsController extends StateController { private static final String TAG = "JobScheduler.Background"; private static final boolean DEBUG = JobSchedulerService.DEBUG || Log.isLoggable(TAG, Log.DEBUG); - // Singleton factory - private static final Object sCreationLock = new Object(); - private static volatile BackgroundJobsController sController; - - private final JobSchedulerService mJobSchedulerService; - private final AppStateTracker mAppStateTracker; - public static BackgroundJobsController get(JobSchedulerService service) { - synchronized (sCreationLock) { - if (sController == null) { - sController = new BackgroundJobsController(service, service.getContext(), - service.getLock()); - } - return sController; - } - } - - private BackgroundJobsController(JobSchedulerService service, Context context, Object lock) { - super(service, context, lock); - mJobSchedulerService = service; + public BackgroundJobsController(JobSchedulerService service) { + super(service); mAppStateTracker = Preconditions.checkNotNull( LocalServices.getService(AppStateTracker.class)); @@ -77,19 +60,15 @@ public final class BackgroundJobsController extends StateController { } @Override - public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) { - pw.println("BackgroundJobsController"); + public void dumpControllerStateLocked(final IndentingPrintWriter pw, + final Predicate<JobStatus> predicate) { + mAppStateTracker.dump(pw); + pw.println(); - mAppStateTracker.dump(pw, ""); - - pw.println("Job state:"); - mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> { - if (!jobStatus.shouldDump(filterUid)) { - return; - } + mService.getJobStore().forEachJob(predicate, (jobStatus) -> { final int uid = jobStatus.getSourceUid(); final String sourcePkg = jobStatus.getSourcePackageName(); - pw.print(" #"); + pw.print("#"); jobStatus.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, uid); @@ -115,17 +94,15 @@ public final class BackgroundJobsController extends StateController { } @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.BACKGROUND); mAppStateTracker.dumpProto(proto, StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER); - mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> { - if (!jobStatus.shouldDump(filterUid)) { - return; - } + mService.getJobStore().forEachJob(predicate, (jobStatus) -> { final long jsToken = proto.start(StateControllerProto.BackgroundJobsController.TRACKED_JOBS); @@ -176,7 +153,7 @@ public final class BackgroundJobsController extends StateController { final long start = DEBUG ? SystemClock.elapsedRealtimeNanos() : 0; - mJobSchedulerService.getJobStore().forEachJob(updateTrackedJobs); + mService.getJobStore().forEachJob(updateTrackedJobs); final long time = DEBUG ? (SystemClock.elapsedRealtimeNanos() - start) : 0; if (DEBUG) { @@ -205,7 +182,7 @@ public final class BackgroundJobsController extends StateController { return jobStatus.setBackgroundNotRestrictedConstraintSatisfied(canRun); } - private final class UpdateJobFunctor implements JobStore.JobStatusFunctor { + private final class UpdateJobFunctor implements Consumer<JobStatus> { private final int mFilterUid; boolean mChanged = false; @@ -217,7 +194,7 @@ public final class BackgroundJobsController extends StateController { } @Override - public void process(JobStatus jobStatus) { + public void accept(JobStatus jobStatus) { mTotalCount++; if ((mFilterUid > 0) && (mFilterUid != jobStatus.getSourceUid())) { return; diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java index 263d99b06f2c..46658ad33b85 100644 --- a/services/core/java/com/android/server/job/controllers/BatteryController.java +++ b/services/core/java/com/android/server/job/controllers/BatteryController.java @@ -31,12 +31,12 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; -import com.android.server.job.StateChangedListener; import com.android.server.job.StateControllerProto; -import java.io.PrintWriter; +import java.util.function.Predicate; /** * Simple controller that tracks whether the phone is charging or not. The phone is considered to @@ -48,36 +48,16 @@ public final class BatteryController extends StateController { private static final boolean DEBUG = JobSchedulerService.DEBUG || Log.isLoggable(TAG, Log.DEBUG); - private static final Object sCreationLock = new Object(); - private static volatile BatteryController sController; - private final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>(); private ChargingTracker mChargeTracker; - public static BatteryController get(JobSchedulerService taskManagerService) { - synchronized (sCreationLock) { - if (sController == null) { - sController = new BatteryController(taskManagerService, - taskManagerService.getContext(), taskManagerService.getLock()); - } - } - return sController; - } - @VisibleForTesting public ChargingTracker getTracker() { return mChargeTracker; } - @VisibleForTesting - public static BatteryController getForTesting(StateChangedListener stateChangedListener, - Context context) { - return new BatteryController(stateChangedListener, context, new Object()); - } - - private BatteryController(StateChangedListener stateChangedListener, Context context, - Object lock) { - super(stateChangedListener, context, lock); + public BatteryController(JobSchedulerService service) { + super(service); mChargeTracker = new ChargingTracker(); mChargeTracker.startTracking(); } @@ -244,24 +224,23 @@ public final class BatteryController extends StateController { } @Override - public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { - pw.print("Battery: stable power = "); - pw.print(mChargeTracker.isOnStablePower()); - pw.print(", not low = "); - pw.println(mChargeTracker.isBatteryNotLow()); + public void dumpControllerStateLocked(IndentingPrintWriter pw, + Predicate<JobStatus> predicate) { + pw.println("Stable power: " + mChargeTracker.isOnStablePower()); + pw.println("Not low: " + mChargeTracker.isBatteryNotLow()); + if (mChargeTracker.isMonitoring()) { pw.print("MONITORING: seq="); pw.println(mChargeTracker.getSeq()); } - pw.print("Tracking "); - pw.print(mTrackedTasks.size()); - pw.println(":"); + pw.println(); + for (int i = 0; i < mTrackedTasks.size(); i++) { final JobStatus js = mTrackedTasks.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } - pw.print(" #"); + pw.print("#"); js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); @@ -270,7 +249,8 @@ public final class BatteryController extends StateController { } @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.BATTERY); @@ -286,7 +266,7 @@ public final class BatteryController extends StateController { for (int i = 0; i < mTrackedTasks.size(); i++) { final JobStatus js = mTrackedTasks.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } final long jsToken = proto.start(StateControllerProto.BatteryController.TRACKED_JOBS); diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index d7ef124c640d..abe55bbfb729 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -21,7 +21,6 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import android.app.job.JobInfo; -import android.content.Context; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.INetworkPolicyListener; @@ -41,12 +40,13 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.job.JobSchedulerService; +import com.android.server.job.JobSchedulerService.Constants; import com.android.server.job.JobServiceContext; -import com.android.server.job.StateChangedListener; import com.android.server.job.StateControllerProto; -import java.io.PrintWriter; +import java.util.function.Predicate; /** * Handles changes in connectivity. @@ -68,22 +68,8 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") private final ArraySet<JobStatus> mTrackedJobs = new ArraySet<>(); - /** Singleton. */ - private static ConnectivityController sSingleton; - private static Object sCreationLock = new Object(); - - public static ConnectivityController get(JobSchedulerService jms) { - synchronized (sCreationLock) { - if (sSingleton == null) { - sSingleton = new ConnectivityController(jms, jms.getContext(), jms.getLock()); - } - return sSingleton; - } - } - - private ConnectivityController(StateChangedListener stateChangedListener, Context context, - Object lock) { - super(stateChangedListener, context, lock); + public ConnectivityController(JobSchedulerService service) { + super(service); mConnManager = mContext.getSystemService(ConnectivityManager.class); mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); @@ -122,7 +108,7 @@ public final class ConnectivityController extends StateController implements */ @SuppressWarnings("unused") private static boolean isInsane(JobStatus jobStatus, Network network, - NetworkCapabilities capabilities) { + NetworkCapabilities capabilities, Constants constants) { final long estimatedBytes = jobStatus.getEstimatedNetworkBytes(); if (estimatedBytes == JobInfo.NETWORK_BYTES_UNKNOWN) { // We don't know how large the job is; cross our fingers! @@ -153,11 +139,11 @@ public final class ConnectivityController extends StateController implements @SuppressWarnings("unused") private static boolean isCongestionDelayed(JobStatus jobStatus, Network network, - NetworkCapabilities capabilities) { + NetworkCapabilities capabilities, Constants constants) { // If network is congested, and job is less than 50% through the // developer-requested window, then we're okay delaying the job. if (!capabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED)) { - return jobStatus.getFractionRunTime() < 0.5; + return jobStatus.getFractionRunTime() < constants.CONN_CONGESTION_DELAY_FRAC; } else { return false; } @@ -165,14 +151,14 @@ public final class ConnectivityController extends StateController implements @SuppressWarnings("unused") private static boolean isStrictSatisfied(JobStatus jobStatus, Network network, - NetworkCapabilities capabilities) { + NetworkCapabilities capabilities, Constants constants) { return jobStatus.getJob().getRequiredNetwork().networkCapabilities .satisfiedByNetworkCapabilities(capabilities); } @SuppressWarnings("unused") private static boolean isRelaxedSatisfied(JobStatus jobStatus, Network network, - NetworkCapabilities capabilities) { + NetworkCapabilities capabilities, Constants constants) { // Only consider doing this for prefetching jobs if ((jobStatus.getJob().getFlags() & JobInfo.FLAG_IS_PREFETCH) == 0) { return false; @@ -184,7 +170,7 @@ public final class ConnectivityController extends StateController implements .removeCapability(NET_CAPABILITY_NOT_METERED); if (relaxed.satisfiedByNetworkCapabilities(capabilities)) { // TODO: treat this as "maybe" response; need to check quotas - return jobStatus.getFractionRunTime() > 0.5; + return jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC; } else { return false; } @@ -192,21 +178,21 @@ public final class ConnectivityController extends StateController implements @VisibleForTesting static boolean isSatisfied(JobStatus jobStatus, Network network, - NetworkCapabilities capabilities) { + NetworkCapabilities capabilities, Constants constants) { // Zeroth, we gotta have a network to think about being satisfied if (network == null || capabilities == null) return false; // First, are we insane? - if (isInsane(jobStatus, network, capabilities)) return false; + if (isInsane(jobStatus, network, capabilities, constants)) return false; // Second, is the network congested? - if (isCongestionDelayed(jobStatus, network, capabilities)) return false; + if (isCongestionDelayed(jobStatus, network, capabilities, constants)) return false; // Third, is the network a strict match? - if (isStrictSatisfied(jobStatus, network, capabilities)) return true; + if (isStrictSatisfied(jobStatus, network, capabilities, constants)) return true; // Third, is the network a relaxed match? - if (isRelaxedSatisfied(jobStatus, network, capabilities)) return true; + if (isRelaxedSatisfied(jobStatus, network, capabilities, constants)) return true; return false; } @@ -222,7 +208,7 @@ public final class ConnectivityController extends StateController implements final NetworkCapabilities capabilities = mConnManager.getNetworkCapabilities(network); final boolean connected = (info != null) && info.isConnected(); - final boolean satisfied = isSatisfied(jobStatus, network, capabilities); + final boolean satisfied = isSatisfied(jobStatus, network, capabilities, mConstants); final boolean changed = jobStatus .setConnectivityConstraintSatisfied(connected && satisfied); @@ -331,18 +317,15 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") @Override - public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { - pw.print("Connectivity: connected="); - pw.println(mConnected); - - pw.print("Tracking "); - pw.print(mTrackedJobs.size()); - pw.println(" jobs"); + public void dumpControllerStateLocked(IndentingPrintWriter pw, + Predicate<JobStatus> predicate) { + pw.println("System connected: " + mConnected); + pw.println(); for (int i = 0; i < mTrackedJobs.size(); i++) { final JobStatus js = mTrackedJobs.valueAt(i); - if (js.shouldDump(filterUid)) { - pw.print(" #"); + if (predicate.test(js)) { + pw.print("#"); js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); @@ -355,7 +338,8 @@ public final class ConnectivityController extends StateController implements @GuardedBy("mLock") @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.CONNECTIVITY); @@ -363,7 +347,7 @@ public final class ConnectivityController extends StateController implements for (int i = 0; i < mTrackedJobs.size(); i++) { final JobStatus js = mTrackedJobs.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } final long jsToken = proto.start(StateControllerProto.ConnectivityController.TRACKED_JOBS); diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java index 90edde907f6d..a775cf5a671c 100644 --- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java +++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java @@ -18,7 +18,6 @@ package com.android.server.job.controllers; import android.annotation.UserIdInt; import android.app.job.JobInfo; -import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; @@ -31,14 +30,13 @@ import android.util.SparseArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; -import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.job.JobSchedulerService; -import com.android.server.job.StateChangedListener; import com.android.server.job.StateControllerProto; import com.android.server.job.StateControllerProto.ContentObserverController.Observer.TriggerContentData; -import java.io.PrintWriter; import java.util.ArrayList; +import java.util.function.Predicate; /** * Controller for monitoring changes to content URIs through a ContentObserver. @@ -60,9 +58,6 @@ public final class ContentObserverController extends StateController { */ private static final int URIS_URGENT_THRESHOLD = 40; - private static final Object sCreationLock = new Object(); - private static volatile ContentObserverController sController; - final private ArraySet<JobStatus> mTrackedTasks = new ArraySet<>(); /** * Per-userid {@link JobInfo.TriggerContentUri} keyed ContentObserver cache. @@ -71,26 +66,9 @@ public final class ContentObserverController extends StateController { new SparseArray<>(); final Handler mHandler; - public static ContentObserverController get(JobSchedulerService taskManagerService) { - synchronized (sCreationLock) { - if (sController == null) { - sController = new ContentObserverController(taskManagerService, - taskManagerService.getContext(), taskManagerService.getLock()); - } - } - return sController; - } - - @VisibleForTesting - public static ContentObserverController getForTesting(StateChangedListener stateChangedListener, - Context context) { - return new ContentObserverController(stateChangedListener, context, new Object()); - } - - private ContentObserverController(StateChangedListener stateChangedListener, Context context, - Object lock) { - super(stateChangedListener, context, lock); - mHandler = new Handler(context.getMainLooper()); + public ContentObserverController(JobSchedulerService service) { + super(service); + mHandler = new Handler(mContext.getMainLooper()); } @Override @@ -375,22 +353,25 @@ public final class ContentObserverController extends StateController { } @Override - public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { - pw.println("Content:"); + public void dumpControllerStateLocked(IndentingPrintWriter pw, + Predicate<JobStatus> predicate) { for (int i = 0; i < mTrackedTasks.size(); i++) { JobStatus js = mTrackedTasks.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } - pw.print(" #"); + pw.print("#"); js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); pw.println(); } + pw.println(); + int N = mObservers.size(); if (N > 0) { - pw.println(" Observers:"); + pw.println("Observers:"); + pw.increaseIndent(); for (int userIdx = 0; userIdx < N; userIdx++) { final int userId = mObservers.keyAt(userIdx); ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observersOfUser = @@ -402,7 +383,7 @@ public final class ContentObserverController extends StateController { boolean shouldDump = false; for (int j = 0; j < M; j++) { JobInstance inst = obs.mJobs.valueAt(j); - if (inst.mJobStatus.shouldDump(filterUid)) { + if (predicate.test(inst.mJobStatus)) { shouldDump = true; break; } @@ -410,7 +391,6 @@ public final class ContentObserverController extends StateController { if (!shouldDump) { continue; } - pw.print(" "); JobInfo.TriggerContentUri trigger = observersOfUser.keyAt(observerIdx); pw.print(trigger.getUri()); pw.print(" 0x"); @@ -418,17 +398,20 @@ public final class ContentObserverController extends StateController { pw.print(" ("); pw.print(System.identityHashCode(obs)); pw.println("):"); - pw.println(" Jobs:"); + pw.increaseIndent(); + pw.println("Jobs:"); + pw.increaseIndent(); for (int j = 0; j < M; j++) { JobInstance inst = obs.mJobs.valueAt(j); - pw.print(" #"); + pw.print("#"); inst.mJobStatus.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, inst.mJobStatus.getSourceUid()); if (inst.mChangedAuthorities != null) { pw.println(":"); + pw.increaseIndent(); if (inst.mTriggerPending) { - pw.print(" Trigger pending: update="); + pw.print("Trigger pending: update="); TimeUtils.formatDuration( inst.mJobStatus.getTriggerContentUpdateDelay(), pw); pw.print(", max="); @@ -436,35 +419,38 @@ public final class ContentObserverController extends StateController { inst.mJobStatus.getTriggerContentMaxDelay(), pw); pw.println(); } - pw.println(" Changed Authorities:"); + pw.println("Changed Authorities:"); for (int k = 0; k < inst.mChangedAuthorities.size(); k++) { - pw.print(" "); pw.println(inst.mChangedAuthorities.valueAt(k)); } if (inst.mChangedUris != null) { pw.println(" Changed URIs:"); for (int k = 0; k < inst.mChangedUris.size(); k++) { - pw.print(" "); pw.println(inst.mChangedUris.valueAt(k)); } } + pw.decreaseIndent(); } else { pw.println(); } } + pw.decreaseIndent(); + pw.decreaseIndent(); } } + pw.decreaseIndent(); } } @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.CONTENT_OBSERVER); for (int i = 0; i < mTrackedTasks.size(); i++) { JobStatus js = mTrackedTasks.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } final long jsToken = @@ -493,7 +479,7 @@ public final class ContentObserverController extends StateController { boolean shouldDump = false; for (int j = 0; j < m; j++) { JobInstance inst = obs.mJobs.valueAt(j); - if (inst.mJobStatus.shouldDump(filterUid)) { + if (predicate.test(inst.mJobStatus)) { shouldDump = true; break; } diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java index 323a12634b39..127a5c876657 100644 --- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java +++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java @@ -33,15 +33,16 @@ import android.util.SparseBooleanArray; import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.DeviceIdleController; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; -import com.android.server.job.JobStore; import com.android.server.job.StateControllerProto; import com.android.server.job.StateControllerProto.DeviceIdleJobsController.TrackedJob; -import java.io.PrintWriter; import java.util.Arrays; +import java.util.function.Consumer; +import java.util.function.Predicate; /** * When device is dozing, set constraint for all jobs, except whitelisted apps, as not satisfied. @@ -56,10 +57,6 @@ public final class DeviceIdleJobsController extends StateController { static final int PROCESS_BACKGROUND_JOBS = 1; - // Singleton factory - private static Object sCreationLock = new Object(); - private static DeviceIdleJobsController sController; - /** * These are jobs added with a special flag to indicate that they should be exempted from doze * when the app is temp whitelisted or in the foreground. @@ -68,7 +65,6 @@ public final class DeviceIdleJobsController extends StateController { private final SparseBooleanArray mForegroundUids; private final DeviceIdleUpdateFunctor mDeviceIdleUpdateFunctor; private final DeviceIdleJobsDelayHandler mHandler; - private final JobSchedulerService mJobSchedulerService; private final PowerManager mPowerManager; private final DeviceIdleController.LocalService mLocalDeviceIdleController; @@ -79,19 +75,6 @@ public final class DeviceIdleJobsController extends StateController { private int[] mDeviceIdleWhitelistAppIds; private int[] mPowerSaveTempWhitelistAppIds; - /** - * Returns a singleton for the DeviceIdleJobsController - */ - public static DeviceIdleJobsController get(JobSchedulerService service) { - synchronized (sCreationLock) { - if (sController == null) { - sController = new DeviceIdleJobsController(service, service.getContext(), - service.getLock()); - } - return sController; - } - } - // onReceive private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -133,12 +116,10 @@ public final class DeviceIdleJobsController extends StateController { } }; - private DeviceIdleJobsController(JobSchedulerService jobSchedulerService, Context context, - Object lock) { - super(jobSchedulerService, context, lock); + public DeviceIdleJobsController(JobSchedulerService service) { + super(service); - mJobSchedulerService = jobSchedulerService; - mHandler = new DeviceIdleJobsDelayHandler(context.getMainLooper()); + mHandler = new DeviceIdleJobsDelayHandler(mContext.getMainLooper()); // Register for device idle mode changes mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mLocalDeviceIdleController = @@ -168,13 +149,13 @@ public final class DeviceIdleJobsController extends StateController { if (DEBUG) Slog.d(TAG, "mDeviceIdleMode=" + mDeviceIdleMode); if (enabled) { mHandler.removeMessages(PROCESS_BACKGROUND_JOBS); - mJobSchedulerService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor); + mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor); } else { // When coming out of doze, process all foreground uids immediately, while others // will be processed after a delay of 3 seconds. for (int i = 0; i < mForegroundUids.size(); i++) { if (mForegroundUids.valueAt(i)) { - mJobSchedulerService.getJobStore().forEachJobForSourceUid( + mService.getJobStore().forEachJobForSourceUid( mForegroundUids.keyAt(i), mDeviceIdleUpdateFunctor); } } @@ -200,7 +181,7 @@ public final class DeviceIdleJobsController extends StateController { } mForegroundUids.put(uid, active); mDeviceIdleUpdateFunctor.mChanged = false; - mJobSchedulerService.getJobStore().forEachJobForSourceUid(uid, mDeviceIdleUpdateFunctor); + mService.getJobStore().forEachJobForSourceUid(uid, mDeviceIdleUpdateFunctor); if (mDeviceIdleUpdateFunctor.mChanged) { mStateChangedListener.onControllerStateChanged(); } @@ -247,71 +228,64 @@ public final class DeviceIdleJobsController extends StateController { } @Override - public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) { - pw.println("DeviceIdleJobsController"); - pw.println("mDeviceIdleMode=" + mDeviceIdleMode); - mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() { - @Override public void process(JobStatus jobStatus) { - if (!jobStatus.shouldDump(filterUid)) { - return; - } - pw.print(" #"); - jobStatus.printUniqueId(pw); - pw.print(" from "); - UserHandle.formatUid(pw, jobStatus.getSourceUid()); - pw.print(": "); - pw.print(jobStatus.getSourcePackageName()); - pw.print((jobStatus.satisfiedConstraints - & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0 - ? " RUNNABLE" : " WAITING"); - if (jobStatus.dozeWhitelisted) { - pw.print(" WHITELISTED"); - } - if (mAllowInIdleJobs.contains(jobStatus)) { - pw.print(" ALLOWED_IN_DOZE"); - } - pw.println(); + public void dumpControllerStateLocked(final IndentingPrintWriter pw, + final Predicate<JobStatus> predicate) { + pw.println("Idle mode: " + mDeviceIdleMode); + pw.println(); + + mService.getJobStore().forEachJob(predicate, (jobStatus) -> { + pw.print("#"); + jobStatus.printUniqueId(pw); + pw.print(" from "); + UserHandle.formatUid(pw, jobStatus.getSourceUid()); + pw.print(": "); + pw.print(jobStatus.getSourcePackageName()); + pw.print((jobStatus.satisfiedConstraints + & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0 + ? " RUNNABLE" : " WAITING"); + if (jobStatus.dozeWhitelisted) { + pw.print(" WHITELISTED"); } + if (mAllowInIdleJobs.contains(jobStatus)) { + pw.print(" ALLOWED_IN_DOZE"); + } + pw.println(); }); } @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.DEVICE_IDLE); proto.write(StateControllerProto.DeviceIdleJobsController.IS_DEVICE_IDLE_MODE, mDeviceIdleMode); - mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() { - @Override public void process(JobStatus jobStatus) { - if (!jobStatus.shouldDump(filterUid)) { - return; - } - final long jsToken = - proto.start(StateControllerProto.DeviceIdleJobsController.TRACKED_JOBS); + mService.getJobStore().forEachJob(predicate, (jobStatus) -> { + final long jsToken = + proto.start(StateControllerProto.DeviceIdleJobsController.TRACKED_JOBS); - jobStatus.writeToShortProto(proto, TrackedJob.INFO); - proto.write(TrackedJob.SOURCE_UID, jobStatus.getSourceUid()); - proto.write(TrackedJob.SOURCE_PACKAGE_NAME, jobStatus.getSourcePackageName()); - proto.write(TrackedJob.ARE_CONSTRAINTS_SATISFIED, - (jobStatus.satisfiedConstraints & - JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0); - proto.write(TrackedJob.IS_DOZE_WHITELISTED, jobStatus.dozeWhitelisted); - proto.write(TrackedJob.IS_ALLOWED_IN_DOZE, mAllowInIdleJobs.contains(jobStatus)); + jobStatus.writeToShortProto(proto, TrackedJob.INFO); + proto.write(TrackedJob.SOURCE_UID, jobStatus.getSourceUid()); + proto.write(TrackedJob.SOURCE_PACKAGE_NAME, jobStatus.getSourcePackageName()); + proto.write(TrackedJob.ARE_CONSTRAINTS_SATISFIED, + (jobStatus.satisfiedConstraints & + JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0); + proto.write(TrackedJob.IS_DOZE_WHITELISTED, jobStatus.dozeWhitelisted); + proto.write(TrackedJob.IS_ALLOWED_IN_DOZE, mAllowInIdleJobs.contains(jobStatus)); - proto.end(jsToken); - } + proto.end(jsToken); }); proto.end(mToken); proto.end(token); } - final class DeviceIdleUpdateFunctor implements JobStore.JobStatusFunctor { + final class DeviceIdleUpdateFunctor implements Consumer<JobStatus> { boolean mChanged; @Override - public void process(JobStatus jobStatus) { + public void accept(JobStatus jobStatus) { mChanged |= updateTaskStateLocked(jobStatus); } } @@ -328,7 +302,7 @@ public final class DeviceIdleJobsController extends StateController { // Just process all the jobs, the ones in foreground should already be running. synchronized (mLock) { mDeviceIdleUpdateFunctor.mChanged = false; - mJobSchedulerService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor); + mService.getJobStore().forEachJob(mDeviceIdleUpdateFunctor); if (mDeviceIdleUpdateFunctor.mChanged) { mStateChangedListener.onControllerStateChanged(); } diff --git a/services/core/java/com/android/server/job/controllers/IdleController.java b/services/core/java/com/android/server/job/controllers/IdleController.java index 78284e57f42d..1dbcfd6a5bdf 100644 --- a/services/core/java/com/android/server/job/controllers/IdleController.java +++ b/services/core/java/com/android/server/job/controllers/IdleController.java @@ -30,12 +30,12 @@ import android.util.Log; import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.am.ActivityManagerService; import com.android.server.job.JobSchedulerService; -import com.android.server.job.StateChangedListener; import com.android.server.job.StateControllerProto; -import java.io.PrintWriter; +import java.util.function.Predicate; public final class IdleController extends StateController { private static final String TAG = "JobScheduler.Idle"; @@ -49,22 +49,8 @@ public final class IdleController extends StateController { final ArraySet<JobStatus> mTrackedTasks = new ArraySet<>(); IdlenessTracker mIdleTracker; - // Singleton factory - private static Object sCreationLock = new Object(); - private static volatile IdleController sController; - - public static IdleController get(JobSchedulerService service) { - synchronized (sCreationLock) { - if (sController == null) { - sController = new IdleController(service, service.getContext(), service.getLock()); - } - return sController; - } - } - - private IdleController(StateChangedListener stateChangedListener, Context context, - Object lock) { - super(stateChangedListener, context, lock); + public IdleController(JobSchedulerService service) { + super(service); initIdleStateTracking(); } @@ -203,18 +189,17 @@ public final class IdleController extends StateController { } @Override - public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { - pw.print("Idle: "); - pw.println(mIdleTracker.isIdle()); - pw.print("Tracking "); - pw.print(mTrackedTasks.size()); - pw.println(":"); + public void dumpControllerStateLocked(IndentingPrintWriter pw, + Predicate<JobStatus> predicate) { + pw.println("Currently idle: " + mIdleTracker.isIdle()); + pw.println(); + for (int i = 0; i < mTrackedTasks.size(); i++) { final JobStatus js = mTrackedTasks.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } - pw.print(" #"); + pw.print("#"); js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); @@ -223,7 +208,8 @@ public final class IdleController extends StateController { } @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.IDLE); @@ -231,7 +217,7 @@ public final class IdleController extends StateController { for (int i = 0; i < mTrackedTasks.size(); i++) { final JobStatus js = mTrackedTasks.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } final long jsToken = proto.start(StateControllerProto.IdleController.TRACKED_JOBS); diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index d1bb63a8fc0d..56161977908c 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -888,11 +888,6 @@ public final class JobStatus { return mLastFailedRunTime; } - public boolean shouldDump(int filterUid) { - return filterUid == -1 || UserHandle.getAppId(getUid()) == filterUid - || UserHandle.getAppId(getSourceUid()) == filterUid; - } - /** * @return Whether or not this job is ready to run, based on its requirements. This is true if * the constraints are satisfied <strong>or</strong> the deadline on the job has expired. diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java index 88d6bea97e43..495109d88fd7 100644 --- a/services/core/java/com/android/server/job/controllers/StateController.java +++ b/services/core/java/com/android/server/job/controllers/StateController.java @@ -19,10 +19,12 @@ package com.android.server.job.controllers; import android.content.Context; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.job.JobSchedulerService; +import com.android.server.job.JobSchedulerService.Constants; import com.android.server.job.StateChangedListener; -import java.io.PrintWriter; +import java.util.function.Predicate; /** * Incorporates shared controller logic between the various controllers of the JobManager. @@ -30,15 +32,18 @@ import java.io.PrintWriter; * are ready to run, or whether they must be stopped. */ public abstract class StateController { + protected final JobSchedulerService mService; + protected final StateChangedListener mStateChangedListener; protected final Context mContext; protected final Object mLock; - protected final StateChangedListener mStateChangedListener; + protected final Constants mConstants; - public StateController(StateChangedListener stateChangedListener, Context context, - Object lock) { - mStateChangedListener = stateChangedListener; - mContext = context; - mLock = lock; + StateController(JobSchedulerService service) { + mService = service; + mStateChangedListener = service; + mContext = service.getContext(); + mLock = service.getLock(); + mConstants = service.getConstants(); } /** @@ -64,7 +69,8 @@ public abstract class StateController { public void rescheduleForFailureLocked(JobStatus newJob, JobStatus failureToReschedule) { } - public abstract void dumpControllerStateLocked(PrintWriter pw, int filterUid); + public abstract void dumpControllerStateLocked(IndentingPrintWriter pw, + Predicate<JobStatus> predicate); public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, - int filterUid); + Predicate<JobStatus> predicate); } diff --git a/services/core/java/com/android/server/job/controllers/StorageController.java b/services/core/java/com/android/server/job/controllers/StorageController.java index 5b79f397b281..c2ae53f69309 100644 --- a/services/core/java/com/android/server/job/controllers/StorageController.java +++ b/services/core/java/com/android/server/job/controllers/StorageController.java @@ -29,12 +29,12 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.job.JobSchedulerService; -import com.android.server.job.StateChangedListener; import com.android.server.job.StateControllerProto; import com.android.server.storage.DeviceStorageMonitorService; -import java.io.PrintWriter; +import java.util.function.Predicate; /** * Simple controller that tracks the status of the device's storage. @@ -44,36 +44,16 @@ public final class StorageController extends StateController { private static final boolean DEBUG = JobSchedulerService.DEBUG || Log.isLoggable(TAG, Log.DEBUG); - private static final Object sCreationLock = new Object(); - private static volatile StorageController sController; - private final ArraySet<JobStatus> mTrackedTasks = new ArraySet<JobStatus>(); - private StorageTracker mStorageTracker; - - public static StorageController get(JobSchedulerService taskManagerService) { - synchronized (sCreationLock) { - if (sController == null) { - sController = new StorageController(taskManagerService, - taskManagerService.getContext(), taskManagerService.getLock()); - } - } - return sController; - } + private final StorageTracker mStorageTracker; @VisibleForTesting public StorageTracker getTracker() { return mStorageTracker; } - @VisibleForTesting - public static StorageController getForTesting(StateChangedListener stateChangedListener, - Context context) { - return new StorageController(stateChangedListener, context, new Object()); - } - - private StorageController(StateChangedListener stateChangedListener, Context context, - Object lock) { - super(stateChangedListener, context, lock); + public StorageController(JobSchedulerService service) { + super(service); mStorageTracker = new StorageTracker(); mStorageTracker.startTracking(); } @@ -175,20 +155,18 @@ public final class StorageController extends StateController { } @Override - public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { - pw.print("Storage: not low = "); - pw.print(mStorageTracker.isStorageNotLow()); - pw.print(", seq="); - pw.println(mStorageTracker.getSeq()); - pw.print("Tracking "); - pw.print(mTrackedTasks.size()); - pw.println(":"); + public void dumpControllerStateLocked(IndentingPrintWriter pw, + Predicate<JobStatus> predicate) { + pw.println("Not low: " + mStorageTracker.isStorageNotLow()); + pw.println("Sequence: " + mStorageTracker.getSeq()); + pw.println(); + for (int i = 0; i < mTrackedTasks.size(); i++) { final JobStatus js = mTrackedTasks.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } - pw.print(" #"); + pw.print("#"); js.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, js.getSourceUid()); @@ -197,7 +175,8 @@ public final class StorageController extends StateController { } @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.STORAGE); @@ -208,7 +187,7 @@ public final class StorageController extends StateController { for (int i = 0; i < mTrackedTasks.size(); i++) { final JobStatus js = mTrackedTasks.valueAt(i); - if (!js.shouldDump(filterUid)) { + if (!predicate.test(js)) { continue; } final long jsToken = proto.start(StateControllerProto.StorageController.TRACKED_JOBS); diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java index cdafc3b7873f..fa48b5e974f6 100644 --- a/services/core/java/com/android/server/job/controllers/TimeController.java +++ b/services/core/java/com/android/server/job/controllers/TimeController.java @@ -30,15 +30,15 @@ import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.job.JobSchedulerService; -import com.android.server.job.StateChangedListener; import com.android.server.job.StateControllerProto; -import java.io.PrintWriter; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.function.Predicate; /** * This class sets an alarm for the next expiring job, and determines whether a job's minimum @@ -62,23 +62,13 @@ public final class TimeController extends StateController { private AlarmManager mAlarmService = null; /** List of tracked jobs, sorted asc. by deadline */ private final List<JobStatus> mTrackedJobs = new LinkedList<>(); - /** Singleton. */ - private static TimeController mSingleton; - public static synchronized TimeController get(JobSchedulerService jms) { - if (mSingleton == null) { - mSingleton = new TimeController(jms, jms.getContext(), jms.getLock()); - } - return mSingleton; - } - - private TimeController(StateChangedListener stateChangedListener, Context context, - Object lock) { - super(stateChangedListener, context, lock); + public TimeController(JobSchedulerService service) { + super(service); mNextJobExpiredElapsedMillis = Long.MAX_VALUE; mNextDelayExpiredElapsedMillis = Long.MAX_VALUE; - mChainedAttributionEnabled = WorkSource.isChainedBatteryAttributionEnabled(context); + mChainedAttributionEnabled = WorkSource.isChainedBatteryAttributionEnabled(mContext); } /** @@ -348,25 +338,24 @@ public final class TimeController extends StateController { }; @Override - public void dumpControllerStateLocked(PrintWriter pw, int filterUid) { + public void dumpControllerStateLocked(IndentingPrintWriter pw, + Predicate<JobStatus> predicate) { final long nowElapsed = sElapsedRealtimeClock.millis(); - pw.print("Alarms: now="); - pw.print(nowElapsed); - pw.println(); + pw.println("Elapsed clock: " + nowElapsed); + pw.print("Next delay alarm in "); TimeUtils.formatDuration(mNextDelayExpiredElapsedMillis, nowElapsed, pw); pw.println(); pw.print("Next deadline alarm in "); TimeUtils.formatDuration(mNextJobExpiredElapsedMillis, nowElapsed, pw); pw.println(); - pw.print("Tracking "); - pw.print(mTrackedJobs.size()); - pw.println(":"); + pw.println(); + for (JobStatus ts : mTrackedJobs) { - if (!ts.shouldDump(filterUid)) { + if (!predicate.test(ts)) { continue; } - pw.print(" #"); + pw.print("#"); ts.printUniqueId(pw); pw.print(" from "); UserHandle.formatUid(pw, ts.getSourceUid()); @@ -387,7 +376,8 @@ public final class TimeController extends StateController { } @Override - public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) { + public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, + Predicate<JobStatus> predicate) { final long token = proto.start(fieldId); final long mToken = proto.start(StateControllerProto.TIME); @@ -399,7 +389,7 @@ public final class TimeController extends StateController { mNextJobExpiredElapsedMillis - nowElapsed); for (JobStatus ts : mTrackedJobs) { - if (!ts.shouldDump(filterUid)) { + if (!predicate.test(ts)) { continue; } final long tsToken = proto.start(StateControllerProto.TimeController.TRACKED_JOBS); diff --git a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 35cba1855503..887489423b4c 100644 --- a/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -33,12 +33,14 @@ import android.content.pm.PackageManagerInternal; import android.net.Network; import android.net.NetworkCapabilities; import android.os.Build; +import android.os.Handler; import android.os.SystemClock; import android.support.test.runner.AndroidJUnit4; import android.util.DataUnit; import com.android.server.LocalServices; import com.android.server.job.JobSchedulerService; +import com.android.server.job.JobSchedulerService.Constants; import org.junit.Before; import org.junit.Test; @@ -49,6 +51,8 @@ import java.time.ZoneOffset; @RunWith(AndroidJUnit4.class) public class ConnectivityControllerTest { + private Constants mConstants; + @Before public void setUp() throws Exception { // Assume all packages are current SDK @@ -65,23 +69,26 @@ public class ConnectivityControllerTest { Clock.fixed(SystemClock.uptimeMillisClock().instant(), ZoneOffset.UTC); JobSchedulerService.sElapsedRealtimeClock = Clock.fixed(SystemClock.elapsedRealtimeClock().instant(), ZoneOffset.UTC); + + // Assume default constants for now + mConstants = new Constants(); } @Test public void testInsane() throws Exception { - final Network network = new Network(101); + final Network net = new Network(101); final JobInfo.Builder job = createJob() .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); // Slow network is too slow - assertFalse(ConnectivityController.isSatisfied(createJobStatus(job), network, + assertFalse(ConnectivityController.isSatisfied(createJobStatus(job), net, createCapabilities().setLinkUpstreamBandwidthKbps(1) - .setLinkDownstreamBandwidthKbps(1))); + .setLinkDownstreamBandwidthKbps(1), mConstants)); // Fast network looks great - assertTrue(ConnectivityController.isSatisfied(createJobStatus(job), network, + assertTrue(ConnectivityController.isSatisfied(createJobStatus(job), net, createCapabilities().setLinkUpstreamBandwidthKbps(1024) - .setLinkDownstreamBandwidthKbps(1024))); + .setLinkDownstreamBandwidthKbps(1024), mConstants)); } @Test @@ -95,19 +102,19 @@ public class ConnectivityControllerTest { // Uncongested network is whenever { - final Network network = new Network(101); - final NetworkCapabilities capabilities = createCapabilities() + final Network net = new Network(101); + final NetworkCapabilities caps = createCapabilities() .addCapability(NET_CAPABILITY_NOT_CONGESTED); - assertTrue(ConnectivityController.isSatisfied(early, network, capabilities)); - assertTrue(ConnectivityController.isSatisfied(late, network, capabilities)); + assertTrue(ConnectivityController.isSatisfied(early, net, caps, mConstants)); + assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants)); } // Congested network is more selective { - final Network network = new Network(101); - final NetworkCapabilities capabilities = createCapabilities(); - assertFalse(ConnectivityController.isSatisfied(early, network, capabilities)); - assertTrue(ConnectivityController.isSatisfied(late, network, capabilities)); + final Network net = new Network(101); + final NetworkCapabilities caps = createCapabilities(); + assertFalse(ConnectivityController.isSatisfied(early, net, caps, mConstants)); + assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants)); } } @@ -126,25 +133,25 @@ public class ConnectivityControllerTest { // Unmetered network is whenever { - final Network network = new Network(101); - final NetworkCapabilities capabilities = createCapabilities() + final Network net = new Network(101); + final NetworkCapabilities caps = createCapabilities() .addCapability(NET_CAPABILITY_NOT_CONGESTED) .addCapability(NET_CAPABILITY_NOT_METERED); - assertTrue(ConnectivityController.isSatisfied(early, network, capabilities)); - assertTrue(ConnectivityController.isSatisfied(late, network, capabilities)); - assertTrue(ConnectivityController.isSatisfied(earlyPrefetch, network, capabilities)); - assertTrue(ConnectivityController.isSatisfied(latePrefetch, network, capabilities)); + assertTrue(ConnectivityController.isSatisfied(early, net, caps, mConstants)); + assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants)); + assertTrue(ConnectivityController.isSatisfied(earlyPrefetch, net, caps, mConstants)); + assertTrue(ConnectivityController.isSatisfied(latePrefetch, net, caps, mConstants)); } // Metered network is only when prefetching and late { - final Network network = new Network(101); - final NetworkCapabilities capabilities = createCapabilities() + final Network net = new Network(101); + final NetworkCapabilities caps = createCapabilities() .addCapability(NET_CAPABILITY_NOT_CONGESTED); - assertFalse(ConnectivityController.isSatisfied(early, network, capabilities)); - assertFalse(ConnectivityController.isSatisfied(late, network, capabilities)); - assertFalse(ConnectivityController.isSatisfied(earlyPrefetch, network, capabilities)); - assertTrue(ConnectivityController.isSatisfied(latePrefetch, network, capabilities)); + assertFalse(ConnectivityController.isSatisfied(early, net, caps, mConstants)); + assertFalse(ConnectivityController.isSatisfied(late, net, caps, mConstants)); + assertFalse(ConnectivityController.isSatisfied(earlyPrefetch, net, caps, mConstants)); + assertTrue(ConnectivityController.isSatisfied(latePrefetch, net, caps, mConstants)); } } |