Merge "Throttle jobs when thermal status is in THROTTLING_SEVERE and above"
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 578a9ae..3cc56ae 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -47,6 +47,8 @@
public static final int REASON_TIMEOUT = JobProtoEnums.STOP_REASON_TIMEOUT; // 3.
/** @hide */
public static final int REASON_DEVICE_IDLE = JobProtoEnums.STOP_REASON_DEVICE_IDLE; // 4.
+ /** @hide */
+ public static final int REASON_DEVICE_THERMAL = JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5.
/** @hide */
public static String getReasonName(int reason) {
diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto
index 2290b2f..bba8328 100644
--- a/core/proto/android/app/job/enums.proto
+++ b/core/proto/android/app/job/enums.proto
@@ -30,4 +30,5 @@
STOP_REASON_PREEMPT = 2;
STOP_REASON_TIMEOUT = 3;
STOP_REASON_DEVICE_IDLE = 4;
+ STOP_REASON_DEVICE_THERMAL = 5;
}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 231caab..c2bc7bf 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -41,6 +41,7 @@
optional int64 last_heartbeat_time_millis = 16;
optional int64 next_heartbeat_time_millis = 17;
optional bool in_parole = 18;
+ optional bool in_thermal = 19;
repeated int32 started_users = 2;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 173f074..e8b2e8b 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -54,6 +54,8 @@
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
+import android.os.IThermalService;
+import android.os.IThermalStatusListener;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
@@ -62,6 +64,7 @@
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
+import android.os.Temperature;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.provider.Settings;
@@ -75,6 +78,7 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
@@ -179,6 +183,11 @@
private final StorageController mStorageController;
/** Need directly for sending uid state changes */
private final DeviceIdleJobsController mDeviceIdleJobsController;
+ /** Need directly for receiving thermal events */
+ private IThermalService mThermalService;
+ /** Thermal constraint. */
+ @GuardedBy("mLock")
+ private boolean mThermalConstraint = false;
/**
* Queue of pending jobs. The JobServiceContext class will receive jobs from this list
@@ -310,6 +319,19 @@
}
/**
+ * Thermal event received from Thermal Service
+ */
+ private final class ThermalStatusListener extends IThermalStatusListener.Stub {
+ @Override public void onStatusChange(int status) {
+ // Throttle for Temperature.THROTTLING_SEVERE and above
+ synchronized (mLock) {
+ mThermalConstraint = status >= Temperature.THROTTLING_SEVERE;
+ }
+ onControllerStateChanged();
+ }
+ }
+
+ /**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
* holding the JobSchedulerService.mLock lock.
@@ -1366,6 +1388,16 @@
}
// Remove any jobs that are not associated with any of the current users.
cancelJobsForNonExistentUsers();
+ // Register thermal callback
+ mThermalService = IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ if (mThermalService != null) {
+ try {
+ mThermalService.registerThermalStatusListener(new ThermalStatusListener());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register thermal callback.", e);
+ }
+ }
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mLock) {
// Let's go!
@@ -1789,14 +1821,26 @@
}
}
+ private boolean isJobThermalConstrainedLocked(JobStatus job) {
+ return mThermalConstraint && job.hasConnectivityConstraint()
+ && (evaluateJobPriorityLocked(job) < JobInfo.PRIORITY_FOREGROUND_APP);
+ }
+
private void stopNonReadyActiveJobsLocked() {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext serviceContext = mActiveServices.get(i);
final JobStatus running = serviceContext.getRunningJobLocked();
- if (running != null && !running.isReady()) {
+ if (running == null) {
+ continue;
+ }
+ if (!running.isReady()) {
serviceContext.cancelExecutingJobLocked(
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
"cancelled due to unsatisfied constraints");
+ } else if (isJobThermalConstrainedLocked(running)) {
+ serviceContext.cancelExecutingJobLocked(
+ JobParameters.REASON_DEVICE_THERMAL,
+ "cancelled due to thermal condition");
}
}
}
@@ -2084,6 +2128,10 @@
return false;
}
+ if (isJobThermalConstrainedLocked(job)) {
+ return false;
+ }
+
final boolean jobPending = mPendingJobs.contains(job);
final boolean jobActive = isCurrentlyActiveLocked(job);
@@ -3033,6 +3081,9 @@
pw.print(" In parole?: ");
pw.print(mInParole);
pw.println();
+ pw.print(" In thermal throttling?: ");
+ pw.print(mThermalConstraint);
+ pw.println();
pw.println();
pw.println("Started users: " + Arrays.toString(mStartedUsers));
@@ -3208,6 +3259,7 @@
proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT_TIME_MILLIS,
mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME - nowUptime);
proto.write(JobSchedulerServiceDumpProto.IN_PAROLE, mInParole);
+ proto.write(JobSchedulerServiceDumpProto.IN_THERMAL, mThermalConstraint);
for (int u : mStartedUsers) {
proto.write(JobSchedulerServiceDumpProto.STARTED_USERS, u);