Thermal
###手机会觉得热么?在炎热的夏天调用如下服务:
package com.xxx.xxxService
import android.app.job.JobInfo
import android.app.job.JobParameters
import android.app.job.JobScheduler
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
import android.util.Log
class SampleJobService : JobService() {
override fun onStartJob(params: JobParameters?): Boolean {
Log.d(TAG, "onStartJob:=============sucess============== ")
jobFinished(params, false)
scheduleJob(applicationContext)
return false
}
override fun onStopJob(params: JobParameters?): Boolean {
Log.d(TAG, "onStopJob: ")
return false
}
companion object {
private const val TAG = "SampleJobService"
private const val SERVICE_JOB_ID = 123086
fun scheduleJob(context: Context) {
try {
Log.d(TAG, "scheduleJob: start")
val serviceComponent = ComponentName("com.xxx.xxxService",
"com.xxx.xxxService.SampleJobService")
val builder = JobInfo.Builder(SERVICE_JOB_ID, serviceComponent)
builder.setMinimumLatency((5 * 1000).toLong()) // wait at least
builder.setOverrideDeadline((10 * 1000).toLong()) // maximum delay
//setPersisted is false to avoid restriction to start foreground service from background
builder.setPersisted(false)
builder.setPriority(JobInfo.PRIORITY_HIGH)
val jobScheduler = context.getSystemService(JobScheduler::class.java)
var result = jobScheduler.schedule(builder.build())
Log.d(TAG, "=============start==============: $result")
Log.d(TAG, "scheduleJob: job scheduled")
} catch (t: Exception) {
Log.e(TAG, "sample Job schedule exception: " + t.message)
}
}
}
}
发现温度低的早上可以正常运行,温度高的中午居然不运行,是天气热了手机也不行干活了:
查看JobSchedulerService看看都干了些什么
一、Thermal 2、问题发生是的log打印地方
final JobRestriction restriction = checkIfRestricted(job);
if (restriction != null) {
if (DEBUG) {
Slog.v(TAG, "areComponentsInPlaceLocked: " + job.toShortString()
+ " restricted due to " + restriction.getInternalReason());
}
return false;
}
/**
* Check if a job is restricted by any of the declared {@link JobRestriction JobRestrictions}.
* Note, that the jobs with {@link JobInfo#BIAS_FOREGROUND_SERVICE} bias or higher may not
* be restricted, thus we won't even perform the check, but simply return null early.
*
* @param job to be checked
* @return the first {@link JobRestriction} restricting the given job that has been found; null
* - if passes all the restrictions or has {@link JobInfo#BIAS_FOREGROUND_SERVICE} bias
* or higher.
*/
@GuardedBy("mLock")
JobRestriction checkIfRestricted(JobStatus job) {
if (evaluateJobBiasLocked(job) >= JobInfo.BIAS_FOREGROUND_SERVICE) {
// Jobs with BIAS_FOREGROUND_SERVICE or higher should not be restricted
return null;
}
for (int i = mJobRestrictions.size() - 1; i >= 0; i--) {
final JobRestriction restriction = mJobRestrictions.get(i);
if (restriction.isJobRestricted(job)) { //zsg 这里判断是否限制
return restriction;
}
}
return null;
}
二、Thermal 3、mThermalStatus这里要是大于门槛值并且返回true,jobservice就会被限制: ThermalStatusRestriction.java
@Override
public boolean isJobRestricted(JobStatus job) {
Log.i("zsg", "isJobRestricted:mThermalStatus: "+mThermalStatus,new Exception());
if (mThermalStatus >= UPPER_THRESHOLD) {
return true;
}
final int priority = job.getEffectivePriority();
if (mThermalStatus >= HIGHER_PRIORITY_THRESHOLD) {
// For moderate throttling, only let expedited jobs and high priority regular jobs that
// are already running run.
return !job.shouldTreatAsExpeditedJob()
&& !(priority == JobInfo.PRIORITY_HIGH
&& mService.isCurrentlyRunningLocked(job));
}
if (mThermalStatus >= LOW_PRIORITY_THRESHOLD) {
// For light throttling, throttle all min priority jobs and all low priority jobs that
// aren't already running.
return (priority == JobInfo.PRIORITY_LOW && !mService.isCurrentlyRunningLocked(job))
|| priority == JobInfo.PRIORITY_MIN;
}
return false;
}
三、那么mThermalStatus 哪里来的呢?
@Override
public void onSystemServicesReady() {
final PowerManager powerManager =
mService.getTestableContext().getSystemService(PowerManager.class);
// Use MainExecutor
powerManager.addThermalStatusListener(new OnThermalStatusChangedListener() {
@Override
public void onThermalStatusChanged(int status) {
// This is called on the main thread. Do not do any slow operations in it.
// mService.onControllerStateChanged() will just post a message, which is okay.
// There are three buckets:
// 1. Below the lower threshold (we don't care about changes within this bucket)
// 2. Between the lower and upper thresholds.
// -> We care about transitions across buckets
// -> We care about transitions within the middle bucket
// 3. Upper the upper threshold (we don't care about changes within this bucket)
final boolean significantChange =
// Handle transitions within and into the bucket we care about (thus
// causing us to change our restrictions).
(status >= LOWER_THRESHOLD && status <= UPPER_THRESHOLD)
// Take care of transitions from the 2nd or 3rd bucket to the 1st
// bucket (thus exiting any restrictions we started enforcing).
|| (mThermalStatus >= LOWER_THRESHOLD && status < LOWER_THRESHOLD)
// Take care of transitions from the 1st or 2nd bucket to the 3rd
// bucket (thus resulting in us beginning to enforce the tightest
// restrictions).
|| (mThermalStatus < UPPER_THRESHOLD && status > UPPER_THRESHOLD);
mThermalStatus = status;
if (significantChange) {
mService.onControllerStateChanged(null);
}
}
});
}
- 那么看看powermanager的addThermalStatusListener :PowerManager.java
四、Thermal 4、这里给listener传递status值,下面注册的监听mThermalService.registerThermalStatusListener
/**
* This function adds a listener for thermal status change.
*
* @param executor {@link Executor} to handle listener callback.
* @param listener listener to be added.
*/
public void addThermalStatusListener(@NonNull @CallbackExecutor Executor executor,
@NonNull OnThermalStatusChangedListener listener) {
Objects.requireNonNull(listener, "listener cannot be null");
Objects.requireNonNull(executor, "executor cannot be null");
Preconditions.checkArgument(!mListenerMap.containsKey(listener),
"Listener already registered: %s", listener);
IThermalStatusListener internalListener = new IThermalStatusListener.Stub() {
@Override
public void onStatusChange(int status) {
final long token = Binder.clearCallingIdentity();
try {
executor.execute(() -> listener.onThermalStatusChanged(status));
} finally {
Binder.restoreCallingIdentity(token);
}
}
};
try {
if (mThermalService.registerThermalStatusListener(internalListener)) {
mListenerMap.put(listener, internalListener);
} else {
throw new RuntimeException("Listener failed to set");
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- 这个mThermalService就是ThermalManagerService
@Override
public boolean registerThermalStatusListener(IThermalStatusListener listener) {
synchronized (mLock) {
// Notify its callback after new client registered.
final long token = Binder.clearCallingIdentity();
try {
if (!mThermalStatusListeners.register(listener)) {
return false;
}
// Notify its callback after new client registered.
postStatusListener(listener);
return true;
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
五、Thermal 5、这里给listener传递的status
private void postStatusListener(IThermalStatusListener listener) {
final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> {
try {
listener.onStatusChange(mStatus);//zsg mStatus就是最后返回的值 mThermalStatus
} catch (RemoteException | RuntimeException e) {
Slog.e(TAG, "Thermal callback failed to call", e);
}
});
if (!thermalCallbackQueued) {
Slog.e(TAG, "Thermal callback failed to queue");
}
}
六、Thermal 6、这里从hal调用上来通知状态改变
/* HwBinder callback **/
private void onTemperatureChangedCallback(Temperature temperature) {
final long token = Binder.clearCallingIdentity();
try {
onTemperatureChanged(temperature, true);
} finally {
Binder.restoreCallingIdentity(token);
}
}
private void onTemperatureChanged(Temperature temperature, boolean sendStatus) {
shutdownIfNeeded(temperature);
synchronized (mLock) {
Temperature old = mTemperatureMap.put(temperature.getName(), temperature);
if (old == null || old.getStatus() != temperature.getStatus()) {
notifyEventListenersLocked(temperature);
}
if (sendStatus) {
onTemperatureMapChangedLocked();
}
}
}
private void notifyStatusListenersLocked() {
final int length = mThermalStatusListeners.beginBroadcast();
try {
for (int i = 0; i < length; i++) {
final IThermalStatusListener listener =
mThermalStatusListeners.getBroadcastItem(i);
postStatusListener(listener);//zsg Thermal 1、这里通知listener
}
} finally {
mThermalStatusListeners.finishBroadcast();
}
}
private void onTemperatureMapChangedLocked() {
int newStatus = Temperature.THROTTLING_NONE;
final int count = mTemperatureMap.size();
for (int i = 0; i < count; i++) {
Temperature t = mTemperatureMap.valueAt(i);
if (t.getType() == Temperature.TYPE_SKIN && t.getStatus() >= newStatus) {
newStatus = t.getStatus();
}
}
// Do not update if override from shell
if (!mIsStatusOverride) {
setStatusLocked(newStatus);//zsg 这里设置的value
}
}