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

Commit b1df6237 authored by Kweku Adams's avatar Kweku Adams Committed by Android (Google) Code Review
Browse files

Merge "Split JobScheduler idle value by charging state." into main

parents f3dfa3f2 16a6a795
Loading
Loading
Loading
Loading
+26 −1
Original line number Diff line number Diff line
@@ -18,13 +18,16 @@ package com.android.server.job.controllers;

import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;

import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateControllerProto;
import com.android.server.job.controllers.idle.CarIdlenessTracker;
@@ -89,6 +92,19 @@ public final class IdleController extends RestrictingController implements Idlen
        }
    }

    @Override
    public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
            @NonNull String key) {
        mIdleTracker.processConstant(properties, key);
    }

    @Override
    @GuardedBy("mLock")
    public void onBatteryStateChangedLocked() {
        mIdleTracker.onBatteryStateChanged(
                mService.isBatteryCharging(), mService.isBatteryNotLow());
    }

    /**
     * State-change notifications from the idleness tracker
     */
@@ -119,7 +135,16 @@ public final class IdleController extends RestrictingController implements Idlen
        } else {
            mIdleTracker = new DeviceIdlenessTracker();
        }
        mIdleTracker.startTracking(ctx, this);
        mIdleTracker.startTracking(ctx, mService, this);
    }

    @Override
    public void dumpConstants(IndentingPrintWriter pw) {
        pw.println();
        pw.println("IdleController:");
        pw.increaseIndent();
        mIdleTracker.dumpConstants(pw);
        pw.decreaseIndent();
    }

    @Override
+18 −1
Original line number Diff line number Diff line
@@ -16,10 +16,13 @@

package com.android.server.job.controllers.idle;

import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.provider.DeviceConfig;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -73,7 +76,8 @@ public final class CarIdlenessTracker extends BroadcastReceiver implements Idlen
    }

    @Override
    public void startTracking(Context context, IdlenessListener listener) {
    public void startTracking(Context context, JobSchedulerService service,
            IdlenessListener listener) {
        mIdleListener = listener;

        IntentFilter filter = new IntentFilter();
@@ -94,6 +98,15 @@ public final class CarIdlenessTracker extends BroadcastReceiver implements Idlen
        context.registerReceiver(this, filter, null, AppSchedulingModuleThread.getHandler());
    }

    /** Process the specified constant and update internal constants if relevant. */
    public void processConstant(@NonNull DeviceConfig.Properties properties,
            @NonNull String key) {
    }

    @Override
    public void onBatteryStateChanged(boolean isCharging, boolean isBatteryNotLow) {
    }

    @Override
    public void dump(PrintWriter pw) {
        pw.print("  mIdle: "); pw.println(mIdle);
@@ -118,6 +131,10 @@ public final class CarIdlenessTracker extends BroadcastReceiver implements Idlen
        proto.end(token);
    }

    @Override
    public void dumpConstants(IndentingPrintWriter pw) {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
+103 −3
Original line number Diff line number Diff line
@@ -17,9 +17,12 @@
package com.android.server.job.controllers.idle;

import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;

import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;

import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.UiModeManager;
import android.content.BroadcastReceiver;
@@ -27,10 +30,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.PowerManager;
import android.provider.DeviceConfig;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.AppSchedulingModuleThread;
import com.android.server.am.ActivityManagerService;
import com.android.server.job.JobSchedulerService;
@@ -45,17 +51,38 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
    private static final boolean DEBUG = JobSchedulerService.DEBUG
            || Log.isLoggable(TAG, Log.DEBUG);

    /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */
    private static final String IC_DIT_CONSTANT_PREFIX = "ic_dit_";
    @VisibleForTesting
    static final String KEY_INACTIVITY_IDLE_THRESHOLD_MS =
            IC_DIT_CONSTANT_PREFIX + "inactivity_idle_threshold_ms";
    @VisibleForTesting
    static final String KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS =
            IC_DIT_CONSTANT_PREFIX + "inactivity_idle_stable_power_threshold_ms";
    private static final String KEY_IDLE_WINDOW_SLOP_MS =
            IC_DIT_CONSTANT_PREFIX + "idle_window_slop_ms";

    private AlarmManager mAlarm;
    private PowerManager mPowerManager;

    // After construction, mutations of idle/screen-on/projection states will only happen
    // on the JobScheduler thread, either in onReceive(), in an alarm callback, or in on.*Changed.
    private long mInactivityIdleThreshold;
    private long mInactivityStablePowerIdleThreshold;
    private long mIdleWindowSlop;
    /** Stable power is defined as "charging + battery not low." */
    private boolean mIsStablePower;
    private boolean mIdle;
    private boolean mScreenOn;
    private boolean mDockIdle;
    private boolean mProjectionActive;

    /**
     * Time (in the elapsed realtime timebase) when the idleness check was scheduled. This should
     * be a negative value if the device is not in state to be considered idle.
     */
    private long mIdlenessCheckScheduledElapsed = -1;

    private IdlenessListener mIdleListener;
    private final UiModeManager.OnProjectionStateChangedListener mOnProjectionStateChangedListener =
            this::onProjectionStateChanged;
@@ -76,10 +103,14 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
    }

    @Override
    public void startTracking(Context context, IdlenessListener listener) {
    public void startTracking(Context context, JobSchedulerService service,
            IdlenessListener listener) {
        mIdleListener = listener;
        mInactivityIdleThreshold = context.getResources().getInteger(
                com.android.internal.R.integer.config_jobSchedulerInactivityIdleThreshold);
        mInactivityStablePowerIdleThreshold = context.getResources().getInteger(
                com.android.internal.R.integer
                        .config_jobSchedulerInactivityIdleThresholdOnStablePower);
        mIdleWindowSlop = context.getResources().getInteger(
                com.android.internal.R.integer.config_jobSchedulerIdleWindowSlop);
        mAlarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -107,6 +138,46 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
        context.getSystemService(UiModeManager.class).addOnProjectionStateChangedListener(
                UiModeManager.PROJECTION_TYPE_ALL, AppSchedulingModuleThread.getExecutor(),
                mOnProjectionStateChangedListener);

        mIsStablePower = service.isBatteryCharging() && service.isBatteryNotLow();
    }

    /** Process the specified constant and update internal constants if relevant. */
    public void processConstant(@NonNull DeviceConfig.Properties properties,
            @NonNull String key) {
        switch (key) {
            case KEY_INACTIVITY_IDLE_THRESHOLD_MS:
                // Keep the threshold in the range [1 minute, 4 hours].
                mInactivityIdleThreshold = Math.max(MINUTE_IN_MILLIS, Math.min(4 * HOUR_IN_MILLIS,
                        properties.getLong(key, mInactivityIdleThreshold)));
                // Don't bother updating any pending alarms. Just wait until the next time we
                // attempt to check for idle state to use the new value.
                break;
            case KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS:
                // Keep the threshold in the range [1 minute, 4 hours].
                mInactivityStablePowerIdleThreshold = Math.max(MINUTE_IN_MILLIS,
                        Math.min(4 * HOUR_IN_MILLIS,
                                properties.getLong(key, mInactivityStablePowerIdleThreshold)));
                // Don't bother updating any pending alarms. Just wait until the next time we
                // attempt to check for idle state to use the new value.
                break;
            case KEY_IDLE_WINDOW_SLOP_MS:
                // Keep the slop in the range [1 minute, 15 minutes].
                mIdleWindowSlop = Math.max(MINUTE_IN_MILLIS, Math.min(15 * MINUTE_IN_MILLIS,
                        properties.getLong(key, mIdleWindowSlop)));
                // Don't bother updating any pending alarms. Just wait until the next time we
                // attempt to check for idle state to use the new value.
                break;
        }
    }

    @Override
    public void onBatteryStateChanged(boolean isCharging, boolean isBatteryNotLow) {
        final boolean isStablePower = isCharging && isBatteryNotLow;
        if (mIsStablePower != isStablePower) {
            mIsStablePower = isStablePower;
            maybeScheduleIdlenessCheck("stable power changed");
        }
    }

    private void onProjectionStateChanged(@UiModeManager.ProjectionType int activeProjectionTypes,
@@ -134,8 +205,10 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
    public void dump(PrintWriter pw) {
        pw.print("  mIdle: "); pw.println(mIdle);
        pw.print("  mScreenOn: "); pw.println(mScreenOn);
        pw.print("  mIsStablePower: "); pw.println(mIsStablePower);
        pw.print("  mDockIdle: "); pw.println(mDockIdle);
        pw.print("  mProjectionActive: "); pw.println(mProjectionActive);
        pw.print("  mIdlenessCheckScheduledElapsed: "); pw.println(mIdlenessCheckScheduledElapsed);
    }

    @Override
@@ -161,6 +234,17 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
        proto.end(token);
    }

    @Override
    public void dumpConstants(IndentingPrintWriter pw) {
        pw.println("DeviceIdlenessTracker:");
        pw.increaseIndent();
        pw.print(KEY_INACTIVITY_IDLE_THRESHOLD_MS, mInactivityIdleThreshold).println();
        pw.print(KEY_INACTIVITY_STABLE_POWER_IDLE_THRESHOLD_MS, mInactivityStablePowerIdleThreshold)
                .println();
        pw.print(KEY_IDLE_WINDOW_SLOP_MS, mIdleWindowSlop).println();
        pw.decreaseIndent();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
@@ -220,9 +304,24 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id
    private void maybeScheduleIdlenessCheck(String reason) {
        if ((!mScreenOn || mDockIdle) && !mProjectionActive) {
            final long nowElapsed = sElapsedRealtimeClock.millis();
            final long when = nowElapsed + mInactivityIdleThreshold;
            final long inactivityThresholdMs = mIsStablePower
                    ? mInactivityStablePowerIdleThreshold : mInactivityIdleThreshold;
            if (mIdlenessCheckScheduledElapsed >= 0) {
                if (mIdlenessCheckScheduledElapsed + inactivityThresholdMs <= nowElapsed) {
                    if (DEBUG) {
                        Slog.v(TAG, "Previous idle check @ " + mIdlenessCheckScheduledElapsed
                                + " allows device to be idle now");
                    }
                    handleIdleTrigger();
                    return;
                }
            } else {
                mIdlenessCheckScheduledElapsed = nowElapsed;
            }
            final long when = mIdlenessCheckScheduledElapsed + inactivityThresholdMs;
            if (DEBUG) {
                Slog.v(TAG, "Scheduling idle : " + reason + " now:" + nowElapsed + " when=" + when);
                Slog.v(TAG, "Scheduling idle : " + reason + " now:" + nowElapsed
                        + " checkElapsed=" + mIdlenessCheckScheduledElapsed + " when=" + when);
            }
            mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    when, mIdleWindowSlop, "JS idleness",
@@ -232,6 +331,7 @@ public final class DeviceIdlenessTracker extends BroadcastReceiver implements Id

    private void cancelIdlenessCheck() {
        mAlarm.cancel(mIdleAlarmListener);
        mIdlenessCheckScheduledElapsed = -1;
    }

    private void handleIdleTrigger() {
+15 −1
Original line number Diff line number Diff line
@@ -16,9 +16,14 @@

package com.android.server.job.controllers.idle;

import android.annotation.NonNull;
import android.content.Context;
import android.provider.DeviceConfig;
import android.util.IndentingPrintWriter;
import android.util.proto.ProtoOutputStream;

import com.android.server.job.JobSchedulerService;

import java.io.PrintWriter;

public interface IdlenessTracker {
@@ -29,7 +34,7 @@ public interface IdlenessTracker {
     * non-interacting state.  When the idle state changes thereafter, the given
     * listener must be called to report the new state.
     */
    void startTracking(Context context, IdlenessListener listener);
    void startTracking(Context context, JobSchedulerService service, IdlenessListener listener);

    /**
     * Report whether the device is currently considered "idle" for purposes of
@@ -40,6 +45,12 @@ public interface IdlenessTracker {
     */
    boolean isIdle();

    /** Process the specified constant and update internal constants if relevant. */
    void processConstant(@NonNull DeviceConfig.Properties properties, @NonNull String key);

    /** Called when the battery state changes. */
    void onBatteryStateChanged(boolean isCharging, boolean isBatteryNotLow);

    /**
     * Dump useful information about tracked idleness-related state in plaintext.
     */
@@ -49,4 +60,7 @@ public interface IdlenessTracker {
     * Dump useful information about tracked idleness-related state to proto.
     */
    void dump(ProtoOutputStream proto, long fieldId);

    /** Dump any internal constants the tracker may have. */
    void dumpConstants(IndentingPrintWriter pw);
}
+4 −0
Original line number Diff line number Diff line
@@ -4177,6 +4177,10 @@
    <!-- Inactivity threshold (in milliseconds) used in JobScheduler. JobScheduler will consider
         the device to be "idle" after being inactive for this long. -->
    <integer name="config_jobSchedulerInactivityIdleThreshold">1860000</integer>
    <!-- Inactivity threshold (in milliseconds) used in JobScheduler. JobScheduler will consider
         the device to be "idle" after being inactive for this long if the device is on stable
         power. Stable power is defined as "charging + battery not low". -->
    <integer name="config_jobSchedulerInactivityIdleThresholdOnStablePower">1860000</integer>
    <!-- The alarm window (in milliseconds) that JobScheduler uses to enter the idle state -->
    <integer name="config_jobSchedulerIdleWindowSlop">300000</integer>

Loading