Merge changes Icdb40ee3,I4c239844
* changes: Knobs for connectivity experiments. Mechanical refactoring to improve job dumping.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
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);
|
||||
}
|
||||
|
||||
// Reset the heartbeat alarm based on the new heartbeat duration
|
||||
setNextHeartbeatAlarm();
|
||||
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(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 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);
|
||||
|
||||
@@ -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,22 +288,23 @@ 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) {
|
||||
public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate,
|
||||
Consumer<JobStatus> functor) {
|
||||
mJobSet.forEachJob(filterPredicate, functor);
|
||||
}
|
||||
|
||||
public void forEachJob(int uid, Consumer<JobStatus> functor) {
|
||||
mJobSet.forEachJob(uid, functor);
|
||||
}
|
||||
|
||||
public void forEachJobForSourceUid(int sourceUid, JobStatusFunctor functor) {
|
||||
public void forEachJobForSourceUid(int sourceUid, Consumer<JobStatus> functor) {
|
||||
mJobSet.forEachJobForSourceUid(sourceUid, functor);
|
||||
}
|
||||
|
||||
public interface JobStatusFunctor {
|
||||
public void process(JobStatus jobStatus);
|
||||
}
|
||||
|
||||
/** Version of the db schema. */
|
||||
private static final int JOBS_FILE_VERSION = 0;
|
||||
/** Tag corresponds to constraints this job needs. */
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user