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