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.os.PowerManager; 22 import android.os.PowerManager.OnThermalStatusChangedListener; 23 import android.util.IndentingPrintWriter; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.server.job.JobSchedulerService; 27 import com.android.server.job.controllers.JobStatus; 28 29 public class ThermalStatusRestriction extends JobRestriction { 30 private static final String TAG = "ThermalStatusRestriction"; 31 32 /** The threshold at which we start restricting low and min priority jobs. */ 33 private static final int LOW_PRIORITY_THRESHOLD = PowerManager.THERMAL_STATUS_LIGHT; 34 /** The threshold at which we start restricting higher priority jobs. */ 35 private static final int HIGHER_PRIORITY_THRESHOLD = PowerManager.THERMAL_STATUS_MODERATE; 36 /** The lowest threshold at which we start restricting jobs. */ 37 private static final int LOWER_THRESHOLD = LOW_PRIORITY_THRESHOLD; 38 /** The threshold at which we start restricting ALL jobs. */ 39 private static final int UPPER_THRESHOLD = PowerManager.THERMAL_STATUS_SEVERE; 40 41 private volatile int mThermalStatus = PowerManager.THERMAL_STATUS_NONE; 42 ThermalStatusRestriction(JobSchedulerService service)43 public ThermalStatusRestriction(JobSchedulerService service) { 44 super(service, JobParameters.STOP_REASON_DEVICE_STATE, 45 JobParameters.INTERNAL_STOP_REASON_DEVICE_THERMAL); 46 } 47 48 @Override onSystemServicesReady()49 public void onSystemServicesReady() { 50 final PowerManager powerManager = 51 mService.getTestableContext().getSystemService(PowerManager.class); 52 // Use MainExecutor 53 powerManager.addThermalStatusListener(new OnThermalStatusChangedListener() { 54 @Override 55 public void onThermalStatusChanged(int status) { 56 // This is called on the main thread. Do not do any slow operations in it. 57 // mService.onControllerStateChanged() will just post a message, which is okay. 58 59 // There are three buckets: 60 // 1. Below the lower threshold (we don't care about changes within this bucket) 61 // 2. Between the lower and upper thresholds. 62 // -> We care about transitions across buckets 63 // -> We care about transitions within the middle bucket 64 // 3. Upper the upper threshold (we don't care about changes within this bucket) 65 final boolean significantChange = 66 // Handle transitions within and into the bucket we care about (thus 67 // causing us to change our restrictions). 68 (status >= LOWER_THRESHOLD && status <= UPPER_THRESHOLD) 69 // Take care of transitions from the 2nd or 3rd bucket to the 1st 70 // bucket (thus exiting any restrictions we started enforcing). 71 || (mThermalStatus >= LOWER_THRESHOLD && status < LOWER_THRESHOLD) 72 // Take care of transitions from the 1st or 2nd bucket to the 3rd 73 // bucket (thus resulting in us beginning to enforce the tightest 74 // restrictions). 75 || (mThermalStatus < UPPER_THRESHOLD && status > UPPER_THRESHOLD); 76 mThermalStatus = status; 77 if (significantChange) { 78 mService.onControllerStateChanged(null); 79 } 80 } 81 }); 82 } 83 84 @Override isJobRestricted(JobStatus job)85 public boolean isJobRestricted(JobStatus job) { 86 if (mThermalStatus >= UPPER_THRESHOLD) { 87 return true; 88 } 89 final int priority = job.getEffectivePriority(); 90 if (mThermalStatus >= HIGHER_PRIORITY_THRESHOLD) { 91 // For moderate throttling, only let expedited jobs and high priority regular jobs that 92 // are already running run. 93 return !job.shouldTreatAsExpeditedJob() 94 && !(priority == JobInfo.PRIORITY_HIGH 95 && mService.isCurrentlyRunningLocked(job)); 96 } 97 if (mThermalStatus >= LOW_PRIORITY_THRESHOLD) { 98 // For light throttling, throttle all min priority jobs and all low priority jobs that 99 // aren't already running. 100 return (priority == JobInfo.PRIORITY_LOW && !mService.isCurrentlyRunningLocked(job)) 101 || priority == JobInfo.PRIORITY_MIN; 102 } 103 return false; 104 } 105 106 @VisibleForTesting getThermalStatus()107 int getThermalStatus() { 108 return mThermalStatus; 109 } 110 111 @Override dumpConstants(IndentingPrintWriter pw)112 public void dumpConstants(IndentingPrintWriter pw) { 113 pw.print("Thermal status: "); 114 pw.println(mThermalStatus); 115 } 116 } 117