Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10ae65d2 authored by Amith Yamasani's avatar Amith Yamasani Committed by Android (Google) Code Review
Browse files

Merge "Move device idle logic into a job StateController" into nyc-dev

parents 6ec134dc cb926fce
Loading
Loading
Loading
Loading
+19 −22
Original line number Diff line number Diff line
@@ -198,7 +198,6 @@ public class DeviceIdleController extends SystemService

    private int mActiveIdleOpCount;
    private IBinder mDownloadServiceActive;
    private boolean mSyncActive;
    private boolean mJobsActive;
    private boolean mAlarmsActive;
    private boolean mReportedMaintenanceActivity;
@@ -944,7 +943,7 @@ public class DeviceIdleController extends SystemService
                                null, mIdleStartedDoneReceiver, null, 0, null, null);
                    }
                    // Always start with one active op for the message being sent here.
                    // Now we we done!
                    // Now we are done!
                    decActiveIdleOps();
                    EventLogTags.writeDeviceIdleOffComplete();
                } break;
@@ -1145,10 +1144,6 @@ public class DeviceIdleController extends SystemService
            setNetworkPolicyTempWhitelistCallbackInternal(callback);
        }

        public void setSyncActive(boolean active) {
            DeviceIdleController.this.setSyncActive(active);
        }

        public void setJobsActive(boolean active) {
            DeviceIdleController.this.setJobsActive(active);
        }
@@ -1157,6 +1152,16 @@ public class DeviceIdleController extends SystemService
        public void setAlarmsActive(boolean 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) {
@@ -1165,6 +1170,12 @@ public class DeviceIdleController extends SystemService
        mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
    }

    int[] getPowerSaveWhitelistUserAppIds() {
        synchronized (this) {
            return mPowerSaveWhitelistUserAppIdArray;
        }
    }

    private static File getSystemDir() {
        return new File(Environment.getDataDirectory(), "system");
    }
@@ -1288,7 +1299,6 @@ public class DeviceIdleController extends SystemService

                mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
                mLocalAlarmManager.setDeviceIdleUserWhitelist(mPowerSaveWhitelistUserAppIdArray);

                mDisplayManager.registerDisplayListener(mDisplayListener, null);
                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) {
        synchronized (this) {
            mJobsActive = active;
@@ -1920,7 +1920,7 @@ public class DeviceIdleController extends SystemService
    }

    void reportMaintenanceActivityIfNeededLocked() {
        boolean active = mJobsActive | mSyncActive | (mDownloadServiceActive != null);
        boolean active = mJobsActive | (mDownloadServiceActive != null);
        if (active == mReportedMaintenanceActivity) {
            return;
        }
@@ -1933,7 +1933,7 @@ public class DeviceIdleController extends SystemService
    void exitMaintenanceEarlyIfNeededLocked() {
        if (mState == STATE_IDLE_MAINTENANCE || mLightState == LIGHT_STATE_IDLE_MAINTENANCE) {
            if (mActiveIdleOpCount <= 0 && mDownloadServiceActive == null
                    && !mSyncActive && !mJobsActive && !mAlarmsActive) {
                    && !mJobsActive && !mAlarmsActive) {
                final long now = SystemClock.elapsedRealtime();
                if (DEBUG) {
                    StringBuilder sb = new StringBuilder();
@@ -2741,9 +2741,6 @@ public class DeviceIdleController extends SystemService
                TimeUtils.formatDuration(mMaintenanceStartTime, SystemClock.elapsedRealtime(), pw);
                pw.println();
            }
            if (mSyncActive) {
                pw.print("  mSyncActive="); pw.println(mSyncActive);
            }
            if (mJobsActive) {
                pw.print("  mJobsActive="); pw.println(mJobsActive);
            }
+21 −52
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import com.android.server.job.controllers.AppIdleController;
import com.android.server.job.controllers.BatteryController;
import com.android.server.job.controllers.ConnectivityController;
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.JobStatus;
import com.android.server.job.controllers.StateController;
@@ -163,11 +164,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
     */
    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.
     */
@@ -228,12 +224,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
                    Slog.d(TAG, "Removing jobs for user: " + 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,24 +408,10 @@ public final class JobSchedulerService extends com.android.server.SystemService
        }
    }

    void updateIdleMode(boolean enabled) {
        boolean changed = false;
        boolean rocking;
        synchronized (mLock) {
            if (mDeviceIdleMode != enabled) {
                changed = true;
            }
            rocking = mReadyToRock;
        }
        if (changed) {
            if (rocking) {
                for (int i=0; i<mControllers.size(); i++) {
                    mControllers.get(i).deviceIdleModeChanged(enabled);
                }
            }
    @Override
    public void onDeviceIdleStateChanged(boolean deviceIdle) {
        synchronized (mLock) {
                mDeviceIdleMode = enabled;
                if (enabled) {
            if (deviceIdle) {
                // When becoming idle, make sure no jobs are actively running.
                for (int i=0; i<mActiveServices.size(); i++) {
                    JobServiceContext jsc = mActiveServices.get(i);
@@ -446,7 +422,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
                }
            } else {
                // When coming out of idle, allow thing to start back up.
                    if (rocking) {
                if (mReadyToRock) {
                    if (mLocalDeviceIdleController != null) {
                        if (!mReportedActive) {
                            mReportedActive = true;
@@ -458,7 +434,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
            }
        }
    }
    }

    void reportActive() {
        // active is true if pending queue contains jobs OR some job is running.
@@ -500,6 +475,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
        mControllers.add(BatteryController.get(this));
        mControllers.add(AppIdleController.get(this));
        mControllers.add(ContentObserverController.get(this));
        mControllers.add(DeviceIdleJobsController.get(this));

        mHandler = new JobHandler(context.getMainLooper());
        mJobSchedulerStub = new JobSchedulerStub();
@@ -521,8 +497,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
            getContext().registerReceiverAsUser(
                    mBroadcastReceiver, UserHandle.ALL, filter, null, null);
            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(
                    mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
            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) {
                        for (int controller = 0; controller < mControllers.size(); controller++) {
                            final StateController sc = mControllers.get(controller);
                            sc.deviceIdleModeChanged(mDeviceIdleMode);
                            sc.maybeStartTrackingJobLocked(job, null);
                        }
                    }
@@ -1015,10 +988,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
         */
        private void maybeRunPendingJobsH() {
            synchronized (mLock) {
                if (mDeviceIdleMode) {
                    // If device is idle, we will not schedule jobs to run.
                    return;
                }
                if (DEBUG) {
                    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
         * jobs are always considered pending.
         */
        @Override
        public List<JobInfo> getSystemScheduledPendingJobs() {
            synchronized (mLock) {
                final List<JobInfo> pendingJobs = new ArrayList<JobInfo>();
@@ -1509,7 +1479,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
            }
            pw.println();
            pw.print("mReadyToRock="); pw.println(mReadyToRock);
            pw.print("mDeviceIdleMode="); pw.println(mDeviceIdleMode);
            pw.print("mReportedActive="); pw.println(mReportedActive);
            pw.print("mMaxActiveJobs="); pw.println(mMaxActiveJobs);
        }
+2 −0
Original line number Diff line number Diff line
@@ -37,4 +37,6 @@ public interface StateChangedListener {
     *                  indicates to the scheduler that any ready jobs should be flushed.</strong>
     */
    public void onRunJobNow(JobStatus jobStatus);

    public void onDeviceIdleStateChanged(boolean deviceIdle);
}
+1 −1
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ public class AppIdleController extends StateController {
        pw.println("Parole On: " + mAppIdleParoleOn);
        for (JobStatus task : mTrackedTasks) {
            pw.print(task.getSourcePackageName());
            pw.print(":idle="
            pw.print(":runnable="
                    + ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
            pw.print(", ");
        }
+184 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}
 No newline at end of file
Loading