More work on device idle mode and other power stuff.
Add idle mode support to the alarm manager. Introduce
a new concept of flags associated with alarms to tell
the alarm manager how to treat the alarm -- they allow
everything from the alarm that will bring us out of idle
mode, to alarms that are allowed when idle or should
also bring us out of idle. The standalone boolean is
now also a flag.
(Note there is currently no protection from user space
setting the flags however it wants; I will be working
on that in a follow-up change.)
When in idle mode, the alarm manager pushes all alarms
that shouldn't execute during that time over to a
separate list that is not executed until out of idle.
To help with this, I reworked a bit how Alarm objects
are managed, so that when rebatching or moving between
lists we don't have to allocated new objects but can
just use the same existing instance.
Also tweaked the sync manager to deal with idle mode,
which currently just means doing the same thing as when
low on storage -- turning off sync.
Add new ACTION_CHARGING and ACTION_DISCHARGING broadcasts
that apps can listen for to know when the device is actively
charging and discharging. These are better than the old
POWER_CONNECTED and POWER_DISCONNECTED ones because we only
report charging when we actually see that there is enough
power being provided to charge the battery (and will report
discharging if there is not enough power).
The job controller uses these new actions for scheduling
jobs that want to run while plugged in. Removed the
"stable charging" stuff while doing so, since the new
charging state serves as an even better signal for that.
Introduced two new process states: FOREGROUND_SERVICE and
TOP_SLEEPING. This will allow us to treat foreground services
specially (such as still allowing network access to them for
background music playback) while not mixing them together with
whatever happens to be the top activity while the device is
asleep.
Also some other small cleanup here and there.
Change-Id: I7a9808b578bad6f50deb8e1baf919298512a0d3a
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 793d0d3..c5c0ba6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -22,6 +22,7 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.content.Context;
+import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
import android.net.wifi.WifiActivityEnergyInfo;
@@ -127,6 +128,7 @@
static final int MSG_UPDATE_WAKELOCKS = 1;
static final int MSG_REPORT_POWER_CHANGE = 2;
+ static final int MSG_REPORT_CHARGING = 3;
static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
@@ -135,6 +137,7 @@
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
public void batteryPowerChanged(boolean onBattery);
+ public void batterySendBroadcast(Intent intent);
}
final class MyHandler extends Handler {
@@ -156,6 +159,18 @@
cb.batteryPowerChanged(msg.arg1 != 0);
}
break;
+ case MSG_REPORT_CHARGING:
+ if (cb != null) {
+ final String action;
+ synchronized (BatteryStatsImpl.this) {
+ action = mCharging ? BatteryManager.ACTION_CHARGING
+ : BatteryManager.ACTION_DISCHARGING;
+ }
+ Intent intent = new Intent(action);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ cb.batterySendBroadcast(intent);
+ }
+ break;
}
}
}
@@ -393,6 +408,12 @@
boolean mOnBattery;
boolean mOnBatteryInternal;
+ /**
+ * External reporting of whether the device is actually charging.
+ */
+ boolean mCharging = true;
+ int mLastChargingStateLevel;
+
/*
* These keep track of battery levels (1-100) at the last plug event and the last unplug event.
*/
@@ -7243,6 +7264,10 @@
return mOnBattery;
}
+ public boolean isCharging() {
+ return mCharging;
+ }
+
public boolean isScreenOn() {
return mScreenState == Display.STATE_ON;
}
@@ -7802,6 +7827,20 @@
}
}
+ boolean setChargingLocked(boolean charging) {
+ if (mCharging != charging) {
+ mCharging = charging;
+ if (charging) {
+ mHistoryCur.states |= HistoryItem.STATE_CHARGING_FLAG;
+ } else {
+ mHistoryCur.states &= ~HistoryItem.STATE_CHARGING_FLAG;
+ }
+ mHandler.sendEmptyMessage(MSG_REPORT_CHARGING);
+ return true;
+ }
+ return false;
+ }
+
void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
final int oldStatus, final int level) {
boolean doWrite = false;
@@ -7861,6 +7900,10 @@
reset = true;
mDischargeStepTracker.init();
}
+ if (mCharging) {
+ setChargingLocked(false);
+ }
+ mLastChargingStateLevel = level;
mOnBattery = mOnBatteryInternal = true;
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
@@ -7890,6 +7933,7 @@
mDischargeAmountScreenOff = 0;
updateTimeBasesLocked(true, !screenOn, uptime, realtime);
} else {
+ mLastChargingStateLevel = level;
mOnBattery = mOnBatteryInternal = false;
pullPendingStateUpdatesLocked();
mHistoryCur.batteryLevel = (byte)level;
@@ -7982,10 +8026,13 @@
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
}
}
+ // Always start out assuming charging, that will be updated later.
+ mHistoryCur.states |= HistoryItem.STATE_CHARGING_FLAG;
mHistoryCur.batteryStatus = (byte)status;
mHistoryCur.batteryLevel = (byte)level;
mMaxChargeStepLevel = mMinDischargeStepLevel =
mLastChargeStepLevel = mLastDischargeStepLevel = level;
+ mLastChargingStateLevel = level;
} else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
}
@@ -8046,13 +8093,11 @@
mHistoryCur.batteryVoltage = (char)volt;
changed = true;
}
- if (changed) {
- addHistoryRecordLocked(elapsedRealtime, uptime);
- }
long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
| (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
| (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
if (onBattery) {
+ changed |= setChargingLocked(false);
if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
modeBits, elapsedRealtime);
@@ -8064,6 +8109,28 @@
mModStepMode = 0;
}
} else {
+ if (level >= 90) {
+ // If the battery level is at least 90%, always consider the device to be
+ // charging even if it happens to go down a level.
+ changed |= setChargingLocked(true);
+ mLastChargeStepLevel = level;
+ } if (!mCharging) {
+ if (mLastChargeStepLevel < level) {
+ // We have not reporting that we are charging, but the level has now
+ // gone up, so consider the state to be charging.
+ changed |= setChargingLocked(true);
+ mLastChargeStepLevel = level;
+ }
+ } else {
+ if (mLastChargeStepLevel > level) {
+ // We had reported that the device was charging, but here we are with
+ // power connected and the level going down. Looks like the current
+ // power supplied isn't enough, so consider the device to now be
+ // discharging.
+ changed |= setChargingLocked(false);
+ mLastChargeStepLevel = level;
+ }
+ }
if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
modeBits, elapsedRealtime);
@@ -8075,6 +8142,9 @@
mModStepMode = 0;
}
}
+ if (changed) {
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
}
if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
// We don't record history while we are plugged in and fully charged.