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

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

Merge "Account for different charging policies." into main

parents 5cb983e0 00d1a384
Loading
Loading
Loading
Loading
+126 −16
Original line number Diff line number Diff line
@@ -318,7 +318,8 @@ public class JobSchedulerService extends com.android.server.SystemService
    private final List<JobRestriction> mJobRestrictions;

    @GuardedBy("mLock")
    private final BatteryStateTracker mBatteryStateTracker;
    @VisibleForTesting
    final BatteryStateTracker mBatteryStateTracker;

    @GuardedBy("mLock")
    private final SparseArray<String> mCloudMediaProviderPackages = new SparseArray<>();
@@ -4261,20 +4262,34 @@ public class JobSchedulerService extends com.android.server.SystemService
                .sendToTarget();
    }

    private final class BatteryStateTracker extends BroadcastReceiver {
    @VisibleForTesting
    final class BatteryStateTracker extends BroadcastReceiver
            implements BatteryManagerInternal.ChargingPolicyChangeListener {
        private final BatteryManagerInternal mBatteryManagerInternal;

        /** Last reported battery level. */
        private int mBatteryLevel;
        /** Keep track of whether the battery is charged enough that we want to do work. */
        private boolean mBatteryNotLow;
        /**
         * Track whether we're "charging", where charging means that we're ready to commit to
         * doing work.
         * Charging status based on {@link BatteryManager#ACTION_CHARGING} and
         * {@link BatteryManager#ACTION_DISCHARGING}.
         */
        private boolean mCharging;
        /** Keep track of whether the battery is charged enough that we want to do work. */
        private boolean mBatteryNotLow;
        /**
         * The most recently acquired value of
         * {@link BatteryManager#BATTERY_PROPERTY_CHARGING_POLICY}.
         */
        private int mChargingPolicy;
        /** Track whether there is power connected. It doesn't mean the device is charging. */
        private boolean mPowerConnected;
        /** Sequence number of last broadcast. */
        private int mLastBatterySeq = -1;

        private BroadcastReceiver mMonitor;

        BatteryStateTracker() {
            mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
        }

        public void startTracking() {
@@ -4286,13 +4301,18 @@ public class JobSchedulerService extends com.android.server.SystemService
            // Charging/not charging.
            filter.addAction(BatteryManager.ACTION_CHARGING);
            filter.addAction(BatteryManager.ACTION_DISCHARGING);
            filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
            filter.addAction(Intent.ACTION_POWER_CONNECTED);
            filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
            getTestableContext().registerReceiver(this, filter);

            mBatteryManagerInternal.registerChargingPolicyChangeListener(this);

            // Initialise tracker state.
            BatteryManagerInternal batteryManagerInternal =
                    LocalServices.getService(BatteryManagerInternal.class);
            mBatteryNotLow = !batteryManagerInternal.getBatteryLevelLow();
            mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
            mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
            mBatteryNotLow = !mBatteryManagerInternal.getBatteryLevelLow();
            mCharging = mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
            mChargingPolicy = mBatteryManagerInternal.getChargingPolicy();
        }

        public void setMonitorBatteryLocked(boolean enabled) {
@@ -4315,7 +4335,7 @@ public class JobSchedulerService extends com.android.server.SystemService
        }

        public boolean isCharging() {
            return mCharging;
            return isConsideredCharging();
        }

        public boolean isBatteryNotLow() {
@@ -4326,17 +4346,42 @@ public class JobSchedulerService extends com.android.server.SystemService
            return mMonitor != null;
        }

        public boolean isPowerConnected() {
            return mPowerConnected;
        }

        public int getSeq() {
            return mLastBatterySeq;
        }

        @Override
        public void onChargingPolicyChanged(int newPolicy) {
            synchronized (mLock) {
                if (mChargingPolicy == newPolicy) {
                    return;
                }
                if (DEBUG) {
                    Slog.i(TAG,
                            "Charging policy changed from " + mChargingPolicy + " to " + newPolicy);
                }

                final boolean wasConsideredCharging = isConsideredCharging();
                mChargingPolicy = newPolicy;

                if (isConsideredCharging() != wasConsideredCharging) {
                    for (int c = mControllers.size() - 1; c >= 0; --c) {
                        mControllers.get(c).onBatteryStateChangedLocked();
                    }
                }
            }
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            onReceiveInternal(intent);
        }

        @VisibleForTesting
        public void onReceiveInternal(Intent intent) {
        private void onReceiveInternal(Intent intent) {
            synchronized (mLock) {
                final String action = intent.getAction();
                boolean changed = false;
@@ -4356,21 +4401,49 @@ public class JobSchedulerService extends com.android.server.SystemService
                        mBatteryNotLow = true;
                        changed = true;
                    }
                } else if (Intent.ACTION_BATTERY_LEVEL_CHANGED.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Battery level changed @ "
                                + sElapsedRealtimeClock.millis());
                    }
                    final boolean wasConsideredCharging = isConsideredCharging();
                    mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
                    changed = isConsideredCharging() != wasConsideredCharging;
                } else if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Power connected @ " + sElapsedRealtimeClock.millis());
                    }
                    if (mPowerConnected) {
                        return;
                    }
                    mPowerConnected = true;
                    changed = true;
                } else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Power disconnected @ " + sElapsedRealtimeClock.millis());
                    }
                    if (!mPowerConnected) {
                        return;
                    }
                    mPowerConnected = false;
                    changed = true;
                } else if (BatteryManager.ACTION_CHARGING.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Battery charging @ " + sElapsedRealtimeClock.millis());
                    }
                    if (!mCharging) {
                        final boolean wasConsideredCharging = isConsideredCharging();
                        mCharging = true;
                        changed = true;
                        changed = isConsideredCharging() != wasConsideredCharging;
                    }
                } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Battery discharging @ " + sElapsedRealtimeClock.millis());
                    }
                    if (mCharging) {
                        final boolean wasConsideredCharging = isConsideredCharging();
                        mCharging = false;
                        changed = true;
                        changed = isConsideredCharging() != wasConsideredCharging;
                    }
                }
                mLastBatterySeq =
@@ -4382,6 +4455,30 @@ public class JobSchedulerService extends com.android.server.SystemService
                }
            }
        }

        private boolean isConsideredCharging() {
            if (mCharging) {
                return true;
            }
            // BatteryService (or Health HAL or whatever central location makes sense)
            // should ideally hold this logic so that everyone has a consistent
            // idea of when the device is charging (or an otherwise stable charging/plugged state).
            // TODO(304512874): move this determination to BatteryService
            if (!mPowerConnected) {
                return false;
            }

            if (mChargingPolicy == Integer.MIN_VALUE) {
                // Property not supported on this device.
                return false;
            }
            // Adaptive charging policies don't expose their target battery level, but 80% is a
            // commonly used threshold for battery health, so assume that's what's being used by
            // the policies and use 70%+ as the threshold here for charging in case some
            // implementations choose to discharge the device slightly before recharging back up
            // to the target level.
            return mBatteryLevel >= 70 && BatteryManager.isAdaptiveChargingPolicy(mChargingPolicy);
        }
    }

    final class LocalService implements JobSchedulerInternal {
@@ -5450,6 +5547,13 @@ public class JobSchedulerService extends com.android.server.SystemService
        }
    }

    /** Return {@code true} if the device is connected to power. */
    public boolean isPowerConnected() {
        synchronized (mLock) {
            return mBatteryStateTracker.isPowerConnected();
        }
    }

    int getStorageSeq() {
        synchronized (mLock) {
            return mStorageController.getTracker().getSeq();
@@ -5778,8 +5882,14 @@ public class JobSchedulerService extends com.android.server.SystemService
            mQuotaTracker.dump(pw);
            pw.println();

            pw.print("Power connected: ");
            pw.println(mBatteryStateTracker.isPowerConnected());
            pw.print("Battery charging: ");
            pw.println(mBatteryStateTracker.isCharging());
            pw.println(mBatteryStateTracker.mCharging);
            pw.print("Considered charging: ");
            pw.println(mBatteryStateTracker.isConsideredCharging());
            pw.print("Battery level: ");
            pw.println(mBatteryStateTracker.mBatteryLevel);
            pw.print("Battery not low: ");
            pw.println(mBatteryStateTracker.isBatteryNotLow());
            if (mBatteryStateTracker.isMonitoring()) {
+2 −74
Original line number Diff line number Diff line
@@ -20,12 +20,6 @@ import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;

import android.annotation.NonNull;
import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
@@ -36,7 +30,6 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.AppSchedulingModuleThread;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateControllerProto;

@@ -60,8 +53,6 @@ public final class BatteryController extends RestrictingController {
    @GuardedBy("mLock")
    private final ArraySet<JobStatus> mTopStartedJobs = new ArraySet<>();

    private final PowerTracker mPowerTracker;

    private final FlexibilityController mFlexibilityController;
    /**
     * Helper set to avoid too much GC churn from frequent calls to
@@ -77,15 +68,9 @@ public final class BatteryController extends RestrictingController {
    public BatteryController(JobSchedulerService service,
            FlexibilityController flexibilityController) {
        super(service);
        mPowerTracker = new PowerTracker();
        mFlexibilityController = flexibilityController;
    }

    @Override
    public void startTrackingLocked() {
        mPowerTracker.startTracking();
    }

    @Override
    public void maybeStartTrackingJobLocked(JobStatus taskStatus, JobStatus lastJob) {
        if (taskStatus.hasPowerConstraint()) {
@@ -95,7 +80,7 @@ public final class BatteryController extends RestrictingController {
            if (taskStatus.hasChargingConstraint()) {
                if (hasTopExemptionLocked(taskStatus)) {
                    taskStatus.setChargingConstraintSatisfied(nowElapsed,
                            mPowerTracker.isPowerConnected());
                            mService.isPowerConnected());
                } else {
                    taskStatus.setChargingConstraintSatisfied(nowElapsed,
                            mService.isBatteryCharging() && mService.isBatteryNotLow());
@@ -178,7 +163,7 @@ public final class BatteryController extends RestrictingController {

    @GuardedBy("mLock")
    private void maybeReportNewChargingStateLocked() {
        final boolean powerConnected = mPowerTracker.isPowerConnected();
        final boolean powerConnected = mService.isPowerConnected();
        final boolean stablePower = mService.isBatteryCharging() && mService.isBatteryNotLow();
        final boolean batteryNotLow = mService.isBatteryNotLow();
        if (DEBUG) {
@@ -239,62 +224,6 @@ public final class BatteryController extends RestrictingController {
        mChangedJobs.clear();
    }

    private final class PowerTracker extends BroadcastReceiver {
        /**
         * Track whether there is power connected. It doesn't mean the device is charging.
         * Use {@link JobSchedulerService#isBatteryCharging()} to determine if the device is
         * charging.
         */
        private boolean mPowerConnected;

        PowerTracker() {
        }

        void startTracking() {
            IntentFilter filter = new IntentFilter();

            filter.addAction(Intent.ACTION_POWER_CONNECTED);
            filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
            mContext.registerReceiver(this, filter);

            // Initialize tracker state.
            BatteryManagerInternal batteryManagerInternal =
                    LocalServices.getService(BatteryManagerInternal.class);
            mPowerConnected = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
        }

        boolean isPowerConnected() {
            return mPowerConnected;
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            synchronized (mLock) {
                final String action = intent.getAction();

                if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Power connected @ " + sElapsedRealtimeClock.millis());
                    }
                    if (mPowerConnected) {
                        return;
                    }
                    mPowerConnected = true;
                } else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Power disconnected @ " + sElapsedRealtimeClock.millis());
                    }
                    if (!mPowerConnected) {
                        return;
                    }
                    mPowerConnected = false;
                }

                maybeReportNewChargingStateLocked();
            }
        }
    }

    @VisibleForTesting
    ArraySet<JobStatus> getTrackedJobs() {
        return mTrackedTasks;
@@ -308,7 +237,6 @@ public final class BatteryController extends RestrictingController {
    @Override
    public void dumpControllerStateLocked(IndentingPrintWriter pw,
            Predicate<JobStatus> predicate) {
        pw.println("Power connected: " + mPowerTracker.isPowerConnected());
        pw.println("Stable power: " + (mService.isBatteryCharging() && mService.isBatteryNotLow()));
        pw.println("Not low: " + mService.isBatteryNotLow());

+10 −0
Original line number Diff line number Diff line
@@ -238,6 +238,16 @@ public class BatteryManager {
    public static final int CHARGING_POLICY_ADAPTIVE_LONGLIFE =
                                            OsProtoEnums.CHARGING_POLICY_ADAPTIVE_LONGLIFE; // = 4

    /**
     * Returns true if the policy is some type of adaptive charging policy.
     * @hide
     */
    public static boolean isAdaptiveChargingPolicy(int policy) {
        return policy == CHARGING_POLICY_ADAPTIVE_AC
                || policy == CHARGING_POLICY_ADAPTIVE_AON
                || policy == CHARGING_POLICY_ADAPTIVE_LONGLIFE;
    }

    // values for "battery part status" property
    /**
     * Battery part status is not supported.
+22 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.os;

import android.annotation.NonNull;

/**
 * Battery manager local system service interface.
 *
@@ -84,6 +86,26 @@ public abstract class BatteryManagerInternal {
     */
    public abstract boolean getBatteryLevelLow();

    public interface ChargingPolicyChangeListener {
        void onChargingPolicyChanged(int newPolicy);
    }

    /**
     * Register a listener for changes to {@link BatteryManager#BATTERY_PROPERTY_CHARGING_POLICY}.
     * The charging policy can't be added to the BATTERY_CHANGED intent because it requires
     * the BATTERY_STATS permission.
     */
    public abstract void registerChargingPolicyChangeListener(
            @NonNull ChargingPolicyChangeListener chargingPolicyChangeListener);

    /**
     * Returns the value of {@link BatteryManager#BATTERY_PROPERTY_CHARGING_POLICY}.
     * This will return {@link Integer#MIN_VALUE} if the device does not support the property.
     *
     * @see BatteryManager#getIntProperty(int)
     */
    public abstract int getChargingPolicy();

    /**
     * Returns a non-zero value if an unsupported charger is attached.
     *
+42 −1
Original line number Diff line number Diff line
@@ -16,8 +16,8 @@

package com.android.server;

import static android.os.Flags.stateOfHealthPublic;
import static android.os.Flags.batteryServiceSupportCurrentAdbCommand;
import static android.os.Flags.stateOfHealthPublic;

import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import static com.android.server.health.Utils.copyV1Battery;
@@ -81,6 +81,7 @@ import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * <p>BatteryService monitors the charging status, and charge level of the device
@@ -157,6 +158,12 @@ public final class BatteryService extends SystemService {
    private int mLastChargeCounter;
    private int mLastBatteryCycleCount;
    private int mLastCharingState;
    /**
     * The last seen charging policy. This requires the
     * {@link android.Manifest.permission#BATTERY_STATS} permission and should therefore not be
     * included in the ACTION_BATTERY_CHANGED intent extras.
     */
    private int mLastChargingPolicy;

    private int mSequence = 1;

@@ -197,6 +204,9 @@ public final class BatteryService extends SystemService {
    private ArrayDeque<Bundle> mBatteryLevelsEventQueue;
    private long mLastBatteryLevelChangedSentMs;

    private final CopyOnWriteArraySet<BatteryManagerInternal.ChargingPolicyChangeListener>
            mChargingPolicyChangeListeners = new CopyOnWriteArraySet<>();

    private Bundle mBatteryChangedOptions = BroadcastOptions.makeBasic()
            .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
            .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
@@ -527,6 +537,11 @@ public final class BatteryService extends SystemService {
        shutdownIfNoPowerLocked();
        shutdownIfOverTempLocked();

        if (force || mHealthInfo.chargingPolicy != mLastChargingPolicy) {
            mLastChargingPolicy = mHealthInfo.chargingPolicy;
            mHandler.post(this::notifyChargingPolicyChanged);
        }

        if (force
                || (mHealthInfo.batteryStatus != mLastBatteryStatus
                        || mHealthInfo.batteryHealth != mLastBatteryHealth
@@ -827,6 +842,17 @@ public final class BatteryService extends SystemService {
        mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime();
    }

    private void notifyChargingPolicyChanged() {
        final int newPolicy;
        synchronized (mLock) {
            newPolicy = mLastChargingPolicy;
        }
        for (BatteryManagerInternal.ChargingPolicyChangeListener listener
                : mChargingPolicyChangeListeners) {
            listener.onChargingPolicyChanged(newPolicy);
        }
    }

    // TODO: Current code doesn't work since "--unplugged" flag in BSS was purposefully removed.
    private void logBatteryStatsLocked() {
        IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
@@ -1220,6 +1246,8 @@ public final class BatteryService extends SystemService {
                pw.println("  voltage: " + mHealthInfo.batteryVoltageMillivolts);
                pw.println("  temperature: " + mHealthInfo.batteryTemperatureTenthsCelsius);
                pw.println("  technology: " + mHealthInfo.batteryTechnology);
                pw.println("  Charging state: " + mHealthInfo.chargingState);
                pw.println("  Charging policy: " + mHealthInfo.chargingPolicy);
            } else {
                Shell shell = new Shell();
                shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
@@ -1451,6 +1479,19 @@ public final class BatteryService extends SystemService {
            }
        }

        @Override
        public void registerChargingPolicyChangeListener(
                BatteryManagerInternal.ChargingPolicyChangeListener listener) {
            mChargingPolicyChangeListeners.add(listener);
        }

        @Override
        public int getChargingPolicy() {
            synchronized (mLock) {
                return mLastChargingPolicy;
            }
        }

        @Override
        public int getInvalidCharger() {
            synchronized (mLock) {
Loading