Merge "Move device idle logic into a job StateController" into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
10ae65d226
@@ -198,7 +198,6 @@ public class DeviceIdleController extends SystemService
|
|||||||
|
|
||||||
private int mActiveIdleOpCount;
|
private int mActiveIdleOpCount;
|
||||||
private IBinder mDownloadServiceActive;
|
private IBinder mDownloadServiceActive;
|
||||||
private boolean mSyncActive;
|
|
||||||
private boolean mJobsActive;
|
private boolean mJobsActive;
|
||||||
private boolean mAlarmsActive;
|
private boolean mAlarmsActive;
|
||||||
private boolean mReportedMaintenanceActivity;
|
private boolean mReportedMaintenanceActivity;
|
||||||
@@ -944,7 +943,7 @@ public class DeviceIdleController extends SystemService
|
|||||||
null, mIdleStartedDoneReceiver, null, 0, null, null);
|
null, mIdleStartedDoneReceiver, null, 0, null, null);
|
||||||
}
|
}
|
||||||
// Always start with one active op for the message being sent here.
|
// Always start with one active op for the message being sent here.
|
||||||
// Now we we done!
|
// Now we are done!
|
||||||
decActiveIdleOps();
|
decActiveIdleOps();
|
||||||
EventLogTags.writeDeviceIdleOffComplete();
|
EventLogTags.writeDeviceIdleOffComplete();
|
||||||
} break;
|
} break;
|
||||||
@@ -1145,10 +1144,6 @@ public class DeviceIdleController extends SystemService
|
|||||||
setNetworkPolicyTempWhitelistCallbackInternal(callback);
|
setNetworkPolicyTempWhitelistCallbackInternal(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSyncActive(boolean active) {
|
|
||||||
DeviceIdleController.this.setSyncActive(active);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setJobsActive(boolean active) {
|
public void setJobsActive(boolean active) {
|
||||||
DeviceIdleController.this.setJobsActive(active);
|
DeviceIdleController.this.setJobsActive(active);
|
||||||
}
|
}
|
||||||
@@ -1157,6 +1152,16 @@ public class DeviceIdleController extends SystemService
|
|||||||
public void setAlarmsActive(boolean active) {
|
public void setAlarmsActive(boolean active) {
|
||||||
DeviceIdleController.this.setAlarmsActive(active);
|
DeviceIdleController.this.setAlarmsActive(active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the array of app ids whitelisted by user. Take care not to
|
||||||
|
* modify this, as it is a reference to the original copy. But the reference
|
||||||
|
* can change when the list changes, so it needs to be re-acquired when
|
||||||
|
* {@link PowerManager#ACTION_POWER_SAVE_WHITELIST_CHANGED} is sent.
|
||||||
|
*/
|
||||||
|
public int[] getPowerSaveWhitelistUserAppIds() {
|
||||||
|
return DeviceIdleController.this.getPowerSaveWhitelistUserAppIds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceIdleController(Context context) {
|
public DeviceIdleController(Context context) {
|
||||||
@@ -1165,6 +1170,12 @@ public class DeviceIdleController extends SystemService
|
|||||||
mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
|
mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int[] getPowerSaveWhitelistUserAppIds() {
|
||||||
|
synchronized (this) {
|
||||||
|
return mPowerSaveWhitelistUserAppIdArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static File getSystemDir() {
|
private static File getSystemDir() {
|
||||||
return new File(Environment.getDataDirectory(), "system");
|
return new File(Environment.getDataDirectory(), "system");
|
||||||
}
|
}
|
||||||
@@ -1288,7 +1299,6 @@ public class DeviceIdleController extends SystemService
|
|||||||
|
|
||||||
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
|
mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
|
||||||
mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
|
mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);
|
||||||
|
|
||||||
mDisplayManager.registerDisplayListener(mDisplayListener, null);
|
mDisplayManager.registerDisplayListener(mDisplayListener, null);
|
||||||
updateDisplayLocked();
|
updateDisplayLocked();
|
||||||
}
|
}
|
||||||
@@ -1877,16 +1887,6 @@ public class DeviceIdleController extends SystemService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSyncActive(boolean active) {
|
|
||||||
synchronized (this) {
|
|
||||||
mSyncActive = active;
|
|
||||||
reportMaintenanceActivityIfNeededLocked();
|
|
||||||
if (!active) {
|
|
||||||
exitMaintenanceEarlyIfNeededLocked();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setJobsActive(boolean active) {
|
void setJobsActive(boolean active) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mJobsActive = active;
|
mJobsActive = active;
|
||||||
@@ -1920,7 +1920,7 @@ public class DeviceIdleController extends SystemService
|
|||||||
}
|
}
|
||||||
|
|
||||||
void reportMaintenanceActivityIfNeededLocked() {
|
void reportMaintenanceActivityIfNeededLocked() {
|
||||||
boolean active = mJobsActive | mSyncActive | (mDownloadServiceActive != null);
|
boolean active = mJobsActive | (mDownloadServiceActive != null);
|
||||||
if (active == mReportedMaintenanceActivity) {
|
if (active == mReportedMaintenanceActivity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1933,7 +1933,7 @@ public class DeviceIdleController extends SystemService
|
|||||||
void exitMaintenanceEarlyIfNeededLocked() {
|
void exitMaintenanceEarlyIfNeededLocked() {
|
||||||
if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
|
if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
|
||||||
if (mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
|
if (mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
|
||||||
&& !mSyncActive && !mJobsActive && !mAlarmsActive) {
|
&& !mJobsActive && !mAlarmsActive) {
|
||||||
final long now = SystemClock.elapsedRealtime();
|
final long now = SystemClock.elapsedRealtime();
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -2741,9 +2741,6 @@ public class DeviceIdleController extends SystemService
|
|||||||
TimeUtils.formatDuration(mMaintenanceStartTime, SystemClock.elapsedRealtime(), pw);
|
TimeUtils.formatDuration(mMaintenanceStartTime, SystemClock.elapsedRealtime(), pw);
|
||||||
pw.println();
|
pw.println();
|
||||||
}
|
}
|
||||||
if (mSyncActive) {
|
|
||||||
pw.print(" mSyncActive="); pw.println(mSyncActive);
|
|
||||||
}
|
|
||||||
if (mJobsActive) {
|
if (mJobsActive) {
|
||||||
pw.print(" mJobsActive="); pw.println(mJobsActive);
|
pw.print(" mJobsActive="); pw.println(mJobsActive);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ import com.android.server.job.controllers.AppIdleController;
|
|||||||
import com.android.server.job.controllers.BatteryController;
|
import com.android.server.job.controllers.BatteryController;
|
||||||
import com.android.server.job.controllers.ConnectivityController;
|
import com.android.server.job.controllers.ConnectivityController;
|
||||||
import com.android.server.job.controllers.ContentObserverController;
|
import com.android.server.job.controllers.ContentObserverController;
|
||||||
|
import com.android.server.job.controllers.DeviceIdleJobsController;
|
||||||
import com.android.server.job.controllers.IdleController;
|
import com.android.server.job.controllers.IdleController;
|
||||||
import com.android.server.job.controllers.JobStatus;
|
import com.android.server.job.controllers.JobStatus;
|
||||||
import com.android.server.job.controllers.StateController;
|
import com.android.server.job.controllers.StateController;
|
||||||
@@ -163,11 +164,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
*/
|
*/
|
||||||
boolean mReadyToRock;
|
boolean mReadyToRock;
|
||||||
|
|
||||||
/**
|
|
||||||
* True when in device idle mode, so we don't want to schedule any jobs.
|
|
||||||
*/
|
|
||||||
boolean mDeviceIdleMode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What we last reported to DeviceIdleController about whether we are active.
|
* What we last reported to DeviceIdleController about whether we are active.
|
||||||
*/
|
*/
|
||||||
@@ -228,12 +224,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
Slog.d(TAG, "Removing jobs for user: " + userId);
|
Slog.d(TAG, "Removing jobs for user: " + userId);
|
||||||
}
|
}
|
||||||
cancelJobsForUser(userId);
|
cancelJobsForUser(userId);
|
||||||
} else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())
|
|
||||||
|| PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
|
|
||||||
updateIdleMode(mPowerManager != null
|
|
||||||
? (mPowerManager.isDeviceIdleMode()
|
|
||||||
|| mPowerManager.isLightDeviceIdleMode())
|
|
||||||
: false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -418,44 +408,29 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateIdleMode(boolean enabled) {
|
@Override
|
||||||
boolean changed = false;
|
public void onDeviceIdleStateChanged(boolean deviceIdle) {
|
||||||
boolean rocking;
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (mDeviceIdleMode != enabled) {
|
if (deviceIdle) {
|
||||||
changed = true;
|
// When becoming idle, make sure no jobs are actively running.
|
||||||
}
|
for (int i=0; i<mActiveServices.size(); i++) {
|
||||||
rocking = mReadyToRock;
|
JobServiceContext jsc = mActiveServices.get(i);
|
||||||
}
|
final JobStatus executing = jsc.getRunningJob();
|
||||||
if (changed) {
|
if (executing != null) {
|
||||||
if (rocking) {
|
jsc.cancelExecutingJob(JobParameters.REASON_DEVICE_IDLE);
|
||||||
for (int i=0; i<mControllers.size(); i++) {
|
}
|
||||||
mControllers.get(i).deviceIdleModeChanged(enabled);
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
synchronized (mLock) {
|
// When coming out of idle, allow thing to start back up.
|
||||||
mDeviceIdleMode = enabled;
|
if (mReadyToRock) {
|
||||||
if (enabled) {
|
if (mLocalDeviceIdleController != null) {
|
||||||
// When becoming idle, make sure no jobs are actively running.
|
if (!mReportedActive) {
|
||||||
for (int i=0; i<mActiveServices.size(); i++) {
|
mReportedActive = true;
|
||||||
JobServiceContext jsc = mActiveServices.get(i);
|
mLocalDeviceIdleController.setJobsActive(true);
|
||||||
final JobStatus executing = jsc.getRunningJob();
|
|
||||||
if (executing != null) {
|
|
||||||
jsc.cancelExecutingJob(JobParameters.REASON_DEVICE_IDLE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// When coming out of idle, allow thing to start back up.
|
|
||||||
if (rocking) {
|
|
||||||
if (mLocalDeviceIdleController != null) {
|
|
||||||
if (!mReportedActive) {
|
|
||||||
mReportedActive = true;
|
|
||||||
mLocalDeviceIdleController.setJobsActive(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
|
|
||||||
}
|
}
|
||||||
|
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -500,6 +475,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
mControllers.add(BatteryController.get(this));
|
mControllers.add(BatteryController.get(this));
|
||||||
mControllers.add(AppIdleController.get(this));
|
mControllers.add(AppIdleController.get(this));
|
||||||
mControllers.add(ContentObserverController.get(this));
|
mControllers.add(ContentObserverController.get(this));
|
||||||
|
mControllers.add(DeviceIdleJobsController.get(this));
|
||||||
|
|
||||||
mHandler = new JobHandler(context.getMainLooper());
|
mHandler = new JobHandler(context.getMainLooper());
|
||||||
mJobSchedulerStub = new JobSchedulerStub();
|
mJobSchedulerStub = new JobSchedulerStub();
|
||||||
@@ -521,8 +497,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
getContext().registerReceiverAsUser(
|
getContext().registerReceiverAsUser(
|
||||||
mBroadcastReceiver, UserHandle.ALL, filter, null, null);
|
mBroadcastReceiver, UserHandle.ALL, filter, null, null);
|
||||||
final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
|
final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
|
||||||
userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
|
|
||||||
userFilter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
|
|
||||||
getContext().registerReceiverAsUser(
|
getContext().registerReceiverAsUser(
|
||||||
mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
|
mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
|
||||||
mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
|
mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
|
||||||
@@ -553,7 +527,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
public void process(JobStatus job) {
|
public void process(JobStatus job) {
|
||||||
for (int controller = 0; controller < mControllers.size(); controller++) {
|
for (int controller = 0; controller < mControllers.size(); controller++) {
|
||||||
final StateController sc = mControllers.get(controller);
|
final StateController sc = mControllers.get(controller);
|
||||||
sc.deviceIdleModeChanged(mDeviceIdleMode);
|
|
||||||
sc.maybeStartTrackingJobLocked(job, null);
|
sc.maybeStartTrackingJobLocked(job, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1015,10 +988,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
*/
|
*/
|
||||||
private void maybeRunPendingJobsH() {
|
private void maybeRunPendingJobsH() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (mDeviceIdleMode) {
|
|
||||||
// If device is idle, we will not schedule jobs to run.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
|
Slog.d(TAG, "pending queue: " + mPendingJobs.size() + " jobs.");
|
||||||
}
|
}
|
||||||
@@ -1188,6 +1157,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
* Returns a list of all pending jobs. A running job is not considered pending. Periodic
|
* Returns a list of all pending jobs. A running job is not considered pending. Periodic
|
||||||
* jobs are always considered pending.
|
* jobs are always considered pending.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public List<JobInfo> getSystemScheduledPendingJobs() {
|
public List<JobInfo> getSystemScheduledPendingJobs() {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
final List<JobInfo> pendingJobs = new ArrayList<JobInfo>();
|
final List<JobInfo> pendingJobs = new ArrayList<JobInfo>();
|
||||||
@@ -1509,7 +1479,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
|
|||||||
}
|
}
|
||||||
pw.println();
|
pw.println();
|
||||||
pw.print("mReadyToRock="); pw.println(mReadyToRock);
|
pw.print("mReadyToRock="); pw.println(mReadyToRock);
|
||||||
pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode);
|
|
||||||
pw.print("mReportedActive="); pw.println(mReportedActive);
|
pw.print("mReportedActive="); pw.println(mReportedActive);
|
||||||
pw.print("mMaxActiveJobs="); pw.println(mMaxActiveJobs);
|
pw.print("mMaxActiveJobs="); pw.println(mMaxActiveJobs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,4 +37,6 @@ public interface StateChangedListener {
|
|||||||
* indicates to the scheduler that any ready jobs should be flushed.</strong>
|
* indicates to the scheduler that any ready jobs should be flushed.</strong>
|
||||||
*/
|
*/
|
||||||
public void onRunJobNow(JobStatus jobStatus);
|
public void onRunJobNow(JobStatus jobStatus);
|
||||||
|
|
||||||
|
public void onDeviceIdleStateChanged(boolean deviceIdle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class AppIdleController extends StateController {
|
|||||||
pw.println("Parole On: " + mAppIdleParoleOn);
|
pw.println("Parole On: " + mAppIdleParoleOn);
|
||||||
for (JobStatus task : mTrackedTasks) {
|
for (JobStatus task : mTrackedTasks) {
|
||||||
pw.print(task.getSourcePackageName());
|
pw.print(task.getSourcePackageName());
|
||||||
pw.print(":idle="
|
pw.print(":runnable="
|
||||||
+ ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
|
+ ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
|
||||||
pw.print(", ");
|
pw.print(", ");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.job.controllers;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
import com.android.server.DeviceIdleController;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
|
import com.android.server.job.JobSchedulerService;
|
||||||
|
import com.android.server.job.StateChangedListener;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When device is dozing, set constraint for all jobs, except whitelisted apps, as not satisfied.
|
||||||
|
* When device is not dozing, set constraint for all jobs as satisfied.
|
||||||
|
*/
|
||||||
|
public class DeviceIdleJobsController extends StateController {
|
||||||
|
|
||||||
|
private static final String LOG_TAG = "DeviceIdleJobsController";
|
||||||
|
private static final boolean LOG_DEBUG = false;
|
||||||
|
|
||||||
|
// Singleton factory
|
||||||
|
private static Object sCreationLock = new Object();
|
||||||
|
final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
|
||||||
|
private static DeviceIdleJobsController sController;
|
||||||
|
|
||||||
|
private final PowerManager mPowerManager;
|
||||||
|
private final DeviceIdleController.LocalService mLocalDeviceIdleController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True when in device idle mode, so we don't want to schedule any jobs.
|
||||||
|
*/
|
||||||
|
private boolean mDeviceIdleMode;
|
||||||
|
private int[] mDeviceIdleWhitelistAppIds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a singleton for the DeviceIdleJobsController
|
||||||
|
*/
|
||||||
|
public static DeviceIdleJobsController get(JobSchedulerService service) {
|
||||||
|
synchronized (sCreationLock) {
|
||||||
|
if (sController == null) {
|
||||||
|
sController = new DeviceIdleJobsController(service, service.getContext(),
|
||||||
|
service.getLock());
|
||||||
|
}
|
||||||
|
return sController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// onReceive
|
||||||
|
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
final String action = intent.getAction();
|
||||||
|
if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)
|
||||||
|
|| PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
|
||||||
|
updateIdleMode(mPowerManager != null
|
||||||
|
? (mPowerManager.isDeviceIdleMode()
|
||||||
|
|| mPowerManager.isLightDeviceIdleMode())
|
||||||
|
: false);
|
||||||
|
} else if (PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(action)) {
|
||||||
|
updateWhitelist();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private DeviceIdleJobsController(StateChangedListener stateChangedListener, Context context,
|
||||||
|
Object lock) {
|
||||||
|
super(stateChangedListener, context, lock);
|
||||||
|
|
||||||
|
// Register for device idle mode changes
|
||||||
|
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||||
|
mLocalDeviceIdleController =
|
||||||
|
LocalServices.getService(DeviceIdleController.LocalService.class);
|
||||||
|
final IntentFilter filter = new IntentFilter();
|
||||||
|
filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
|
||||||
|
filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
|
||||||
|
filter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
|
||||||
|
mContext.registerReceiverAsUser(
|
||||||
|
mBroadcastReceiver, UserHandle.ALL, filter, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateIdleMode(boolean enabled) {
|
||||||
|
boolean changed = false;
|
||||||
|
// Need the whitelist to be ready when going into idle
|
||||||
|
if (mDeviceIdleWhitelistAppIds == null) {
|
||||||
|
updateWhitelist();
|
||||||
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mDeviceIdleMode != enabled) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
mDeviceIdleMode = enabled;
|
||||||
|
if (LOG_DEBUG) Slog.d(LOG_TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
|
||||||
|
for (JobStatus task : mTrackedTasks) {
|
||||||
|
updateTaskStateLocked(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Inform the job scheduler service about idle mode changes
|
||||||
|
if (changed) {
|
||||||
|
mStateChangedListener.onDeviceIdleStateChanged(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the latest whitelist from the device idle controller.
|
||||||
|
*/
|
||||||
|
void updateWhitelist() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (mLocalDeviceIdleController != null) {
|
||||||
|
mDeviceIdleWhitelistAppIds =
|
||||||
|
mLocalDeviceIdleController.getPowerSaveWhitelistUserAppIds();
|
||||||
|
if (LOG_DEBUG) {
|
||||||
|
Slog.d(LOG_TAG, "Got whitelist " + Arrays.toString(mDeviceIdleWhitelistAppIds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given job's scheduling app id exists in the device idle user whitelist.
|
||||||
|
*/
|
||||||
|
boolean isWhitelistedLocked(JobStatus job) {
|
||||||
|
if (mDeviceIdleWhitelistAppIds != null
|
||||||
|
&& ArrayUtils.contains(mDeviceIdleWhitelistAppIds,
|
||||||
|
UserHandle.getAppId(job.getSourceUid()))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTaskStateLocked(JobStatus task) {
|
||||||
|
boolean enableTask = !mDeviceIdleMode || isWhitelistedLocked(task);
|
||||||
|
task.setDeviceNotDozingConstraintSatisfied(enableTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mTrackedTasks.add(jobStatus);
|
||||||
|
updateTaskStateLocked(jobStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void maybeStopTrackingJobLocked(JobStatus jobStatus, boolean forUpdate) {
|
||||||
|
mTrackedTasks.remove(jobStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dumpControllerStateLocked(PrintWriter pw) {
|
||||||
|
pw.println("DeviceIdleJobsController");
|
||||||
|
for (JobStatus task : mTrackedTasks) {
|
||||||
|
pw.print(task.getSourcePackageName());
|
||||||
|
pw.print(":runnable="
|
||||||
|
+ ((task.satisfiedConstraints & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0));
|
||||||
|
pw.print(", ");
|
||||||
|
}
|
||||||
|
pw.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,6 +54,7 @@ public final class JobStatus {
|
|||||||
static final int CONSTRAINT_CONNECTIVITY = 1<<5;
|
static final int CONSTRAINT_CONNECTIVITY = 1<<5;
|
||||||
static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
|
static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
|
||||||
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
|
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
|
||||||
|
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<8;
|
||||||
|
|
||||||
// Soft override: ignore constraints like time that don't affect API availability
|
// Soft override: ignore constraints like time that don't affect API availability
|
||||||
public static final int OVERRIDE_SOFT = 1;
|
public static final int OVERRIDE_SOFT = 1;
|
||||||
@@ -363,6 +364,10 @@ public final class JobStatus {
|
|||||||
return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
|
return setConstraintSatisfied(CONSTRAINT_CONTENT_TRIGGER, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean setDeviceNotDozingConstraintSatisfied(boolean state) {
|
||||||
|
return setConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING, state);
|
||||||
|
}
|
||||||
|
|
||||||
boolean setConstraintSatisfied(int constraint, boolean state) {
|
boolean setConstraintSatisfied(int constraint, boolean state) {
|
||||||
boolean old = (satisfiedConstraints&constraint) != 0;
|
boolean old = (satisfiedConstraints&constraint) != 0;
|
||||||
if (old == state) {
|
if (old == state) {
|
||||||
@@ -380,11 +385,14 @@ public final class JobStatus {
|
|||||||
// Deadline constraint trumps other constraints (except for periodic jobs where deadline
|
// Deadline constraint trumps other constraints (except for periodic jobs where deadline
|
||||||
// is an implementation detail. A periodic job should only run if its constraints are
|
// is an implementation detail. A periodic job should only run if its constraints are
|
||||||
// satisfied).
|
// satisfied).
|
||||||
// AppNotIdle implicit constraint trumps all!
|
// AppNotIdle implicit constraint must be satisfied
|
||||||
|
// DeviceNotDozing implicit constraint must be satisfied
|
||||||
return (isConstraintsSatisfied()
|
return (isConstraintsSatisfied()
|
||||||
|| (!job.isPeriodic()
|
|| (!job.isPeriodic()
|
||||||
&& hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0))
|
&& hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0)
|
||||||
&& (satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0;
|
)
|
||||||
|
&& (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0
|
||||||
|
&& (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static final int CONSTRAINTS_OF_INTEREST =
|
static final int CONSTRAINTS_OF_INTEREST =
|
||||||
@@ -433,6 +441,7 @@ public final class JobStatus {
|
|||||||
+ ",U=" + (job.getTriggerContentUris() != null)
|
+ ",U=" + (job.getTriggerContentUris() != null)
|
||||||
+ ",F=" + numFailures + ",P=" + job.isPersisted()
|
+ ",F=" + numFailures + ",P=" + job.isPersisted()
|
||||||
+ ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
|
+ ",ANI=" + ((satisfiedConstraints&CONSTRAINT_APP_NOT_IDLE) != 0)
|
||||||
|
+ ",DND=" + ((satisfiedConstraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0)
|
||||||
+ (isReady() ? "(READY)" : "")
|
+ (isReady() ? "(READY)" : "")
|
||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
@@ -492,6 +501,9 @@ public final class JobStatus {
|
|||||||
if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
|
if ((constraints&CONSTRAINT_CONTENT_TRIGGER) != 0) {
|
||||||
pw.print(" CONTENT_TRIGGER");
|
pw.print(" CONTENT_TRIGGER");
|
||||||
}
|
}
|
||||||
|
if ((constraints&CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
|
||||||
|
pw.print(" DEVICE_NOT_DOZING");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dumpsys infrastructure
|
// Dumpsys infrastructure
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ public abstract class StateController {
|
|||||||
protected final Context mContext;
|
protected final Context mContext;
|
||||||
protected final Object mLock;
|
protected final Object mLock;
|
||||||
protected final StateChangedListener mStateChangedListener;
|
protected final StateChangedListener mStateChangedListener;
|
||||||
protected boolean mDeviceIdleMode;
|
|
||||||
|
|
||||||
public StateController(StateChangedListener stateChangedListener, Context context,
|
public StateController(StateChangedListener stateChangedListener, Context context,
|
||||||
Object lock) {
|
Object lock) {
|
||||||
@@ -42,10 +41,6 @@ public abstract class StateController {
|
|||||||
mLock = lock;
|
mLock = lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deviceIdleModeChanged(boolean enabled) {
|
|
||||||
mDeviceIdleMode = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement the logic here to decide whether a job should be tracked by this controller.
|
* Implement the logic here to decide whether a job should be tracked by this controller.
|
||||||
* This logic is put here so the JobManager can be completely agnostic of Controller logic.
|
* This logic is put here so the JobManager can be completely agnostic of Controller logic.
|
||||||
|
|||||||
Reference in New Issue
Block a user