summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/display/DisplayManager.java3
-rw-r--r--core/java/android/net/INetworkPolicyManager.aidl3
-rw-r--r--core/java/android/os/BatteryStats.java82
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl1
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java129
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java424
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java8
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java26
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java4
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java31
-rw-r--r--services/java/com/android/server/SystemServer.java1
11 files changed, 649 insertions, 63 deletions
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index b077e06..12e1963 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -472,7 +472,8 @@ public final class DisplayManager {
/**
* Creates a virtual display.
*
- * @see #createVirtualDisplay(String, int, int, int, Surface, int, VirtualDisplay.Callback)
+ * @see #createVirtualDisplay(String, int, int, int, Surface, int,
+ * VirtualDisplay.Callback, Handler)
*/
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 1129c9e..7e92de2 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -54,7 +54,8 @@ interface INetworkPolicyManager {
void setRestrictBackground(boolean restrictBackground);
boolean getRestrictBackground();
+ void setDeviceIdleMode(boolean enabled);
+
NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
boolean isNetworkMetered(in NetworkState state);
-
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index d96a0e9..cab03da 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,7 +30,6 @@ import android.content.pm.ApplicationInfo;
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
import android.util.Printer;
-import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
@@ -1044,14 +1043,15 @@ public abstract class BatteryStats implements Parcelable {
public static final int STATE2_WIFI_SIGNAL_STRENGTH_MASK =
0x7 << STATE2_WIFI_SIGNAL_STRENGTH_SHIFT;
- public static final int STATE2_LOW_POWER_FLAG = 1<<31;
+ public static final int STATE2_POWER_SAVE_FLAG = 1<<31;
public static final int STATE2_VIDEO_ON_FLAG = 1<<30;
public static final int STATE2_WIFI_RUNNING_FLAG = 1<<29;
public static final int STATE2_WIFI_ON_FLAG = 1<<28;
public static final int STATE2_FLASHLIGHT_FLAG = 1<<27;
+ public static final int STATE2_DEVICE_IDLE_FLAG = 1<<26;
public static final int MOST_INTERESTING_STATES2 =
- STATE2_LOW_POWER_FLAG | STATE2_WIFI_ON_FLAG;
+ STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_FLAG;
public int states2;
@@ -1086,10 +1086,18 @@ public abstract class BatteryStats implements Parcelable {
public static final int EVENT_USER_RUNNING = 0x0007;
// Events for foreground user.
public static final int EVENT_USER_FOREGROUND = 0x0008;
- // Events for connectivity changed.
+ // Event for connectivity changed.
public static final int EVENT_CONNECTIVITY_CHANGED = 0x0009;
+ // Event for significant motion taking us out of idle mode.
+ public static final int EVENT_SIGNIFICANT_MOTION = 0x000a;
+ // Event for becoming active taking us out of idle mode.
+ public static final int EVENT_ACTIVE = 0x000b;
+ // Event for a package being installed.
+ public static final int EVENT_PACKAGE_INSTALLED = 0x000c;
+ // Event for a package being uninstalled.
+ public static final int EVENT_PACKAGE_UNINSTALLED = 0x000d;
// Number of event types.
- public static final int EVENT_COUNT = 0x000a;
+ public static final int EVENT_COUNT = 0x000e;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -1486,19 +1494,34 @@ public abstract class BatteryStats implements Parcelable {
long elapsedRealtimeUs, int which);
/**
- * Returns the time in microseconds that low power mode has been enabled while the device was
+ * Returns the time in microseconds that power save mode has been enabled while the device was
* running on battery.
*
* {@hide}
*/
- public abstract long getLowPowerModeEnabledTime(long elapsedRealtimeUs, int which);
+ public abstract long getPowerSaveModeEnabledTime(long elapsedRealtimeUs, int which);
/**
- * Returns the number of times that low power mode was enabled.
+ * Returns the number of times that power save mode was enabled.
*
* {@hide}
*/
- public abstract int getLowPowerModeEnabledCount(int which);
+ public abstract int getPowerSaveModeEnabledCount(int which);
+
+ /**
+ * Returns the time in microseconds that device has been in idle mode while
+ * running on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getDeviceIdleModeEnabledTime(long elapsedRealtimeUs, int which);
+
+ /**
+ * Returns the number of times that the devie has gone in to idle mode.
+ *
+ * {@hide}
+ */
+ public abstract int getDeviceIdleModeEnabledCount(int which);
/**
* Returns the number of times that connectivity state changed.
@@ -1692,11 +1715,12 @@ public abstract class BatteryStats implements Parcelable {
public static final BitDescription[] HISTORY_STATE2_DESCRIPTIONS
= new BitDescription[] {
- new BitDescription(HistoryItem.STATE2_LOW_POWER_FLAG, "low_power", "lp"),
+ new BitDescription(HistoryItem.STATE2_POWER_SAVE_FLAG, "power_save", "ps"),
new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"),
new BitDescription(HistoryItem.STATE2_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
new BitDescription(HistoryItem.STATE2_WIFI_ON_FLAG, "wifi", "W"),
new BitDescription(HistoryItem.STATE2_FLASHLIGHT_FLAG, "flashlight", "fl"),
+ new BitDescription(HistoryItem.STATE2_DEVICE_IDLE_FLAG, "device_idle", "di"),
new BitDescription(HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK,
HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT, "wifi_signal_strength", "Wss",
new String[] { "0", "1", "2", "3", "4" },
@@ -1707,11 +1731,13 @@ public abstract class BatteryStats implements Parcelable {
};
public static final String[] HISTORY_EVENT_NAMES = new String[] {
- "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn"
+ "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
+ "motion", "active", "pkginst", "pkgunin"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
- "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn"
+ "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
+ "Esm", "Eac", "Epi", "Epu"
};
/**
@@ -2310,7 +2336,8 @@ public abstract class BatteryStats implements Parcelable {
final long totalUptime = computeUptime(rawUptime, which);
final long screenOnTime = getScreenOnTime(rawRealtime, which);
final long interactiveTime = getInteractiveTime(rawRealtime, which);
- final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which);
+ final long powerSaveModeEnabledTime = getPowerSaveModeEnabledTime(rawRealtime, which);
+ final long deviceIdleModeEnabledTime = getDeviceIdleModeEnabledTime(rawRealtime, which);
final int connChanges = getNumConnectivityChange(which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
@@ -2382,7 +2409,8 @@ public abstract class BatteryStats implements Parcelable {
fullWakeLockTimeTotal / 1000, partialWakeLockTimeTotal / 1000,
0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which) / 1000,
getMobileRadioActiveAdjustedTime(which) / 1000, interactiveTime / 1000,
- lowPowerModeEnabledTime / 1000, connChanges);
+ powerSaveModeEnabledTime / 1000, connChanges, deviceIdleModeEnabledTime / 1000,
+ getDeviceIdleModeEnabledCount(which));
// Dump screen brightness stats
Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -2849,7 +2877,8 @@ public abstract class BatteryStats implements Parcelable {
final long screenOnTime = getScreenOnTime(rawRealtime, which);
final long interactiveTime = getInteractiveTime(rawRealtime, which);
- final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which);
+ final long powerSaveModeEnabledTime = getPowerSaveModeEnabledTime(rawRealtime, which);
+ final long deviceIdleModeEnabledTime = getDeviceIdleModeEnabledTime(rawRealtime, which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
@@ -2884,22 +2913,33 @@ public abstract class BatteryStats implements Parcelable {
}
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
- if (lowPowerModeEnabledTime != 0) {
+ if (powerSaveModeEnabledTime != 0) {
sb.setLength(0);
sb.append(prefix);
- sb.append(" Low power mode enabled: ");
- formatTimeMs(sb, lowPowerModeEnabledTime / 1000);
+ sb.append(" Power save mode enabled: ");
+ formatTimeMs(sb, powerSaveModeEnabledTime / 1000);
sb.append("(");
- sb.append(formatRatioLocked(lowPowerModeEnabledTime, whichBatteryRealtime));
+ sb.append(formatRatioLocked(powerSaveModeEnabledTime, whichBatteryRealtime));
sb.append(")");
pw.println(sb.toString());
}
+ if (deviceIdleModeEnabledTime != 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Device idling: ");
+ formatTimeMs(sb, deviceIdleModeEnabledTime / 1000);
+ sb.append("(");
+ sb.append(formatRatioLocked(deviceIdleModeEnabledTime, whichBatteryRealtime));
+ sb.append(") "); sb.append(getDeviceIdleModeEnabledCount(which));
+ sb.append("x");
+ pw.println(sb.toString());
+ }
if (phoneOnTime != 0) {
sb.setLength(0);
sb.append(prefix);
sb.append(" Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
- sb.append(") "); sb.append(getPhoneOnCount(which));
+ sb.append(") "); sb.append(getPhoneOnCount(which)); sb.append("x");
}
int connChanges = getNumConnectivityChange(which);
if (connChanges != 0) {
@@ -4721,7 +4761,7 @@ public abstract class BatteryStats implements Parcelable {
prepareForDumpLocked();
dumpLine(pw, 0 /* uid */, "i" /* category */, VERSION_DATA,
- "12", getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion());
+ "13", getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion());
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 87b6ed7..bea4ece 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -111,6 +111,7 @@ interface IBatteryStats {
void noteWifiMulticastDisabledFromSource(in WorkSource ws);
void noteNetworkInterfaceType(String iface, int type);
void noteNetworkStatsEnabled();
+ void noteDeviceIdleMode(boolean enabled, boolean fromActive, boolean fromMotion);
void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f9b1ca1..7d5df46 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -109,7 +109,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 119 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 120 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -307,8 +307,11 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mInteractive;
StopwatchTimer mInteractiveTimer;
- boolean mLowPowerModeEnabled;
- StopwatchTimer mLowPowerModeEnabledTimer;
+ boolean mPowerSaveModeEnabled;
+ StopwatchTimer mPowerSaveModeEnabledTimer;
+
+ boolean mDeviceIdleModeEnabled;
+ StopwatchTimer mDeviceIdleModeEnabledTimer;
boolean mPhoneOn;
StopwatchTimer mPhoneOnTimer;
@@ -1775,17 +1778,18 @@ public final class BatteryStatsImpl extends BatteryStats {
private final Map<String, KernelWakelockStats> readKernelWakelockStats() {
FileInputStream is;
- byte[] buffer = new byte[8192];
+ byte[] buffer = new byte[32*1024];
int len;
- boolean wakeup_sources = false;
+ boolean wakeup_sources;
try {
try {
- is = new FileInputStream("/proc/wakelocks");
+ is = new FileInputStream("/d/wakeup_sources");
+ wakeup_sources = true;
} catch (java.io.FileNotFoundException e) {
try {
- is = new FileInputStream("/d/wakeup_sources");
- wakeup_sources = true;
+ is = new FileInputStream("/proc/wakelocks");
+ wakeup_sources = false;
} catch (java.io.FileNotFoundException e2) {
return null;
}
@@ -1798,6 +1802,9 @@ public final class BatteryStatsImpl extends BatteryStats {
}
if (len > 0) {
+ if (len >= buffer.length) {
+ Slog.wtf(TAG, "Kernel wake locks exceeded buffer size " + buffer.length);
+ }
int i;
for (i=0; i<len; i++) {
if (buffer[i] == '\0') {
@@ -3386,29 +3393,73 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public void noteLowPowerMode(boolean enabled) {
- if (mLowPowerModeEnabled != enabled) {
+ public void notePowerSaveMode(boolean enabled) {
+ if (mPowerSaveModeEnabled != enabled) {
int stepState = enabled ? STEP_LEVEL_MODE_POWER_SAVE : 0;
mModStepMode |= (mCurStepMode&STEP_LEVEL_MODE_POWER_SAVE) ^ stepState;
mCurStepMode = (mCurStepMode&~STEP_LEVEL_MODE_POWER_SAVE) | stepState;
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
- mLowPowerModeEnabled = enabled;
+ mPowerSaveModeEnabled = enabled;
+ if (enabled) {
+ mHistoryCur.states2 |= HistoryItem.STATE2_POWER_SAVE_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode enabled to: "
+ + Integer.toHexString(mHistoryCur.states2));
+ mPowerSaveModeEnabledTimer.startRunningLocked(elapsedRealtime);
+ } else {
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_POWER_SAVE_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Power save mode disabled to: "
+ + Integer.toHexString(mHistoryCur.states2));
+ mPowerSaveModeEnabledTimer.stopRunningLocked(elapsedRealtime);
+ }
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
+ }
+
+ public void noteDeviceIdleModeLocked(boolean enabled, boolean fromActive, boolean fromMotion) {
+ if (mDeviceIdleModeEnabled != enabled) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ mDeviceIdleModeEnabled = enabled;
+ if (fromMotion) {
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_SIGNIFICANT_MOTION,
+ "", 0);
+ }
+ if (fromActive) {
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ACTIVE,
+ "", 0);
+ }
if (enabled) {
- mHistoryCur.states2 |= HistoryItem.STATE2_LOW_POWER_FLAG;
- if (DEBUG_HISTORY) Slog.v(TAG, "Low power mode enabled to: "
+ mHistoryCur.states2 |= HistoryItem.STATE2_DEVICE_IDLE_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Device idle mode enabled to: "
+ Integer.toHexString(mHistoryCur.states2));
- mLowPowerModeEnabledTimer.startRunningLocked(elapsedRealtime);
+ mDeviceIdleModeEnabledTimer.startRunningLocked(elapsedRealtime);
} else {
- mHistoryCur.states2 &= ~HistoryItem.STATE2_LOW_POWER_FLAG;
- if (DEBUG_HISTORY) Slog.v(TAG, "Low power mode disabled to: "
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_DEVICE_IDLE_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Device idle mode disabled to: "
+ Integer.toHexString(mHistoryCur.states2));
- mLowPowerModeEnabledTimer.stopRunningLocked(elapsedRealtime);
+ mDeviceIdleModeEnabledTimer.stopRunningLocked(elapsedRealtime);
}
addHistoryRecordLocked(elapsedRealtime, uptime);
}
}
+ public void notePackageInstalledLocked(String pkgName, int versionCode) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
+ pkgName, versionCode);
+ mNumConnectivityChange++;
+ }
+
+ public void notePackageUninstalledLocked(String pkgName) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_UNINSTALLED,
+ pkgName, 0);
+ mNumConnectivityChange++;
+ }
+
public void notePhoneOnLocked() {
if (!mPhoneOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -4195,12 +4246,20 @@ public final class BatteryStatsImpl extends BatteryStats {
return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
- @Override public long getLowPowerModeEnabledTime(long elapsedRealtimeUs, int which) {
- return mLowPowerModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+ @Override public long getPowerSaveModeEnabledTime(long elapsedRealtimeUs, int which) {
+ return mPowerSaveModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+ }
+
+ @Override public int getPowerSaveModeEnabledCount(int which) {
+ return mPowerSaveModeEnabledTimer.getCountLocked(which);
+ }
+
+ @Override public long getDeviceIdleModeEnabledTime(long elapsedRealtimeUs, int which) {
+ return mDeviceIdleModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
- @Override public int getLowPowerModeEnabledCount(int which) {
- return mLowPowerModeEnabledTimer.getCountLocked(which);
+ @Override public int getDeviceIdleModeEnabledCount(int which) {
+ return mDeviceIdleModeEnabledTimer.getCountLocked(which);
}
@Override public int getNumConnectivityChange(int which) {
@@ -6662,8 +6721,9 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
}
- mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
- mLowPowerModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
+ mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase);
+ mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
+ mDeviceIdleModeEnabledTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase);
mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
@@ -7233,7 +7293,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[i].reset(false);
}
mInteractiveTimer.reset(false);
- mLowPowerModeEnabledTimer.reset(false);
+ mPowerSaveModeEnabledTimer.reset(false);
+ mDeviceIdleModeEnabledTimer.reset(false);
mPhoneOnTimer.reset(false);
mAudioOnTimer.reset(false);
mVideoOnTimer.reset(false);
@@ -8534,7 +8595,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mInteractive = false;
mInteractiveTimer.readSummaryFromParcelLocked(in);
mPhoneOn = false;
- mLowPowerModeEnabledTimer.readSummaryFromParcelLocked(in);
+ mPowerSaveModeEnabledTimer.readSummaryFromParcelLocked(in);
+ mDeviceIdleModeEnabledTimer.readSummaryFromParcelLocked(in);
mPhoneOnTimer.readSummaryFromParcelLocked(in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
@@ -8835,7 +8897,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- mLowPowerModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mPowerSaveModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mDeviceIdleModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -9132,9 +9195,10 @@ public final class BatteryStatsImpl extends BatteryStats {
in);
}
mInteractive = false;
- mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
+ mInteractiveTimer = new StopwatchTimer(null, -10, null, mOnBatteryTimeBase, in);
mPhoneOn = false;
- mLowPowerModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mPowerSaveModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+ mDeviceIdleModeEnabledTimer = new StopwatchTimer(null, -11, null, mOnBatteryTimeBase, in);
mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
@@ -9299,7 +9363,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
}
mInteractiveTimer.writeToParcel(out, uSecRealtime);
- mLowPowerModeEnabledTimer.writeToParcel(out, uSecRealtime);
+ mPowerSaveModeEnabledTimer.writeToParcel(out, uSecRealtime);
+ mDeviceIdleModeEnabledTimer.writeToParcel(out, uSecRealtime);
mPhoneOnTimer.writeToParcel(out, uSecRealtime);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
@@ -9436,8 +9501,10 @@ public final class BatteryStatsImpl extends BatteryStats {
}
pr.println("*** Interactive timer:");
mInteractiveTimer.logState(pr, " ");
- pr.println("*** Low power mode timer:");
- mLowPowerModeEnabledTimer.logState(pr, " ");
+ pr.println("*** Power save mode timer:");
+ mPowerSaveModeEnabledTimer.logState(pr, " ");
+ pr.println("*** Device idle mode timer:");
+ mDeviceIdleModeEnabledTimer.logState(pr, " ");
pr.println("*** Phone timer:");
mPhoneOnTimer.logState(pr, " ");
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
new file mode 100644
index 0000000..062992d
--- /dev/null
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEvent;
+import android.hardware.TriggerEventListener;
+import android.hardware.display.DisplayManager;
+import android.net.INetworkPolicyManager;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.TimeUtils;
+import android.view.Display;
+import com.android.internal.app.IBatteryStats;
+import com.android.server.am.BatteryStatsService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Keeps track of device idleness and drives low power mode based on that.
+ */
+public class DeviceIdleController extends SystemService {
+ private static final String TAG = "DeviceIdleController";
+
+ private static final String ACTION_STEP_IDLE_STATE =
+ "com.android.server.device_idle.STEP_IDLE_STATE";
+
+ // TODO: These need to be moved to system settings.
+
+ /**
+ * This is the time, after becoming inactive, at which we start looking at the
+ * motion sensor to determine if the device is being left alone. We don't do this
+ * immediately after going inactive just because we don't want to be continually running
+ * the significant motion sensor whenever the screen is off.
+ */
+ private static final long DEFAULT_INACTIVE_TIMEOUT = 30*60*1000L;
+ /**
+ * This is the time, after the inactive timeout elapses, that we will wait looking
+ * for significant motion until we truly consider the device to be idle.
+ */
+ private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = 30*60*1000L;
+ /**
+ * This is the initial time, after being idle, that we will allow ourself to be back
+ * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
+ */
+ private static final long DEFAULT_IDLE_PENDING_TIMEOUT = 5*60*1000L;
+ /**
+ * Maximum pending idle timeout (time spent running) we will be allowed to use.
+ */
+ private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = 10*60*1000L;
+ /**
+ * Scaling factor to apply to current pending idle timeout each time we cycle through
+ * that state.
+ */
+ private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
+ /**
+ * This is the initial time that we want to sit in the idle state before waking up
+ * again to return to pending idle and allowing normal work to run.
+ */
+ private static final long DEFAULT_IDLE_TIMEOUT = 60*60*1000L;
+ /**
+ * Maximum idle duration we will be allowed to use.
+ */
+ private static final long DEFAULT_MAX_IDLE_TIMEOUT = 6*60*60*1000L;
+ /**
+ * Scaling factor to apply to current idle timeout each time we cycle through that state.
+ */
+ private static final float DEFAULT_IDLE_FACTOR = 2f;
+
+ private AlarmManager mAlarmManager;
+ private IBatteryStats mBatteryStats;
+ private INetworkPolicyManager mNetworkPolicyManager;
+ private DisplayManager mDisplayManager;
+ private SensorManager mSensorManager;
+ private Sensor mSigMotionSensor;
+ private PendingIntent mAlarmIntent;
+ private Display mCurDisplay;
+ private boolean mScreenOn;
+ private boolean mCharging;
+ private boolean mSigMotionActive;
+
+ /** Device is currently active. */
+ private static final int STATE_ACTIVE = 0;
+ /** Device is inactve (screen off, no motion) and we are waiting to for idle. */
+ private static final int STATE_INACTIVE = 1;
+ /** Device is past the initial inactive period, and waiting for the next idle period. */
+ private static final int STATE_IDLE_PENDING = 2;
+ /** Device is in the idle state, trying to stay asleep as much as possible. */
+ private static final int STATE_IDLE = 3;
+ private static String stateToString(int state) {
+ switch (state) {
+ case STATE_ACTIVE: return "ACTIVE";
+ case STATE_INACTIVE: return "INACTIVE";
+ case STATE_IDLE_PENDING: return "IDLE_PENDING";
+ case STATE_IDLE: return "IDLE";
+ default: return Integer.toString(state);
+ }
+ }
+
+ private int mState;
+
+ private long mNextAlarmTime;
+ private long mNextIdlePendingDelay;
+ private long mNextIdleDelay;
+
+ private final Binder mBinder = new Binder() {
+ @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ DeviceIdleController.this.dump(fd, pw, args);
+ }
+ };
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+ int plugged = intent.getIntExtra("plugged", 0);
+ updateChargingLocked(plugged != 0);
+ } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
+ synchronized (DeviceIdleController.this) {
+ stepIdleStateLocked();
+ }
+ }
+ }
+ };
+
+ private final DisplayManager.DisplayListener mDisplayListener
+ = new DisplayManager.DisplayListener() {
+ @Override public void onDisplayAdded(int displayId) {
+ }
+
+ @Override public void onDisplayRemoved(int displayId) {
+ }
+
+ @Override public void onDisplayChanged(int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ synchronized (DeviceIdleController.this) {
+ updateDisplayLocked();
+ }
+ }
+ }
+ };
+
+ private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
+ @Override public void onTrigger(TriggerEvent event) {
+ synchronized (DeviceIdleController.this) {
+ significantMotionLocked();
+ }
+ }
+ };
+
+ public DeviceIdleController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ synchronized (this) {
+ mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+ mBatteryStats = BatteryStatsService.getService();
+ mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ mDisplayManager = (DisplayManager) getContext().getSystemService(
+ Context.DISPLAY_SERVICE);
+ mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
+ mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
+
+ Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
+ .setPackage("android")
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(ACTION_STEP_IDLE_STATE);
+ getContext().registerReceiver(mReceiver, filter);
+
+ mDisplayManager.registerDisplayListener(mDisplayListener, null);
+
+ mScreenOn = true;
+ // Start out assuming we are charging. If we aren't, we will at least get
+ // a battery update the next time the level drops.
+ mCharging = true;
+ mState = STATE_ACTIVE;
+ updateDisplayLocked();
+ }
+
+ publishBinderService("deviceidle", mBinder);
+ }
+
+ void updateDisplayLocked() {
+ mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ // We consider any situation where the display is showing something to be it on,
+ // because if there is anything shown we are going to be updating it at some
+ // frequency so can't be allowed to go into deep sleeps.
+ boolean screenOn = mCurDisplay.getState() != Display.STATE_OFF;;
+ if (!screenOn && mScreenOn) {
+ mScreenOn = false;
+ becomeInactiveIfAppropriateLocked();
+ } else if (screenOn) {
+ mScreenOn = true;
+ becomeActiveLocked();
+ }
+ }
+
+ void updateChargingLocked(boolean charging) {
+ if (!charging && mCharging) {
+ mCharging = false;
+ becomeInactiveIfAppropriateLocked();
+ } else if (charging) {
+ mCharging = charging;
+ becomeActiveLocked();
+ }
+ }
+
+ void becomeActiveLocked() {
+ if (mState != STATE_ACTIVE) {
+ try {
+ mNetworkPolicyManager.setDeviceIdleMode(false);
+ mBatteryStats.noteDeviceIdleMode(false, true, false);
+ } catch (RemoteException e) {
+ }
+ mState = STATE_ACTIVE;
+ mNextIdlePendingDelay = 0;
+ mNextIdleDelay = 0;
+ cancelAlarmLocked();
+ stopMonitoringSignificantMotion();
+ }
+ }
+
+ void becomeInactiveIfAppropriateLocked() {
+ if (!mScreenOn && !mCharging && mState == STATE_ACTIVE) {
+ // Screen has turned off; we are now going to become inactive and start
+ // waiting to see if we will ultimately go idle.
+ mState = STATE_INACTIVE;
+ scheduleAlarmLocked(DEFAULT_INACTIVE_TIMEOUT, false);
+ }
+ }
+
+ void stepIdleStateLocked() {
+ switch (mState) {
+ case STATE_INACTIVE:
+ // We have now been inactive long enough, it is time to start looking
+ // for significant motion and sleep some more while doing so.
+ startMonitoringSignificantMotion();
+ scheduleAlarmLocked(DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT, false);
+ // Reset the upcoming idle delays.
+ mNextIdlePendingDelay = DEFAULT_IDLE_PENDING_TIMEOUT;
+ mNextIdleDelay = DEFAULT_IDLE_TIMEOUT;
+ mState = STATE_IDLE_PENDING;
+ break;
+ case STATE_IDLE_PENDING:
+ // We have been waiting to become idle, and now it is time! This is the
+ // only case where we want to use a wakeup alarm, because we do want to
+ // drag the device out of its sleep state in this case to do the next
+ // scheduled work.
+ scheduleAlarmLocked(mNextIdleDelay, true);
+ mNextIdleDelay = (long)(mNextIdleDelay*DEFAULT_IDLE_FACTOR);
+ if (mNextIdleDelay > DEFAULT_MAX_IDLE_TIMEOUT) {
+ mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT;
+ }
+ mState = STATE_IDLE;
+ try {
+ mNetworkPolicyManager.setDeviceIdleMode(true);
+ mBatteryStats.noteDeviceIdleMode(true, false, false);
+ } catch (RemoteException e) {
+ }
+ break;
+ case STATE_IDLE:
+ // We have been idling long enough, now it is time to do some work.
+ scheduleAlarmLocked(mNextIdlePendingDelay, false);
+ mNextIdlePendingDelay = (long)(mNextIdlePendingDelay*DEFAULT_IDLE_PENDING_FACTOR);
+ if (mNextIdlePendingDelay > DEFAULT_MAX_IDLE_PENDING_TIMEOUT) {
+ mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
+ }
+ mState = STATE_IDLE_PENDING;
+ try {
+ mNetworkPolicyManager.setDeviceIdleMode(false);
+ mBatteryStats.noteDeviceIdleMode(false, false, false);
+ } catch (RemoteException e) {
+ }
+ break;
+ }
+ }
+
+ void significantMotionLocked() {
+ // When the sensor goes off, its trigger is automatically removed.
+ mSigMotionActive = false;
+ // The device is not yet active, so we want to go back to the pending idle
+ // state to wait again for no motion. Note that we only monitor for significant
+ // motion after moving out of the inactive state, so no need to worry about that.
+ if (mState != STATE_ACTIVE) {
+ mState = STATE_INACTIVE;
+ try {
+ mNetworkPolicyManager.setDeviceIdleMode(false);
+ mBatteryStats.noteDeviceIdleMode(false, false, true);
+ } catch (RemoteException e) {
+ }
+ stepIdleStateLocked();
+ }
+ }
+
+ void startMonitoringSignificantMotion() {
+ if (mSigMotionSensor != null && !mSigMotionActive) {
+ mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
+ mSigMotionActive = true;
+ }
+ }
+
+ void stopMonitoringSignificantMotion() {
+ if (mSigMotionActive) {
+ mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
+ mSigMotionActive = false;
+ }
+ }
+
+ void cancelAlarmLocked() {
+ if (mNextAlarmTime != 0) {
+ mNextAlarmTime = 0;
+ mAlarmManager.cancel(mAlarmIntent);
+ }
+ }
+
+ void scheduleAlarmLocked(long delay, boolean wakeup) {
+ if (mSigMotionSensor == null) {
+ // If there is no significant motion sensor on this device, then we won't schedule
+ // alarms, because we can't determine if the device is not moving. This effectively
+ // turns off normal exeuction of device idling, although it is still possible to
+ // manually poke it by pretending like the alarm is going off.
+ return;
+ }
+ mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
+ mAlarmManager.set(wakeup ? AlarmManager.ELAPSED_REALTIME_WAKEUP
+ : AlarmManager.ELAPSED_REALTIME, mNextAlarmTime, mAlarmIntent);
+ }
+
+ private void dumpHelp(PrintWriter pw) {
+ pw.println("Device idle controller (deviceidle) dump options:");
+ pw.println(" [-h] [CMD]");
+ pw.println(" -h: print this help text.");
+ pw.println("Commands:");
+ pw.println(" step");
+ pw.println(" Immediately step to next state, without waiting for alarm.");
+ }
+
+ void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump DeviceIdleController from from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " without permission " + android.Manifest.permission.DUMP);
+ return;
+ }
+
+ if (args != null) {
+ for (int i=0; i<args.length; i++) {
+ String arg = args[i];
+ if ("-h".equals(arg)) {
+ dumpHelp(pw);
+ return;
+ } else if ("step".equals(arg)) {
+ synchronized (this) {
+ stepIdleStateLocked();
+ pw.print("Stepped to: "); pw.println(stateToString(mState));
+ }
+ return;
+ } else if (arg.length() > 0 && arg.charAt(0) == '-'){
+ pw.println("Unknown option: " + arg);
+ dumpHelp(pw);
+ return;
+ } else {
+ pw.println("Unknown command: " + arg);
+ dumpHelp(pw);
+ return;
+ }
+ }
+ }
+
+ pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
+ pw.print(" mCurDisplay="); pw.println(mCurDisplay);
+ pw.print(" mScreenOn="); pw.println(mScreenOn);
+ pw.print(" mCharging="); pw.println(mCharging);
+ pw.print(" mSigMotionActive="); pw.println(mSigMotionActive);
+ pw.print(" mState="); pw.println(stateToString(mState));
+ if (mNextAlarmTime != 0) {
+ pw.print(" mNextAlarmTime=");
+ TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
+ pw.println();
+ }
+ if (mNextIdlePendingDelay != 0) {
+ pw.print(" mNextIdlePendingDelay=");
+ TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
+ pw.println();
+ }
+ if (mNextIdleDelay != 0) {
+ pw.print(" mNextIdleDelay=");
+ TimeUtils.formatDuration(mNextIdleDelay, pw);
+ pw.println();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index dcee96a..7f4ccb7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15798,6 +15798,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (userId == UserHandle.USER_OWNER) {
mTaskPersister.removeFromPackageCache(ssp);
}
+ mBatteryStatsService.notePackageUninstalled(ssp);
}
} else {
removeTasksByRemovedPackageComponentsLocked(ssp, userId);
@@ -15824,6 +15825,13 @@ public final class ActivityManagerService extends ActivityManagerNative
if (userId == UserHandle.USER_OWNER) {
mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
}
+ try {
+ ApplicationInfo ai = AppGlobals.getPackageManager().
+ getApplicationInfo(ssp, 0, 0);
+ mBatteryStatsService.notePackageInstalled(ssp,
+ ai != null ? ai.versionCode : 0);
+ } catch (RemoteException e) {
+ }
}
break;
case Intent.ACTION_TIMEZONE_CHANGED:
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 6eacfa9..197b51d 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -86,7 +86,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void initPowerManagement() {
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mPowerManagerInternal.registerLowPowerModeObserver(this);
- mStats.noteLowPowerMode(mPowerManagerInternal.getLowPowerModeEnabled());
+ mStats.notePowerSaveMode(mPowerManagerInternal.getLowPowerModeEnabled());
(new WakeupReasonThread()).start();
}
@@ -109,7 +109,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
@Override
public void onLowPowerModeChanged(boolean enabled) {
synchronized (mStats) {
- mStats.noteLowPowerMode(enabled);
+ mStats.notePowerSaveMode(enabled);
}
}
@@ -686,6 +686,28 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
}
+ @Override
+ public void noteDeviceIdleMode(boolean enabled, boolean fromActive, boolean fromMotion) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteDeviceIdleModeLocked(enabled, fromActive, fromMotion);
+ }
+ }
+
+ public void notePackageInstalled(String pkgName, int versionCode) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.notePackageInstalledLocked(pkgName, versionCode);
+ }
+ }
+
+ public void notePackageUninstalled(String pkgName) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.notePackageUninstalledLocked(pkgName);
+ }
+ }
+
public boolean isOnBattery() {
return mStats.isOnBattery();
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 83d6986..fe1260d 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
@@ -72,7 +73,8 @@ public class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
static final boolean DEBUG = false;
/** The number of concurrent jobs we run at one time. */
- private static final int MAX_JOB_CONTEXTS_COUNT = 3;
+ private static final int MAX_JOB_CONTEXTS_COUNT
+ = ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
static final String TAG = "JobSchedulerService";
/** Master list of jobs. */
final JobStore mJobs;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index cc0fcf5..a69a95f 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -243,9 +243,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final Object mRulesLock = new Object();
+ volatile boolean mSystemReady;
volatile boolean mScreenOn;
volatile boolean mRestrictBackground;
volatile boolean mRestrictPower;
+ volatile boolean mDeviceIdleMode;
private final boolean mSuppressDefaultPolicy;
@@ -367,11 +369,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
});
mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
+ mSystemReady = true;
// read policy from disk
readPolicyLocked();
- if (mRestrictBackground || mRestrictPower) {
+ if (mRestrictBackground || mRestrictPower || mDeviceIdleMode) {
updateRulesForGlobalChangeLocked(true);
updateNotificationsLocked();
}
@@ -1031,7 +1034,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// will not have a bandwidth limit. Also only do this if restrict
// background data use is *not* enabled, since that takes precendence
// use over those networks can have a cost associated with it).
- final boolean powerSave = mRestrictPower && !mRestrictBackground;
+ final boolean powerSave = (mRestrictPower || mDeviceIdleMode) && !mRestrictBackground;
// First, generate identities of all connected networks so we can
// quickly compare them against all defined policies below.
@@ -1696,6 +1699,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ @Override
+ public void setDeviceIdleMode(boolean enabled) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ synchronized (mRulesLock) {
+ if (mDeviceIdleMode != enabled) {
+ mDeviceIdleMode = enabled;
+ if (mSystemReady) {
+ updateRulesForGlobalChangeLocked(true);
+ }
+ }
+ }
+ }
+
private NetworkPolicy findPolicyForNetworkLocked(NetworkIdentity ident) {
for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
NetworkPolicy policy = mNetworkPolicy.valueAt(i);
@@ -1801,8 +1818,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return;
}
+ fout.print("System ready: "); fout.println(mSystemReady);
fout.print("Restrict background: "); fout.println(mRestrictBackground);
fout.print("Restrict power: "); fout.println(mRestrictPower);
+ fout.print("Device idle: "); fout.println(mDeviceIdleMode);
fout.print("Current foreground state: "); fout.println(mCurForegroundState);
fout.println("Network policies:");
fout.increaseIndent();
@@ -1952,8 +1971,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
/**
- * Update rules that might be changed by {@link #mRestrictBackground}
- * or {@link #mRestrictPower} value.
+ * Update rules that might be changed by {@link #mRestrictBackground},
+ * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
*/
void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
final PackageManager pm = mContext.getPackageManager();
@@ -1962,7 +1981,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// If we are in restrict power mode, we allow all important apps
// to have data access. Otherwise, we restrict data access to only
// the top apps.
- mCurForegroundState = (!mRestrictBackground && mRestrictPower)
+ mCurForegroundState = (!mRestrictBackground && (mRestrictPower || mDeviceIdleMode))
? ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
: ActivityManager.PROCESS_STATE_TOP;
@@ -2015,7 +2034,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// uid in background, and global background disabled
uidRules = RULE_REJECT_METERED;
}
- } else if (mRestrictPower) {
+ } else if (mRestrictPower || mDeviceIdleMode) {
final boolean whitelisted = mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid));
if (!whitelisted && !uidForeground
&& (uidPolicy & POLICY_ALLOW_BACKGROUND_BATTERY_SAVE) == 0) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a0c7f86..ed55c56 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -960,6 +960,7 @@ public final class SystemServer {
if (!disableNonCoreServices) {
mSystemServiceManager.startService(MediaProjectionManagerService.class);
+ mSystemServiceManager.startService(DeviceIdleController.class);
}
// Before things start rolling, be sure we have decided whether