Fix issue #21814207 and issue #21814212 (alarm manager)
Issue #21814207: AlarmManager.setAndAllowWhileIdle should also allow wake locks.
Introduce a whole new infrastructure for providing options when
sending broadcasts, much like ActivityOptions. There is a single
option right now, asking the activity manager to apply a tempory
whitelist to each receiver of the broadcast.
Issue #21814212: Need to allow configuration of alarm manager parameters
The various alarm manager timing configurations are not modifiable
through settings, much like DeviceIdleController. Also did a few
tweaks in the existing DeviceIdleController impl.
Change-Id: Ifd01013185acc4de668617b1e46e78e30ebed041
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 26ece72..839b87a 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -20,13 +20,16 @@
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
+import android.app.BroadcastOptions;
import android.app.IAlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -43,6 +46,7 @@
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.ArrayMap;
+import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -75,22 +79,6 @@
import com.android.internal.util.LocalLog;
class AlarmManagerService extends SystemService {
- // The threshold for how long an alarm can be late before we print a
- // warning message. The time duration is in milliseconds.
- private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
-
- // Minimum futurity of a new alarm
- private static final long MIN_FUTURITY = 5 * 1000; // 5 seconds, in millis
-
- // Minimum alarm recurrence interval
- private static final long MIN_INTERVAL = 60 * 1000; // one minute, in millis
-
- // Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle.
- private static final long ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000;
-
- // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling.
- private static final long ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
-
private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
private static final int RTC_MASK = 1 << RTC;
private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
@@ -102,7 +90,6 @@
static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
static final String TAG = "AlarmManager";
- static final String ClockReceiver_TAG = "ClockReceiver";
static final boolean localLOGV = false;
static final boolean DEBUG_BATCH = localLOGV || false;
static final boolean DEBUG_VALIDATE = localLOGV || false;
@@ -148,7 +135,7 @@
long mNextNonWakeupDeliveryTime;
long mLastTimeChangeClockTime;
long mLastTimeChangeRealtime;
- long mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_SHORT_TIME;
+ long mAllowWhileIdleMinTime;
int mNumTimeChanged;
/**
@@ -157,6 +144,11 @@
*/
final SparseLongArray mLastAllowWhileIdleDispatch = new SparseLongArray();
+ /**
+ * Broadcast options to use for FLAG_ALLOW_WHILE_IDLE.
+ */
+ Bundle mIdleOptions;
+
private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
new SparseArray<>();
private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray =
@@ -169,12 +161,137 @@
private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
new SparseArray<>();
+ /**
+ * All times are in milliseconds. These constants are kept synchronized with the system
+ * global Settings. Any access to this class or its fields should be done while
+ * holding the AlarmManagerService.mLock lock.
+ */
+ private final class Constants extends ContentObserver {
+ // Key names stored in the settings value.
+ private static final String KEY_MIN_FUTURITY = "min_futurity";
+ private static final String KEY_MIN_INTERVAL = "min_interval";
+ private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time";
+ private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time";
+ private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION
+ = "allow_while_idle_whitelist_duration";
+
+ private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
+ private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000;
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
+ private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
+
+ // Minimum futurity of a new alarm
+ public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
+
+ // Minimum alarm recurrence interval
+ public long MIN_INTERVAL = DEFAULT_MIN_INTERVAL;
+
+ // Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle.
+ public long ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME;
+
+ // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling.
+ public long ALLOW_WHILE_IDLE_LONG_TIME = DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME;
+
+ // BroadcastOptions.setTemporaryAppWhitelistDuration() to use for FLAG_ALLOW_WHILE_IDLE.
+ public long ALLOW_WHILE_IDLE_WHITELIST_DURATION
+ = DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
+
+ private ContentResolver mResolver;
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+ private long mLastAllowWhileIdleWhitelistDuration = -1;
+
+ public Constants(Handler handler) {
+ super(handler);
+ updateAllowWhileIdleMinTimeLocked();
+ updateAllowWhileIdleWhitelistDurationLocked();
+ }
+
+ public void start(ContentResolver resolver) {
+ mResolver = resolver;
+ mResolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.ALARM_MANAGER_CONSTANTS), false, this);
+ updateConstants();
+ }
+
+ public void updateAllowWhileIdleMinTimeLocked() {
+ mAllowWhileIdleMinTime = mPendingIdleUntil != null
+ ? ALLOW_WHILE_IDLE_LONG_TIME : ALLOW_WHILE_IDLE_SHORT_TIME;
+ }
+
+ public void updateAllowWhileIdleWhitelistDurationLocked() {
+ if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) {
+ mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION;
+ BroadcastOptions opts = BroadcastOptions.makeBasic();
+ opts.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+ mIdleOptions = opts.toBundle();
+ }
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateConstants();
+ }
+
+ private void updateConstants() {
+ synchronized (mLock) {
+ try {
+ mParser.setString(Settings.Global.getString(mResolver,
+ Settings.Global.ALARM_MANAGER_CONSTANTS));
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad device idle settings", e);
+ }
+
+ MIN_FUTURITY = mParser.getLong(KEY_MIN_FUTURITY, DEFAULT_MIN_FUTURITY);
+ MIN_INTERVAL = mParser.getLong(KEY_MIN_INTERVAL, DEFAULT_MIN_INTERVAL);
+ ALLOW_WHILE_IDLE_SHORT_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME,
+ DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME);
+ ALLOW_WHILE_IDLE_LONG_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME,
+ DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME);
+ ALLOW_WHILE_IDLE_WHITELIST_DURATION = mParser.getLong(
+ KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION,
+ DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+
+ updateAllowWhileIdleMinTimeLocked();
+ updateAllowWhileIdleWhitelistDurationLocked();
+ }
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(" Settings:");
+
+ pw.print(" "); pw.print(KEY_MIN_FUTURITY); pw.print("=");
+ TimeUtils.formatDuration(MIN_FUTURITY, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_MIN_INTERVAL); pw.print("=");
+ TimeUtils.formatDuration(MIN_INTERVAL, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_ALLOW_WHILE_IDLE_SHORT_TIME); pw.print("=");
+ TimeUtils.formatDuration(ALLOW_WHILE_IDLE_SHORT_TIME, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_ALLOW_WHILE_IDLE_LONG_TIME); pw.print("=");
+ TimeUtils.formatDuration(ALLOW_WHILE_IDLE_LONG_TIME, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION); pw.print("=");
+ TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
+ pw.println();
+ }
+ }
+
+ final Constants mConstants;
+
// Alarm delivery ordering bookkeeping
static final int PRIO_TICK = 0;
static final int PRIO_WAKEUP = 1;
static final int PRIO_NORMAL = 2;
- class PriorityClass {
+ final class PriorityClass {
int seq;
int priority;
@@ -184,11 +301,10 @@
}
}
- final HashMap<String, PriorityClass> mPriorities =
- new HashMap<String, PriorityClass>();
+ final HashMap<String, PriorityClass> mPriorities = new HashMap<>();
int mCurrentSeq = 0;
- class WakeupEvent {
+ static final class WakeupEvent {
public long when;
public int uid;
public String action;
@@ -482,6 +598,7 @@
public AlarmManagerService(Context context) {
super(context);
+ mConstants = new Constants(mHandler);
}
static long convertToElapsed(long when, int type) {
@@ -595,7 +712,7 @@
}
// Make sure we are using the correct ALLOW_WHILE_IDLE min time.
- mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_SHORT_TIME;
+ mConstants.updateAllowWhileIdleMinTimeLocked();
// Reschedule everything.
rescheduleKernelAlarmsLocked();
@@ -714,6 +831,13 @@
}
@Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ mConstants.start(getContext().getContentResolver());
+ }
+ }
+
+ @Override
protected void finalize() throws Throwable {
try {
close(mNativeData);
@@ -784,11 +908,12 @@
// Sanity check the recurrence interval. This will catch people who supply
// seconds when the API expects milliseconds.
- if (interval > 0 && interval < MIN_INTERVAL) {
+ final long minInterval = mConstants.MIN_INTERVAL;
+ if (interval > 0 && interval < minInterval) {
Slog.w(TAG, "Suspiciously short interval " + interval
- + " millis; expanding to " + (int)(MIN_INTERVAL/1000)
+ + " millis; expanding to " + (minInterval/1000)
+ " seconds");
- interval = MIN_INTERVAL;
+ interval = minInterval;
}
if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
@@ -805,7 +930,7 @@
final long nowElapsed = SystemClock.elapsedRealtime();
final long nominalTrigger = convertToElapsed(triggerAtTime, type);
// Try to prevent spamming by making sure we aren't firing alarms in the immediate future
- final long minTrigger = nowElapsed + MIN_FUTURITY;
+ final long minTrigger = nowElapsed + mConstants.MIN_FUTURITY;
final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger;
final long maxElapsed;
@@ -904,7 +1029,7 @@
if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
mPendingIdleUntil = a;
- mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_LONG_TIME;
+ mConstants.updateAllowWhileIdleMinTimeLocked();
needRebatch = true;
} else if ((a.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
if (mNextWakeFromIdle == null || mNextWakeFromIdle.whenElapsed > a.whenElapsed) {
@@ -1054,45 +1179,48 @@
void dumpImpl(PrintWriter pw) {
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
+ mConstants.dump(pw);
+ pw.println();
+
final long nowRTC = System.currentTimeMillis();
final long nowELAPSED = SystemClock.elapsedRealtime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- pw.print("nowRTC="); pw.print(nowRTC);
+ pw.print(" nowRTC="); pw.print(nowRTC);
pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw);
pw.println();
- pw.print("mLastTimeChangeClockTime="); pw.print(mLastTimeChangeClockTime);
+ pw.print(" mLastTimeChangeClockTime="); pw.print(mLastTimeChangeClockTime);
pw.print("="); pw.println(sdf.format(new Date(mLastTimeChangeClockTime)));
- pw.print("mLastTimeChangeRealtime=");
+ pw.print(" mLastTimeChangeRealtime=");
TimeUtils.formatDuration(mLastTimeChangeRealtime, pw);
pw.println();
if (!mInteractive) {
- pw.print("Time since non-interactive: ");
+ pw.print(" Time since non-interactive: ");
TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw);
pw.println();
- pw.print("Max wakeup delay: ");
+ pw.print(" Max wakeup delay: ");
TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
pw.println();
- pw.print("Time since last dispatch: ");
+ pw.print(" Time since last dispatch: ");
TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
pw.println();
- pw.print("Next non-wakeup delivery time: ");
+ pw.print(" Next non-wakeup delivery time: ");
TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
pw.println();
}
long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
- pw.print("Next non-wakeup alarm: ");
+ pw.print(" Next non-wakeup alarm: ");
TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
- pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
+ pw.print(" Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
- pw.print("Num time change events: "); pw.println(mNumTimeChanged);
+ pw.print(" Num time change events: "); pw.println(mNumTimeChanged);
pw.println();
- pw.println("Next alarm clock information: ");
+ pw.println(" Next alarm clock information: ");
final TreeSet<Integer> users = new TreeSet<>();
for (int i = 0; i < mNextAlarmClockForUser.size(); i++) {
users.add(mNextAlarmClockForUser.keyAt(i));
@@ -1104,7 +1232,7 @@
final AlarmManager.AlarmClockInfo next = mNextAlarmClockForUser.get(user);
final long time = next != null ? next.getTriggerTime() : 0;
final boolean pendingSend = mPendingSendNextAlarmClockChangedForUser.get(user);
- pw.print(" user:"); pw.print(user);
+ pw.print(" user:"); pw.print(user);
pw.print(" pendingSend:"); pw.print(pendingSend);
pw.print(" time:"); pw.print(time);
if (time > 0) {
@@ -1115,25 +1243,25 @@
}
if (mAlarmBatches.size() > 0) {
pw.println();
- pw.print("Pending alarm batches: ");
+ pw.print(" Pending alarm batches: ");
pw.println(mAlarmBatches.size());
for (Batch b : mAlarmBatches) {
pw.print(b); pw.println(':');
- dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf);
+ dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf);
}
}
if (mPendingIdleUntil != null || mPendingWhileIdleAlarms.size() > 0) {
pw.println();
- pw.println("Idle mode state:");
- pw.print(" Idling until: ");
+ pw.println(" Idle mode state:");
+ pw.print(" Idling until: ");
if (mPendingIdleUntil != null) {
pw.println(mPendingIdleUntil);
mPendingIdleUntil.dump(pw, " ", nowRTC, nowELAPSED, sdf);
} else {
pw.println("null");
}
- pw.println(" Pending alarms:");
- dumpAlarmList(pw, mPendingWhileIdleAlarms, " ", nowELAPSED, nowRTC, sdf);
+ pw.println(" Pending alarms:");
+ dumpAlarmList(pw, mPendingWhileIdleAlarms, " ", nowELAPSED, nowRTC, sdf);
}
if (mNextWakeFromIdle != null) {
pw.println();
@@ -1142,17 +1270,17 @@
}
pw.println();
- pw.print("Past-due non-wakeup alarms: ");
+ pw.print(" Past-due non-wakeup alarms: ");
if (mPendingNonWakeupAlarms.size() > 0) {
pw.println(mPendingNonWakeupAlarms.size());
- dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf);
+ dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf);
} else {
pw.println("(none)");
}
- pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms);
+ pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms);
pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw);
pw.println();
- pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw);
+ pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw);
pw.print(", max non-interactive time: ");
TimeUtils.formatDuration(mNonInteractiveTime, pw);
pw.println();
@@ -1161,11 +1289,11 @@
pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
pw.println();
- pw.print("mAllowWhileIdleMinTime=");
+ pw.print(" mAllowWhileIdleMinTime=");
TimeUtils.formatDuration(mAllowWhileIdleMinTime, pw);
pw.println();
if (mLastAllowWhileIdleDispatch.size() > 0) {
- pw.println("Last allow while idle dispatch times:");
+ pw.println(" Last allow while idle dispatch times:");
for (int i=0; i<mLastAllowWhileIdleDispatch.size(); i++) {
pw.print(" UID ");
UserHandle.formatUid(pw, mLastAllowWhileIdleDispatch.keyAt(i));
@@ -1969,6 +2097,7 @@
mLastAlarmDeliveryTime = nowELAPSED;
for (int i=0; i<triggerList.size(); i++) {
Alarm alarm = triggerList.get(i);
+ final boolean allowWhileIdle = (alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0;
try {
if (localLOGV) {
Slog.v(TAG, "sending alarm " + alarm);
@@ -1987,7 +2116,7 @@
alarm.operation.send(getContext(), 0,
mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT, alarm.count),
- mResultReceiver, mHandler);
+ mResultReceiver, mHandler, null, allowWhileIdle ? mIdleOptions : null);
// we have an active broadcast so stay awake.
if (mBroadcastRefCount == 0) {
@@ -2000,7 +2129,7 @@
mInFlight.add(inflight);
mBroadcastRefCount++;
- if ((alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
+ if (allowWhileIdle) {
// Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
mLastAllowWhileIdleDispatch.put(alarm.uid, nowELAPSED);
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 6eba3f6..8dd087a 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -19,7 +19,6 @@
import android.Manifest;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
-import android.app.AppGlobals;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -27,7 +26,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
@@ -101,10 +99,6 @@
private static final String ACTION_ENTER_INACTIVE_STATE =
"com.android.server.device_idle.ENTER_INACTIVE_STATE";
- // TODO: These need to be moved to system settings.
-
-
-
private AlarmManager mAlarmManager;
private IBatteryStats mBatteryStats;
private PowerManagerInternal mLocalPowerManager;
@@ -180,7 +174,7 @@
* List of end times for UIDs that are temporarily marked as being allowed to access
* the network and acquire wakelocks. Times are in milliseconds.
*/
- private SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray();
+ private final SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray();
/**
* Current app IDs of temporarily whitelist apps for high-priority messages.
@@ -234,7 +228,7 @@
* global Settings. Any access to this class or its fields should be done while
* holding the DeviceIdleController lock.
*/
- private class Constants extends ContentObserver {
+ private final class Constants extends ContentObserver {
// Key names stored in the settings value.
private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
private static final String KEY_SENSING_TIMEOUT = "sensing_to";
@@ -403,49 +397,49 @@
void dump(PrintWriter pw) {
pw.println(" Settings:");
- pw.print(" DOZE_INACTIVE_TIMEOUT=");
+ pw.print(" "); pw.print(KEY_INACTIVE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(INACTIVE_TIMEOUT, pw);
pw.println();
- pw.print(" DOZE_SENSING_TIMEOUT=");
+ pw.print(" "); pw.print(KEY_SENSING_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(SENSING_TIMEOUT, pw);
pw.println();
- pw.print(" DOZE_MOTION_INACTIVE_TIMEOUT=");
+ pw.print(" "); pw.print(KEY_MOTION_INACTIVE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw);
pw.println();
- pw.print(" DOZE_IDLE_AFTER_INACTIVE_TIMEOUT=");
+ pw.print(" "); pw.print(KEY_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw);
pw.println();
- pw.print(" DOZE_IDLE_PENDING_TIMEOUT=");
+ pw.print(" "); pw.print(KEY_IDLE_PENDING_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(IDLE_PENDING_TIMEOUT, pw);
pw.println();
- pw.print(" DOZE_MAX_IDLE_PENDING_TIMEOUT=");
+ pw.print(" "); pw.print(KEY_MAX_IDLE_PENDING_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(MAX_IDLE_PENDING_TIMEOUT, pw);
pw.println();
- pw.print(" DOZE_IDLE_PENDING_FACTOR=");
+ pw.print(" "); pw.print(KEY_IDLE_PENDING_FACTOR); pw.print("=");
pw.println(IDLE_PENDING_FACTOR);
- pw.print(" DOZE_IDLE_TIMEOUT=");
+ pw.print(" "); pw.print(KEY_IDLE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(IDLE_TIMEOUT, pw);
pw.println();
- pw.print(" DOZE_MAX_IDLE_TIMEOUT=");
+ pw.print(" "); pw.print(KEY_MAX_IDLE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(MAX_IDLE_TIMEOUT, pw);
pw.println();
- pw.print(" DOZE_IDLE_FACTOR=");
+ pw.print(" "); pw.print(KEY_IDLE_FACTOR); pw.print("=");
pw.println(IDLE_FACTOR);
- pw.print(" DOZE_MIN_TIME_TO_ALARM=");
+ pw.print(" "); pw.print(KEY_MIN_TIME_TO_ALARM); pw.print("=");
TimeUtils.formatDuration(MIN_TIME_TO_ALARM, pw);
pw.println();
- pw.print(" DOZE_MAX_TEMP_APP_WHITELIST_DURATION=");
+ pw.print(" "); pw.print(KEY_MAX_TEMP_APP_WHITELIST_DURATION); pw.print("=");
TimeUtils.formatDuration(MAX_TEMP_APP_WHITELIST_DURATION, pw);
pw.println();
}
@@ -465,6 +459,7 @@
} else if (result == AnyMotionDetector.RESULT_MOVED) {
if (DEBUG) Slog.d(TAG, "RESULT_MOVED received.");
synchronized (this) {
+ EventLogTags.writeDeviceIdle(mState, "sense_moved");
enterInactiveStateLocked();
}
}
@@ -573,15 +568,11 @@
userId,
/*allowAll=*/ false,
/*requireFull=*/ false,
- "addAppBrieflyToWhitelist", null);
+ "addPowerSaveTempWhitelistApp", null);
final long token = Binder.clearCallingIdentity();
try {
- PackageInfo pi = AppGlobals.getPackageManager()
- .getPackageInfo(packageName, 0, userId);
- if (pi == null) return;
DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(packageName,
duration, userId);
- } catch (RemoteException re) {
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -592,6 +583,12 @@
}
}
+ public final class LocalService {
+ public void addPowerSaveTempWhitelistAppDirect(int appId, long duration) {
+ DeviceIdleController.this.addPowerSaveTempWhitelistAppDirectInternal(appId, duration);
+ }
+ }
+
public DeviceIdleController(Context context) {
super(context);
mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
@@ -635,6 +632,7 @@
}
publishBinderService(Context.DEVICE_IDLE_CONTROLLER, new BinderService());
+ publishLocalService(LocalService.class, new LocalService());
}
@Override
@@ -765,33 +763,41 @@
try {
int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
int appId = UserHandle.getAppId(uid);
- final long timeNow = System.currentTimeMillis();
- synchronized (this) {
- duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION);
- long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
- // Set the new end time
- mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration);
- if (DEBUG) {
- Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist");
- }
- if (currentEndTime == 0) {
- // No pending timeout for the app id, post a delayed message
- postTempActiveTimeoutMessage(appId, duration);
- updateTempWhitelistAppIdsLocked();
- reportTempWhitelistChangedLocked();
- }
- }
+ addPowerSaveTempWhitelistAppDirectInternal(appId, duration);
} catch (NameNotFoundException e) {
}
}
+ /**
+ * Adds an app to the temporary whitelist and resets the endTime for granting the
+ * app an exemption to access network and acquire wakelocks.
+ */
+ public void addPowerSaveTempWhitelistAppDirectInternal(int appId, long duration) {
+ final long timeNow = SystemClock.elapsedRealtime();
+ synchronized (this) {
+ duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION);
+ long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
+ // Set the new end time
+ mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration);
+ if (DEBUG) {
+ Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist");
+ }
+ if (currentEndTime == 0) {
+ // No pending timeout for the app id, post a delayed message
+ postTempActiveTimeoutMessage(appId, duration);
+ updateTempWhitelistAppIdsLocked();
+ reportTempWhitelistChangedLocked();
+ }
+ }
+ }
+
private void postTempActiveTimeoutMessage(int uid, long delay) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0),
delay);
}
void checkTempAppWhitelistTimeout(int uid) {
- final long timeNow = System.currentTimeMillis();
+ final long timeNow = SystemClock.elapsedRealtime();
synchronized (this) {
long endTime = mTempWhitelistAppIdEndTimes.get(uid);
if (endTime == 0) {
@@ -1295,6 +1301,8 @@
}
synchronized (this) {
+ mConstants.dump(pw);
+
int size = mPowerSaveWhitelistApps.size();
if (size > 0) {
pw.println(" Whitelist system apps:");
@@ -1313,17 +1321,34 @@
}
size = mPowerSaveWhitelistAppIds.size();
if (size > 0) {
- pw.println(" Whitelist app uids:");
+ pw.println(" Whitelist app ids:");
for (int i = 0; i < size; i++) {
- pw.print(" UID=");
+ pw.print(" ");
pw.print(mPowerSaveWhitelistAppIds.keyAt(i));
- pw.print(": ");
- pw.print(mPowerSaveWhitelistAppIds.valueAt(i));
pw.println();
}
}
-
- mConstants.dump(pw);
+ size = mTempWhitelistAppIdEndTimes.size();
+ if (size > 0) {
+ pw.println(" Temp whitelist schedule:");
+ final long timeNow = SystemClock.elapsedRealtime();
+ for (int i = 0; i < size; i++) {
+ pw.print(" UID=");
+ pw.print(mTempWhitelistAppIdEndTimes.keyAt(i));
+ pw.print(": ");
+ TimeUtils.formatDuration(mTempWhitelistAppIdEndTimes.valueAt(i), timeNow, pw);
+ pw.println();
+ }
+ }
+ size = mTempWhitelistAppIdArray != null ? mTempWhitelistAppIdArray.length : 0;
+ if (size > 0) {
+ pw.println(" Temp whitelist app ids:");
+ for (int i = 0; i < size; i++) {
+ pw.print(" ");
+ pw.print(mTempWhitelistAppIdArray[i]);
+ pw.println();
+ }
+ }
pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
pw.print(" mCurDisplay="); pw.println(mCurDisplay);
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 6e67970..e0a9ab4 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -34,7 +34,7 @@
* local interfaces that other services within the system server may use to access
* privileged internal functions.
* <li>Then {@link #onBootPhase(int)} is called as many times as there are boot phases
- * until {@link #PHASE_BOOT_COMPLETE} is sent, which is the last boot phase. Each phase
+ * until {@link #PHASE_BOOT_COMPLETED} is sent, which is the last boot phase. Each phase
* is an opportunity to do special work, like acquiring optional service dependencies,
* waiting to see if SafeMode is enabled, or registering with a service that gets
* started after this one.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 667abb6..c4f460e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -39,6 +39,7 @@
import android.Manifest;
import android.app.AppOpsManager;
import android.app.ApplicationThreadNative;
+import android.app.BroadcastOptions;
import android.app.IActivityContainer;
import android.app.IActivityContainerCallback;
import android.app.IAppTask;
@@ -89,6 +90,7 @@
import com.android.internal.util.Preconditions;
import com.android.server.AppOpsService;
import com.android.server.AttributeCache;
+import com.android.server.DeviceIdleController;
import com.android.server.IntentResolver;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
@@ -941,6 +943,11 @@
UsageStatsManagerInternal mUsageStatsService;
/**
+ * Access to DeviceIdleController service.
+ */
+ DeviceIdleController.LocalService mLocalDeviceIdleController;
+
+ /**
* Information about and control over application operations
*/
final AppOpsService mAppOpsService;
@@ -1438,7 +1445,7 @@
}
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
+ null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
if (mShowDialogs) {
Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
@@ -2559,9 +2566,9 @@
@Override
public void batterySendBroadcast(Intent intent) {
- broadcastIntentLocked(null, null, intent, null,
- null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1,
- Process.SYSTEM_UID, UserHandle.USER_ALL);
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ AppOpsManager.OP_NONE, null, false, false,
+ -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
/**
@@ -5089,7 +5096,7 @@
Uri.fromParts("package", packageName, null));
intent.putExtra(Intent.EXTRA_UID, pkgUid);
broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
- null, null, 0, null, null, null, false, false, userId);
+ null, null, 0, null, null, null, null, false, false, userId);
} catch (RemoteException e) {
}
} finally {
@@ -5322,9 +5329,9 @@
mStackSupervisor.closeSystemDialogsLocked();
- broadcastIntentLocked(null, null, intent, null,
- null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1,
- Process.SYSTEM_UID, UserHandle.USER_ALL);
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ AppOpsManager.OP_NONE, null, false, false,
+ -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
@Override
@@ -5423,8 +5430,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- false, false,
- MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
+ null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
}
private void forceStopUserLocked(int userId, String reason) {
@@ -5435,8 +5441,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- false, false,
- MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
private final boolean killPackageProcessesLocked(String packageName, int appId,
@@ -6329,8 +6334,8 @@
},
0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
- AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID,
- userId);
+ AppOpsManager.OP_NONE, null, true, false,
+ MY_PID, Process.SYSTEM_UID, userId);
}
}
scheduleStartProfilesLocked();
@@ -11442,8 +11447,7 @@
EventLogTags.writeAmPreBoot(users[curUser], intent.getComponent().getPackageName());
broadcastIntentLocked(null, null, intent, null, this,
0, null, null, null, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID,
- users[curUser]);
+ null, true, false, MY_PID, Process.SYSTEM_UID, users[curUser]);
}
public void performReceive(Intent intent, int resultCode,
@@ -11535,6 +11539,9 @@
return;
}
+ mLocalDeviceIdleController
+ = LocalServices.getService(DeviceIdleController.LocalService.class);
+
// Make sure we have the current profile info, since it is needed for
// security checks.
updateCurrentProfileIdsLocked();
@@ -11704,7 +11711,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
+ null, false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
@@ -11717,7 +11724,7 @@
}
}, 0, null, null,
INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} catch (Throwable t) {
Slog.wtf(TAG, "Failed sending first user broadcasts", t);
} finally {
@@ -16101,8 +16108,8 @@
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
- null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
- null, null, false, true, true, -1);
+ null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
+ null, 0, null, null, false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
@@ -16255,9 +16262,8 @@
private final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
- Bundle map, String requiredPermission, int appOp,
- boolean ordered, boolean sticky, int callingPid, int callingUid,
- int userId) {
+ Bundle resultExtras, String requiredPermission, int appOp, Bundle options,
+ boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
intent = new Intent(intent);
// By default broadcasts do not go to stopped apps.
@@ -16292,6 +16298,28 @@
}
}
+ BroadcastOptions brOptions = null;
+ if (options != null) {
+ brOptions = new BroadcastOptions(options);
+ if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
+ // See if the caller is allowed to do this. Note we are checking against
+ // the actual real caller (not whoever provided the operation as say a
+ // PendingIntent), because that who is actually supplied the arguments.
+ if (checkComponentPermission(
+ android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
+ Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: " + intent.getAction()
+ + " broadcast from " + callerPackage + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")"
+ + " requires "
+ + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ }
+ }
+
/*
* Prevent non-system code (defined here to be non-persistent
* processes) from sending protected broadcasts.
@@ -16598,8 +16626,8 @@
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
- appOp, registeredReceivers, resultTo, resultCode, resultData, map,
- ordered, sticky, false, userId);
+ appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
+ resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced) {
@@ -16687,8 +16715,8 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
- requiredPermission, appOp, receivers, resultTo, resultCode,
- resultData, map, ordered, sticky, false, userId);
+ requiredPermission, appOp, brOptions, receivers, resultTo, resultCode,
+ resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
@@ -16735,8 +16763,9 @@
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
- int resultCode, String resultData, Bundle map,
- String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
+ int resultCode, String resultData, Bundle resultExtras,
+ String requiredPermission, int appOp, Bundle options,
+ boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -16747,8 +16776,8 @@
final long origId = Binder.clearCallingIdentity();
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
- intent, resolvedType, resultTo,
- resultCode, resultData, map, requiredPermission, appOp, serialized, sticky,
+ intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
+ requiredPermission, appOp, null, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
@@ -16757,15 +16786,16 @@
int broadcastIntentInPackage(String packageName, int uid,
Intent intent, String resolvedType, IIntentReceiver resultTo,
- int resultCode, String resultData, Bundle map,
- String requiredPermission, boolean serialized, boolean sticky, int userId) {
+ int resultCode, String resultData, Bundle resultExtras,
+ String requiredPermission, Bundle options, boolean serialized, boolean sticky,
+ int userId) {
synchronized(this) {
intent = verifyBroadcastLocked(intent);
final long origId = Binder.clearCallingIdentity();
int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
- resultTo, resultCode, resultData, map, requiredPermission,
- AppOpsManager.OP_NONE, serialized, sticky, -1, uid, userId);
+ resultTo, resultCode, resultData, resultExtras, requiredPermission,
+ AppOpsManager.OP_NONE, options, serialized, sticky, -1, uid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
@@ -17162,8 +17192,8 @@
| Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
- null, AppOpsManager.OP_NONE, false, false, MY_PID,
- Process.SYSTEM_UID, UserHandle.USER_ALL);
+ null, AppOpsManager.OP_NONE, null, false, false,
+ MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -17172,7 +17202,7 @@
}
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
}
}
@@ -19642,7 +19672,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, userId);
+ null, false, false, MY_PID, Process.SYSTEM_UID, userId);
}
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
@@ -19657,8 +19687,7 @@
onUserInitialized(uss, foreground, oldUserId, userId);
}
}, 0, null, null, null, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID,
- userId);
+ null, true, false, MY_PID, Process.SYSTEM_UID, userId);
uss.initializing = true;
} else {
getUserManagerLocked().makeInitialized(userInfo.id);
@@ -19680,13 +19709,13 @@
broadcastIntentLocked(null, null, intent,
null, new IIntentReceiver.Stub() {
@Override
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky, int sendingUser)
- throws RemoteException {
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered, boolean sticky,
+ int sendingUser) throws RemoteException {
}
}, 0, null, null,
INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
}
} finally {
@@ -19724,7 +19753,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
+ null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
}
}
if (newUserId >= 0) {
@@ -19739,7 +19768,7 @@
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
+ null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
}
intent = new Intent(Intent.ACTION_USER_SWITCHED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -19748,7 +19777,7 @@
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null,
android.Manifest.permission.MANAGE_USERS, AppOpsManager.OP_NONE,
- false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -19925,7 +19954,7 @@
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID, userId);
+ null, true, false, MY_PID, Process.SYSTEM_UID, userId);
}
}
}
@@ -20057,14 +20086,14 @@
mSystemServiceManager.stopUser(userId);
broadcastIntentLocked(null, null, shutdownIntent,
null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID, userId);
+ null, true, false, MY_PID, Process.SYSTEM_UID, userId);
}
};
// Kick things off.
broadcastIntentLocked(null, null, stoppingIntent,
null, stoppingReceiver, 0, null, null,
INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 80b8a93..2335071 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -26,6 +26,7 @@
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -43,6 +44,7 @@
import android.os.UserHandle;
import android.util.EventLog;
import android.util.Slog;
+import com.android.server.DeviceIdleController;
import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -146,6 +148,8 @@
static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG;
static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
+ static final int SCHEDULE_TEMP_WHITELIST_MSG
+ = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 2;
final BroadcastHandler mHandler;
@@ -167,6 +171,13 @@
broadcastTimeoutLocked(true);
}
} break;
+ case SCHEDULE_TEMP_WHITELIST_MSG: {
+ DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;
+ if (dic != null) {
+ dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),
+ msg.arg2);
+ }
+ } break;
}
}
};
@@ -547,6 +558,19 @@
}
}
+ final void scheduleTempWhitelistLocked(int uid, long duration) {
+ if (duration > Integer.MAX_VALUE) {
+ duration = Integer.MAX_VALUE;
+ }
+ // XXX ideally we should pause the broadcast until everything behind this is done,
+ // or else we will likely start dispatching the broadcast before we have opened
+ // access to the app (there is a lot of asynchronicity behind this). It is probably
+ // not that big a deal, however, because the main purpose here is to allow apps
+ // to hold wake locks, and they will be able to acquire their wake lock immediately
+ // it just won't be enabled until we get through this work.
+ mHandler.obtainMessage(SCHEDULE_TEMP_WHITELIST_MSG, uid, (int)duration).sendToTarget();
+ }
+
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
BroadcastRecord r;
@@ -721,7 +745,9 @@
setBroadcastTimeoutLocked(timeoutTime);
}
- Object nextReceiver = r.receivers.get(recIdx);
+ final BroadcastOptions brOptions = r.options;
+ final Object nextReceiver = r.receivers.get(recIdx);
+
if (nextReceiver instanceof BroadcastFilter) {
// Simple case: this is a registered receiver who gets
// a direct call.
@@ -739,6 +765,11 @@
+ r.ordered + " receiver=" + r.receiver);
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
+ } else {
+ if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
+ scheduleTempWhitelistLocked(filter.owningUid,
+ brOptions.getTemporaryAppWhitelistDuration());
+ }
}
return;
}
@@ -882,6 +913,11 @@
+ info.activityInfo.applicationInfo.uid);
}
+ if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
+ scheduleTempWhitelistLocked(receiverUid,
+ brOptions.getTemporaryAppWhitelistDuration());
+ }
+
// Broadcast is being executed, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index c050d03f..b943222 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
import android.content.IIntentReceiver;
import android.content.ComponentName;
import android.content.Intent;
@@ -52,6 +53,7 @@
final String resolvedType; // the resolved data type
final String requiredPermission; // a permission the caller has required
final int appOp; // an app op that is associated with this broadcast
+ final BroadcastOptions options; // BroadcastOptions supplied by caller
final List receivers; // contains BroadcastFilter and ResolveInfo
IIntentReceiver resultTo; // who receives final result if non-null
long enqueueClockTime; // the clock time the broadcast was enqueued
@@ -105,6 +107,9 @@
pw.print(prefix); pw.print("requiredPermission="); pw.print(requiredPermission);
pw.print(" appOp="); pw.println(appOp);
}
+ if (options != null) {
+ pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
+ }
pw.print(prefix); pw.print("enqueueClockTime=");
pw.print(new Date(enqueueClockTime));
pw.print(" dispatchClockTime=");
@@ -180,8 +185,8 @@
BroadcastRecord(BroadcastQueue _queue,
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
int _callingPid, int _callingUid, String _resolvedType, String _requiredPermission,
- int _appOp, List _receivers, IIntentReceiver _resultTo, int _resultCode,
- String _resultData, Bundle _resultExtras, boolean _serialized,
+ int _appOp, BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo,
+ int _resultCode, String _resultData, Bundle _resultExtras, boolean _serialized,
boolean _sticky, boolean _initialSticky,
int _userId) {
queue = _queue;
@@ -194,6 +199,7 @@
resolvedType = _resolvedType;
requiredPermission = _requiredPermission;
appOp = _appOp;
+ options = _options;
receivers = _receivers;
resultTo = _resultTo;
resultCode = _resultCode;
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 531de46..ece3ffb 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -199,9 +199,9 @@
}
public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
- String requiredPermission) throws TransactionTooLargeException {
+ String requiredPermission, Bundle options) throws TransactionTooLargeException {
return sendInner(code, intent, resolvedType, finishedReceiver,
- requiredPermission, null, null, 0, 0, 0, null, null);
+ requiredPermission, null, null, 0, 0, 0, options, null);
}
int sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver,
@@ -293,9 +293,9 @@
// If a completion callback has been requested, require
// that the broadcast be delivered synchronously
int sent = owner.broadcastIntentInPackage(key.packageName, uid,
- finalIntent, resolvedType,
- finishedReceiver, code, null, null,
- requiredPermission, (finishedReceiver != null), false, userId);
+ finalIntent, resolvedType, finishedReceiver, code, null, null,
+ requiredPermission, options, (finishedReceiver != null),
+ false, userId);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5b7dd70..06e27fc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8808,7 +8808,7 @@
}
am.broadcastIntent(null, intent, null, finishedReceiver,
0, null, null, null, android.app.AppOpsManager.OP_NONE,
- finishedReceiver != null, false, id);
+ null, finishedReceiver != null, false, id);
}
} catch (RemoteException ex) {
}
@@ -8982,7 +8982,7 @@
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
.setPackage(packageName);
am.broadcastIntent(null, bcIntent, null, null, 0, null, null, null,
- android.app.AppOpsManager.OP_NONE, false, false, userId);
+ android.app.AppOpsManager.OP_NONE, null, false, false, userId);
}
} catch (RemoteException e) {
// shouldn't happen