1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.job.restrictions; 18 19 import android.app.job.JobInfo; 20 import android.app.job.JobParameters; 21 import android.app.job.JobScheduler; 22 import android.os.PowerManager; 23 import android.os.PowerManager.OnThermalStatusChangedListener; 24 import android.util.IndentingPrintWriter; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 import com.android.server.job.Flags; 28 import com.android.server.job.JobSchedulerService; 29 import com.android.server.job.controllers.JobStatus; 30 31 public class ThermalStatusRestriction extends JobRestriction { 32 private static final String TAG = "ThermalStatusRestriction"; 33 34 /** The threshold at which we start restricting low and min priority jobs. */ 35 private static final int LOW_PRIORITY_THRESHOLD = PowerManager.THERMAL_STATUS_LIGHT; 36 /** The threshold at which we start restricting higher priority jobs. */ 37 private static final int HIGHER_PRIORITY_THRESHOLD = PowerManager.THERMAL_STATUS_MODERATE; 38 /** The lowest threshold at which we start restricting jobs. */ 39 private static final int LOWER_THRESHOLD = LOW_PRIORITY_THRESHOLD; 40 /** The threshold at which we start restricting ALL jobs. */ 41 private static final int UPPER_THRESHOLD = PowerManager.THERMAL_STATUS_SEVERE; 42 43 private volatile int mThermalStatus = PowerManager.THERMAL_STATUS_NONE; 44 ThermalStatusRestriction(JobSchedulerService service)45 public ThermalStatusRestriction(JobSchedulerService service) { 46 super(service, JobParameters.STOP_REASON_DEVICE_STATE, 47 JobScheduler.PENDING_JOB_REASON_DEVICE_STATE, 48 JobParameters.INTERNAL_STOP_REASON_DEVICE_THERMAL); 49 } 50 51 @Override onSystemServicesReady()52 public void onSystemServicesReady() { 53 final PowerManager powerManager = 54 mService.getTestableContext().getSystemService(PowerManager.class); 55 // Use MainExecutor 56 powerManager.addThermalStatusListener(new OnThermalStatusChangedListener() { 57 @Override 58 public void onThermalStatusChanged(int status) { 59 // This is called on the main thread. Do not do any slow operations in it. 60 // mService.onControllerStateChanged() will just post a message, which is okay. 61 62 // There are three buckets: 63 // 1. Below the lower threshold (we don't care about changes within this bucket) 64 // 2. Between the lower and upper thresholds. 65 // -> We care about transitions across buckets 66 // -> We care about transitions within the middle bucket 67 // 3. Upper the upper threshold (we don't care about changes within this bucket) 68 final boolean significantChange = 69 // Handle transitions within and into the bucket we care about (thus 70 // causing us to change our restrictions). 71 (status >= LOWER_THRESHOLD && status <= UPPER_THRESHOLD) 72 // Take care of transitions from the 2nd or 3rd bucket to the 1st 73 // bucket (thus exiting any restrictions we started enforcing). 74 || (mThermalStatus >= LOWER_THRESHOLD && status < LOWER_THRESHOLD) 75 // Take care of transitions from the 1st or 2nd bucket to the 3rd 76 // bucket (thus resulting in us beginning to enforce the tightest 77 // restrictions). 78 || (mThermalStatus < UPPER_THRESHOLD && status > UPPER_THRESHOLD); 79 final boolean increased = mThermalStatus < status; 80 mThermalStatus = status; 81 if (significantChange) { 82 mService.onRestrictionStateChanged(ThermalStatusRestriction.this, increased); 83 } 84 } 85 }); 86 } 87 88 @Override isJobRestricted(JobStatus job, int bias)89 public boolean isJobRestricted(JobStatus job, int bias) { 90 if (Flags.thermalRestrictionsToFgsJobs()) { 91 if (bias >= JobInfo.BIAS_TOP_APP) { 92 // Jobs with BIAS_TOP_APP should not be restricted 93 return false; 94 } 95 } else { 96 if (bias >= JobInfo.BIAS_FOREGROUND_SERVICE) { 97 // Jobs with BIAS_FOREGROUND_SERVICE or higher should not be restricted 98 return false; 99 } 100 } 101 if (mThermalStatus >= UPPER_THRESHOLD) { 102 return true; 103 } 104 final int priority = job.getEffectivePriority(); 105 if (mThermalStatus >= HIGHER_PRIORITY_THRESHOLD) { 106 // For moderate throttling: 107 // Let all user-initiated jobs run. 108 // Only let expedited jobs run if: 109 // 1. They haven't previously run 110 // 2. They're already running and aren't yet in overtime 111 // Only let high priority jobs run if: 112 // They are already running and aren't yet in overtime 113 // Don't let any other job run. 114 if (job.shouldTreatAsUserInitiatedJob()) { 115 return false; 116 } 117 if (job.shouldTreatAsExpeditedJob()) { 118 return job.getNumPreviousAttempts() > 0 119 || (mService.isCurrentlyRunningLocked(job) 120 && mService.isJobInOvertimeLocked(job)); 121 } 122 if (Flags.thermalRestrictionsToFgsJobs()) { 123 // Only let foreground jobs run if: 124 // 1. They haven't previously run 125 // 2. They're already running and aren't yet in overtime 126 if (bias >= JobInfo.BIAS_FOREGROUND_SERVICE 127 && job.getJob().isImportantWhileForeground()) { 128 return job.getNumPreviousAttempts() > 0 129 || (mService.isCurrentlyRunningLocked(job) 130 && mService.isJobInOvertimeLocked(job)); 131 } 132 } 133 if (priority == JobInfo.PRIORITY_HIGH) { 134 return !mService.isCurrentlyRunningLocked(job) 135 || mService.isJobInOvertimeLocked(job); 136 } 137 return true; 138 } 139 if (mThermalStatus >= LOW_PRIORITY_THRESHOLD) { 140 if (Flags.thermalRestrictionsToFgsJobs()) { 141 if (bias >= JobInfo.BIAS_FOREGROUND_SERVICE) { 142 // No restrictions on foreground jobs 143 // on LOW_PRIORITY_THRESHOLD and below 144 return false; 145 } 146 } 147 // For light throttling, throttle all min priority jobs and all low priority jobs that 148 // aren't already running or have been running for long enough. 149 return priority == JobInfo.PRIORITY_MIN 150 || (priority == JobInfo.PRIORITY_LOW 151 && (!mService.isCurrentlyRunningLocked(job) 152 || mService.isJobInOvertimeLocked(job))); 153 } 154 return false; 155 } 156 157 @VisibleForTesting getThermalStatus()158 int getThermalStatus() { 159 return mThermalStatus; 160 } 161 162 @Override dumpConstants(IndentingPrintWriter pw)163 public void dumpConstants(IndentingPrintWriter pw) { 164 pw.print("Thermal status: "); 165 pw.println(mThermalStatus); 166 } 167 } 168