diff options
Diffstat (limited to 'services/core/java')
21 files changed, 712 insertions, 291 deletions
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 168742f..4ab8a01 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -22,7 +22,6 @@ import android.app.AlarmManager; import android.app.IAlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -40,7 +39,6 @@ import android.os.UserHandle; import android.os.WorkSource; import android.text.TextUtils; import android.util.ArrayMap; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -104,13 +102,21 @@ class AlarmManagerService extends SystemService { int mBroadcastRefCount = 0; PowerManager.WakeLock mWakeLock; boolean mLastWakeLockUnimportantForLogging; + ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>(); ArrayList<InFlight> mInFlight = new ArrayList<InFlight>(); final AlarmHandler mHandler = new AlarmHandler(); ClockReceiver mClockReceiver; + InteractiveStateReceiver mInteractiveStateReceiver; private UninstallReceiver mUninstallReceiver; final ResultReceiver mResultReceiver = new ResultReceiver(); PendingIntent mTimeTickSender; PendingIntent mDateChangeSender; + boolean mInteractive = true; + long mNonInteractiveStartTime; + long mNonInteractiveTime; + long mLastAlarmDeliveryTime; + long mStartCurrentDelayTime; + long mNextNonWakeupDeliveryTime; class WakeupEvent { public long when; @@ -318,7 +324,11 @@ class AlarmManagerService extends SystemService { final Comparator<Alarm> mAlarmDispatchComparator = new Comparator<Alarm>() { @Override public int compare(Alarm lhs, Alarm rhs) { - if (lhs.wakeup != rhs.wakeup) { + if ((!lhs.operation.getCreatorPackage().equals(rhs.operation.getCreatorPackage())) + && lhs.wakeup != rhs.wakeup) { + // We want to put wakeup alarms before non-wakeup alarms, since they are + // the things that drive most activity in the alarm manager. However, + // alarms from the same package should always be ordered strictly by time. return lhs.wakeup ? -1 : 1; } if (lhs.whenElapsed < rhs.whenElapsed) { @@ -424,24 +434,21 @@ class AlarmManagerService extends SystemService { static final class InFlight extends Intent { final PendingIntent mPendingIntent; final WorkSource mWorkSource; - final Pair<String, ComponentName> mTarget; + final String mTag; final BroadcastStats mBroadcastStats; final FilterStats mFilterStats; final int mAlarmType; InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource, - int alarmType) { + int alarmType, String tag) { mPendingIntent = pendingIntent; mWorkSource = workSource; - Intent intent = pendingIntent.getIntent(); - mTarget = intent != null - ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent()) - : null; + mTag = tag; mBroadcastStats = service.getStatsLocked(pendingIntent); - FilterStats fs = mBroadcastStats.filterStats.get(mTarget); + FilterStats fs = mBroadcastStats.filterStats.get(mTag); if (fs == null) { - fs = new FilterStats(mBroadcastStats, mTarget); - mBroadcastStats.filterStats.put(mTarget, fs); + fs = new FilterStats(mBroadcastStats, mTag); + mBroadcastStats.filterStats.put(mTag, fs); } mFilterStats = fs; mAlarmType = alarmType; @@ -450,7 +457,7 @@ class AlarmManagerService extends SystemService { static final class FilterStats { final BroadcastStats mBroadcastStats; - final Pair<String, ComponentName> mTarget; + final String mTag; long aggregateTime; int count; @@ -458,9 +465,9 @@ class AlarmManagerService extends SystemService { long startTime; int nesting; - FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) { + FilterStats(BroadcastStats broadcastStats, String tag) { mBroadcastStats = broadcastStats; - mTarget = target; + mTag = tag; } } @@ -473,8 +480,7 @@ class AlarmManagerService extends SystemService { int numWakeup; long startTime; int nesting; - final ArrayMap<Pair<String, ComponentName>, FilterStats> filterStats - = new ArrayMap<Pair<String, ComponentName>, FilterStats>(); + final ArrayMap<String, FilterStats> filterStats = new ArrayMap<String, FilterStats>(); BroadcastStats(int uid, String packageName) { mUid = uid; @@ -484,7 +490,11 @@ class AlarmManagerService extends SystemService { final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats = new SparseArray<ArrayMap<String, BroadcastStats>>(); - + + int mNumDelayedAlarms = 0; + long mTotalDelayTime = 0; + long mMaxDelayTime = 0; + @Override public void onStart() { mNativeData = init(); @@ -511,6 +521,7 @@ class AlarmManagerService extends SystemService { mClockReceiver = new ClockReceiver(); mClockReceiver.scheduleTimeTickEvent(); mClockReceiver.scheduleDateChangedEvent(); + mInteractiveStateReceiver = new InteractiveStateReceiver(); mUninstallReceiver = new UninstallReceiver(); if (mNativeData != 0) { @@ -735,13 +746,29 @@ class AlarmManagerService extends SystemService { pw.print("nowRTC="); pw.print(nowRTC); pw.print("="); pw.print(sdf.format(new Date(nowRTC))); - pw.print(" nowELAPSED="); pw.println(nowELAPSED); + pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw); + pw.println(); + if (!mInteractive) { + pw.print("Time since non-interactive: "); + TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw); + pw.println(); + pw.print("Max wakeup delay: "); + TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw); + pw.println(); + pw.print("Time since last dispatch: "); + TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw); + pw.println(); + 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 alarm: "); pw.print(mNextNonWakeup); + pw.print("Next non-wakeup alarm: "); + TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw); pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC))); - pw.print("Next wakeup: "); pw.print(mNextWakeup); + pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw); pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC))); if (mAlarmBatches.size() > 0) { @@ -750,11 +777,27 @@ class AlarmManagerService extends SystemService { pw.println(mAlarmBatches.size()); for (Batch b : mAlarmBatches) { pw.print(b); pw.println(':'); - dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC); + dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf); } } pw.println(); + pw.print("Past-due non-wakeup alarms: "); + if (mPendingNonWakeupAlarms.size() > 0) { + pw.println(mPendingNonWakeupAlarms.size()); + dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf); + } else { + pw.println("(none)"); + } + 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 non-interactive time: "); + TimeUtils.formatDuration(mNonInteractiveTime, pw); + pw.println(); + + pw.println(); pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); pw.println(); @@ -811,13 +854,7 @@ class AlarmManagerService extends SystemService { pw.print(" alarms: "); UserHandle.formatUid(pw, fs.mBroadcastStats.mUid); pw.print(":"); pw.print(fs.mBroadcastStats.mPackageName); pw.println(); - pw.print(" "); - if (fs.mTarget.first != null) { - pw.print(" act="); pw.print(fs.mTarget.first); - } - if (fs.mTarget.second != null) { - pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString()); - } + pw.print(" "); pw.print(fs.mTag); pw.println(); } } @@ -849,13 +886,8 @@ class AlarmManagerService extends SystemService { TimeUtils.formatDuration(fs.aggregateTime, pw); pw.print(" "); pw.print(fs.numWakeup); pw.print(" wakes " ); pw.print(fs.count); - pw.print(" alarms:"); - if (fs.mTarget.first != null) { - pw.print(" act="); pw.print(fs.mTarget.first); - } - if (fs.mTarget.second != null) { - pw.print(" cmp="); pw.print(fs.mTarget.second.toShortString()); - } + pw.print(" alarms: "); + pw.print(fs.mTag); pw.println(); } } @@ -883,7 +915,7 @@ class AlarmManagerService extends SystemService { } } - private void logBatchesLocked() { + private void logBatchesLocked(SimpleDateFormat sdf) { ByteArrayOutputStream bs = new ByteArrayOutputStream(2048); PrintWriter pw = new PrintWriter(bs); final long nowRTC = System.currentTimeMillis(); @@ -892,7 +924,7 @@ class AlarmManagerService extends SystemService { for (int iz = 0; iz < NZ; iz++) { Batch bz = mAlarmBatches.get(iz); pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz); - dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC); + dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC, sdf); pw.flush(); Slog.v(TAG, bs.toString()); bs.reset(); @@ -910,7 +942,8 @@ class AlarmManagerService extends SystemService { lastTime = b.start; } else { Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order"); - logBatchesLocked(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + logBatchesLocked(sdf); return false; } } @@ -932,6 +965,7 @@ class AlarmManagerService extends SystemService { void rescheduleKernelAlarmsLocked() { // Schedule the next upcoming wakeup alarm. If there is a deliverable batch // prior to that which contains no wakeups, we schedule that as well. + long nextNonWakeup = 0; if (mAlarmBatches.size() > 0) { final Batch firstWakeup = findFirstWakeupBatchLocked(); final Batch firstBatch = mAlarmBatches.get(0); @@ -939,11 +973,19 @@ class AlarmManagerService extends SystemService { mNextWakeup = firstWakeup.start; setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start); } - if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) { - mNextNonWakeup = firstBatch.start; - setLocked(ELAPSED_REALTIME, firstBatch.start); + if (firstBatch != firstWakeup) { + nextNonWakeup = firstBatch.start; + } + } + if (mPendingNonWakeupAlarms.size() > 0) { + if (nextNonWakeup == 0 || mNextNonWakeupDeliveryTime < nextNonWakeup) { + nextNonWakeup = mNextNonWakeupDeliveryTime; } } + if (nextNonWakeup != 0 && mNextNonWakeup != nextNonWakeup) { + mNextNonWakeup = nextNonWakeup; + setLocked(ELAPSED_REALTIME, nextNonWakeup); + } } private void removeLocked(PendingIntent operation) { @@ -1003,6 +1045,32 @@ class AlarmManagerService extends SystemService { } } + void interactiveStateChangedLocked(boolean interactive) { + if (mInteractive != interactive) { + mInteractive = interactive; + final long nowELAPSED = SystemClock.elapsedRealtime(); + if (interactive) { + if (mPendingNonWakeupAlarms.size() > 0) { + final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; + mTotalDelayTime += thisDelayTime; + if (mMaxDelayTime < thisDelayTime) { + mMaxDelayTime = thisDelayTime; + } + deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED); + mPendingNonWakeupAlarms.clear(); + } + if (mNonInteractiveStartTime > 0) { + long dur = nowELAPSED - mNonInteractiveStartTime; + if (dur > mNonInteractiveTime) { + mNonInteractiveTime = dur; + } + } + } else { + mNonInteractiveStartTime = nowELAPSED; + } + } + } + boolean lookForPackageLocked(String packageName) { for (int i = 0; i < mAlarmBatches.size(); i++) { Batch b = mAlarmBatches.get(i); @@ -1037,12 +1105,12 @@ class AlarmManagerService extends SystemService { } private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, - String prefix, String label, long now) { + String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) { for (int i=list.size()-1; i>=0; i--) { Alarm a = list.get(i); pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); pw.print(": "); pw.println(a); - a.dump(pw, prefix + " ", now); + a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf); } } @@ -1059,14 +1127,13 @@ class AlarmManagerService extends SystemService { } private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list, - String prefix, long nowELAPSED, long nowRTC) { + String prefix, long nowELAPSED, long nowRTC, SimpleDateFormat sdf) { for (int i=list.size()-1; i>=0; i--) { Alarm a = list.get(i); final String label = labelForType(a.type); - long now = (a.type <= RTC) ? nowRTC : nowELAPSED; pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i); pw.print(": "); pw.println(a); - a.dump(pw, prefix + " ", now); + a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf); } } @@ -1077,8 +1144,9 @@ class AlarmManagerService extends SystemService { private native int setKernelTime(long nativeData, long millis); private native int setKernelTimezone(long nativeData, int minuteswest); - void triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, + boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED, final long nowRTC) { + boolean hasWakeup = false; // batches are temporally sorted, so we need only pull from the // start of the list until we either empty it or hit a batch // that is not yet deliverable @@ -1113,8 +1181,14 @@ class AlarmManagerService extends SystemService { maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval), alarm.repeatInterval, alarm.operation, batch.standalone, true, alarm.workSource); - } + // For now we count this as a wakeup alarm, meaning it needs to be + // delivered immediately. In the future we should change this, but + // that required delaying when we reschedule the repeat...! + hasWakeup = false; + } else if (alarm.wakeup) { + hasWakeup = true; + } } } @@ -1125,6 +1199,8 @@ class AlarmManagerService extends SystemService { Slog.v(TAG, "Triggering alarm #" + i + ": " + triggerList.get(i)); } } + + return hasWakeup; } /** @@ -1147,15 +1223,16 @@ class AlarmManagerService extends SystemService { private static class Alarm { public final int type; public final boolean wakeup; + public final PendingIntent operation; + public final String tag; + public final WorkSource workSource; public int count; public long when; public long windowLength; public long whenElapsed; // 'when' in the elapsed time base public long maxWhen; // also in the elapsed time base public long repeatInterval; - public PendingIntent operation; - public WorkSource workSource; - + public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen, long _interval, PendingIntent _op, WorkSource _ws) { type = _type; @@ -1167,12 +1244,17 @@ class AlarmManagerService extends SystemService { maxWhen = _maxWhen; repeatInterval = _interval; operation = _op; + tag = makeTag(_op, _type); workSource = _ws; } + public static String makeTag(PendingIntent pi, int type) { + return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP + ? "*walarm*:" : "*alarm*:"); + } + @Override - public String toString() - { + public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("Alarm{"); sb.append(Integer.toHexString(System.identityHashCode(this))); @@ -1186,11 +1268,20 @@ class AlarmManagerService extends SystemService { return sb.toString(); } - public void dump(PrintWriter pw, String prefix, long now) { + public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED, + SimpleDateFormat sdf) { + final boolean isRtc = (type == RTC || type == RTC_WAKEUP); + pw.print(prefix); pw.print("tag="); pw.println(tag); pw.print(prefix); pw.print("type="); pw.print(type); - pw.print(" whenElapsed="); pw.print(whenElapsed); - pw.print(" when="); TimeUtils.formatDuration(when, now, pw); - pw.print(" window="); pw.print(windowLength); + pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed, + nowELAPSED, pw); + if (isRtc) { + pw.print(" when="); pw.print(sdf.format(new Date(when))); + } else { + pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw); + } + pw.println(); + pw.print(prefix); pw.print("window="); pw.print(windowLength); pw.print(" repeatInterval="); pw.print(repeatInterval); pw.print(" count="); pw.println(count); pw.print(prefix); pw.print("operation="); pw.println(operation); @@ -1216,6 +1307,102 @@ class AlarmManagerService extends SystemService { } } + long currentNonWakeupFuzzLocked(long nowELAPSED) { + long timeSinceOn = nowELAPSED - mNonInteractiveStartTime; + if (timeSinceOn < 5*60*1000) { + // If the screen has been off for 5 minutes, only delay by at most two minutes. + return 2*60*1000; + } else if (timeSinceOn < 30*60*1000) { + // If the screen has been off for 30 minutes, only delay by at most 15 minutes. + return 15*60*1000; + } else { + // Otherwise, we will delay by at most an hour. + return 60*60*1000; + } + } + + boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) { + if (mInteractive) { + return false; + } + if (mLastAlarmDeliveryTime <= 0) { + return false; + } + if (mPendingNonWakeupAlarms.size() > 0 && mNextNonWakeupDeliveryTime > nowELAPSED) { + // This is just a little paranoia, if somehow we have pending non-wakeup alarms + // and the next delivery time is in the past, then just deliver them all. This + // avoids bugs where we get stuck in a loop trying to poll for alarms. + return false; + } + long timeSinceLast = nowELAPSED - mLastAlarmDeliveryTime; + return timeSinceLast <= currentNonWakeupFuzzLocked(nowELAPSED); + } + + void deliverAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED) { + mLastAlarmDeliveryTime = nowELAPSED; + for (int i=0; i<triggerList.size(); i++) { + Alarm alarm = triggerList.get(i); + try { + if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); + alarm.operation.send(getContext(), 0, + mBackgroundIntent.putExtra( + Intent.EXTRA_ALARM_COUNT, alarm.count), + mResultReceiver, mHandler); + + // we have an active broadcast so stay awake. + if (mBroadcastRefCount == 0) { + setWakelockWorkSource(alarm.operation, alarm.workSource, + alarm.type, alarm.tag, true); + mWakeLock.acquire(); + } + final InFlight inflight = new InFlight(AlarmManagerService.this, + alarm.operation, alarm.workSource, alarm.type, alarm.tag); + mInFlight.add(inflight); + mBroadcastRefCount++; + + final BroadcastStats bs = inflight.mBroadcastStats; + bs.count++; + if (bs.nesting == 0) { + bs.nesting = 1; + bs.startTime = nowELAPSED; + } else { + bs.nesting++; + } + final FilterStats fs = inflight.mFilterStats; + fs.count++; + if (fs.nesting == 0) { + fs.nesting = 1; + fs.startTime = nowELAPSED; + } else { + fs.nesting++; + } + if (alarm.type == ELAPSED_REALTIME_WAKEUP + || alarm.type == RTC_WAKEUP) { + bs.numWakeup++; + fs.numWakeup++; + if (alarm.workSource != null && alarm.workSource.size() > 0) { + for (int wi=0; wi<alarm.workSource.size(); wi++) { + ActivityManagerNative.noteWakeupAlarm( + alarm.operation, alarm.workSource.get(wi), + alarm.workSource.getName(wi)); + } + } else { + ActivityManagerNative.noteWakeupAlarm( + alarm.operation, -1, null); + } + } + } catch (PendingIntent.CanceledException e) { + if (alarm.repeatInterval > 0) { + // This IntentSender is no longer valid, but this + // is a repeating alarm, so toss the hoser. + removeImpl(alarm.operation); + } + } catch (RuntimeException e) { + Slog.w(TAG, "Failure sending alarm.", e); + } + } + } + private class AlarmThread extends Thread { public AlarmThread() @@ -1269,70 +1456,35 @@ class AlarmManagerService extends SystemService { } } - triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); - rescheduleKernelAlarmsLocked(); - - // now deliver the alarm intents - for (int i=0; i<triggerList.size(); i++) { - Alarm alarm = triggerList.get(i); - try { - if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); - alarm.operation.send(getContext(), 0, - mBackgroundIntent.putExtra( - Intent.EXTRA_ALARM_COUNT, alarm.count), - mResultReceiver, mHandler); - - // we have an active broadcast so stay awake. - if (mBroadcastRefCount == 0) { - setWakelockWorkSource(alarm.operation, alarm.workSource, - alarm.type, true); - mWakeLock.acquire(); - } - final InFlight inflight = new InFlight(AlarmManagerService.this, - alarm.operation, alarm.workSource, alarm.type); - mInFlight.add(inflight); - mBroadcastRefCount++; - - final BroadcastStats bs = inflight.mBroadcastStats; - bs.count++; - if (bs.nesting == 0) { - bs.nesting = 1; - bs.startTime = nowELAPSED; - } else { - bs.nesting++; - } - final FilterStats fs = inflight.mFilterStats; - fs.count++; - if (fs.nesting == 0) { - fs.nesting = 1; - fs.startTime = nowELAPSED; - } else { - fs.nesting++; - } - if (alarm.type == ELAPSED_REALTIME_WAKEUP - || alarm.type == RTC_WAKEUP) { - bs.numWakeup++; - fs.numWakeup++; - if (alarm.workSource != null && alarm.workSource.size() > 0) { - for (int wi=0; wi<alarm.workSource.size(); wi++) { - ActivityManagerNative.noteWakeupAlarm( - alarm.operation, alarm.workSource.get(wi), - alarm.workSource.getName(wi)); - } - } else { - ActivityManagerNative.noteWakeupAlarm( - alarm.operation, -1, null); - } - } - } catch (PendingIntent.CanceledException e) { - if (alarm.repeatInterval > 0) { - // This IntentSender is no longer valid, but this - // is a repeating alarm, so toss the hoser. - removeImpl(alarm.operation); + boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC); + if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) { + // if there are no wakeup alarms and the screen is off, we can + // delay what we have so far until the future. + if (mPendingNonWakeupAlarms.size() == 0) { + mStartCurrentDelayTime = nowELAPSED; + mNextNonWakeupDeliveryTime = nowELAPSED + + ((currentNonWakeupFuzzLocked(nowELAPSED)*3)/2); + } + mPendingNonWakeupAlarms.addAll(triggerList); + mNumDelayedAlarms += triggerList.size(); + rescheduleKernelAlarmsLocked(); + } else { + // now deliver the alarm intents; if there are pending non-wakeup + // alarms, we need to merge them in to the list. note we don't + // just deliver them first because we generally want non-wakeup + // alarms delivered after wakeup alarms. + rescheduleKernelAlarmsLocked(); + if (mPendingNonWakeupAlarms.size() > 0) { + triggerList.addAll(mPendingNonWakeupAlarms); + Collections.sort(triggerList, mAlarmDispatchComparator); + final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime; + mTotalDelayTime += thisDelayTime; + if (mMaxDelayTime < thisDelayTime) { + mMaxDelayTime = thisDelayTime; } - } catch (RuntimeException e) { - Slog.w(TAG, "Failure sending alarm.", e); + mPendingNonWakeupAlarms.clear(); } + deliverAlarmsLocked(triggerList, nowELAPSED); } } } @@ -1344,14 +1496,13 @@ class AlarmManagerService extends SystemService { * @param pi PendingIntent to attribute blame to if ws is null. * @param ws WorkSource to attribute blame. */ - void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, boolean first) { + void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag, + boolean first) { try { final boolean unimportant = pi == mTimeTickSender; mWakeLock.setUnimportantForLogging(unimportant); if (first || mLastWakeLockUnimportantForLogging) { - mWakeLock.setHistoryTag(pi.getTag( - type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP - ? "*walarm*:" : "*alarm*:")); + mWakeLock.setHistoryTag(tag); } else { mWakeLock.setHistoryTag(null); } @@ -1462,6 +1613,23 @@ class AlarmManagerService extends SystemService { } } + class InteractiveStateReceiver extends BroadcastReceiver { + public InteractiveStateReceiver() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + getContext().registerReceiver(this, filter); + } + + @Override + public void onReceive(Context context, Intent intent) { + synchronized (mLock) { + interactiveStateChangedLocked(Intent.ACTION_SCREEN_ON.equals(intent.getAction())); + } + } + } + class UninstallReceiver extends BroadcastReceiver { public UninstallReceiver() { IntentFilter filter = new IntentFilter(); @@ -1589,7 +1757,7 @@ class AlarmManagerService extends SystemService { if (mInFlight.size() > 0) { InFlight inFlight = mInFlight.get(0); setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource, - inFlight.mAlarmType, false); + inFlight.mAlarmType, inFlight.mTag, false); } else { // should never happen mLog.w("Alarm wakelock still held but sent queue empty"); diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index be20616..bfa0402 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -1253,7 +1253,10 @@ public class AppOpsService extends IAppOpsService.Stub { public void removeUser(int userHandle) throws RemoteException { checkSystemUid("removeUser"); mOpRestrictions.remove(userHandle); - mProfileOwnerUids.removeAt(mProfileOwnerUids.indexOfKey(userHandle)); + final int index = mProfileOwnerUids.indexOfKey(userHandle); + if (index >= 0) { + mProfileOwnerUids.removeAt(index); + } } private void checkSystemUid(String function) { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5f53e49..af53fef 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -20,7 +20,7 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; -import static android.net.ConnectivityManager.NetworkCallbacks; +import static android.net.ConnectivityManager.NetworkCallbackListener; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_DUMMY; import static android.net.ConnectivityManager.TYPE_ETHERNET; @@ -398,7 +398,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * used internally when registering NetworkFactories - * obj = Messenger + * obj = NetworkFactoryInfo */ private static final int EVENT_REGISTER_NETWORK_FACTORY = 17; @@ -434,6 +434,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_RELEASE_NETWORK_REQUEST = 22; + /** + * used internally when registering NetworkFactories + * obj = Messenger + */ + private static final int EVENT_UNREGISTER_NETWORK_FACTORY = 23; + + /** Handler used for internal events. */ final private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -507,10 +514,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; + // sequence number for Networks private final static int MIN_NET_ID = 10; // some reserved marks private final static int MAX_NET_ID = 65535; private int mNextNetId = MIN_NET_ID; + // sequence number of NetworkRequests + private int mNextNetworkRequestId = 1; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -526,7 +537,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - mDefaultRequest = new NetworkRequest(netCap, true); + mDefaultRequest = new NetworkRequest(netCap, true, nextNetworkRequestId()); NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(), NetworkRequestInfo.REQUEST); mNetworkRequests.put(mDefaultRequest, nri); @@ -773,6 +784,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); } + private synchronized int nextNetworkRequestId() { + return mNextNetworkRequestId++; + } + private synchronized int nextNetId() { int netId = mNextNetId; if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID; @@ -2881,6 +2896,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } + pw.println("NetworkFactories for:"); + pw.increaseIndent(); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + pw.println(nfi.name); + } + pw.decreaseIndent(); + pw.println(); + NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId); pw.print("Active default network: "); if (defaultNai == null) { @@ -2975,6 +2998,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (nai == null) { loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED"); } else { + if (VDBG) log("Update of Linkproperties for " + nai.name()); LinkProperties oldLp = nai.linkProperties; nai.linkProperties = (LinkProperties)msg.obj; updateLinkProperties(nai, oldLp); @@ -3088,18 +3112,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleAsyncChannelHalfConnect(Message msg) { AsyncChannel ac = (AsyncChannel) msg.obj; - if (mNetworkFactories.contains(ac)) { + if (mNetworkFactoryInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); // A network factory has connected. Send it all current NetworkRequests. for (NetworkRequestInfo nri : mNetworkRequests.values()) { + if (nri.isRequest == false) continue; NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, (nai != null ? nai.currentScore : 0), 0, nri.request); } } else { loge("Error connecting NetworkFactory"); - mNetworkFactories.remove(ac); + mNetworkFactoryInfos.remove(msg.obj); } } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { @@ -3206,8 +3231,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetworkRequests.put(nri.request, nri); if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) { if (DBG) log("sending new NetworkRequest to factories"); - for (AsyncChannel ac : mNetworkFactories) { - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); } } } @@ -3228,8 +3253,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (nri.isRequest) { - for (AsyncChannel factory : mNetworkFactories) { - factory.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); } if (affectedNetwork != null) { @@ -3348,7 +3373,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } case EVENT_REGISTER_NETWORK_FACTORY: { - handleRegisterNetworkFactory((Messenger)msg.obj); + handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj); + break; + } + case EVENT_UNREGISTER_NETWORK_FACTORY: { + handleUnregisterNetworkFactory((Messenger)msg.obj); break; } case EVENT_REGISTER_NETWORK_AGENT: { @@ -5214,10 +5243,22 @@ public class ConnectivityService extends IConnectivityManager.Stub { mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent); } - private final ArrayList<AsyncChannel> mNetworkFactories = new ArrayList<AsyncChannel>(); + private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos = + new HashMap<Messenger, NetworkFactoryInfo>(); private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<NetworkRequest, NetworkRequestInfo>(); + private static class NetworkFactoryInfo { + public final String name; + public final Messenger messenger; + public final AsyncChannel asyncChannel; + + public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) { + this.name = name; + this.messenger = messenger; + this.asyncChannel = asyncChannel; + } + } private class NetworkRequestInfo implements IBinder.DeathRecipient { static final boolean REQUEST = true; @@ -5255,6 +5296,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { request + ", " + mBinder + ")"); releaseNetworkRequest(request); } + + public String toString() { + return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" + + mPid + " for " + request; + } } @Override @@ -5271,7 +5317,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities)); + networkCapabilities), false, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); @@ -5297,7 +5343,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { enforceAccessPermission(); NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities)); + networkCapabilities), false, nextNetworkRequestId()); if (DBG) log("listenForNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.LISTEN); @@ -5318,24 +5364,31 @@ public class ConnectivityService extends IConnectivityManager.Stub { } @Override - public void registerNetworkFactory(Messenger messenger) { + public void registerNetworkFactory(Messenger messenger, String name) { enforceConnectivityInternalPermission(); - mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger)); + NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel()); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); } - private void handleRegisterNetworkFactory(Messenger messenger) { - if (VDBG) log("Got NetworkFactory Messenger"); - AsyncChannel ac = new AsyncChannel(); - mNetworkFactories.add(ac); - ac.connect(mContext, mTrackerHandler, messenger); - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - if (nri.isRequest) { - int score = 0; - NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); - if (currentNetwork != null) score = currentNetwork.currentScore; - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); - } + private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) { + if (VDBG) log("Got NetworkFactory Messenger for " + nfi.name); + mNetworkFactoryInfos.put(nfi.messenger, nfi); + nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger); + } + + @Override + public void unregisterNetworkFactory(Messenger messenger) { + enforceConnectivityInternalPermission(); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger)); + } + + private void handleUnregisterNetworkFactory(Messenger messenger) { + NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger); + if (nfi == null) { + if (VDBG) log("Failed to find Messenger in unregisterNetworkFactory"); + return; } + if (VDBG) log("unregisterNetworkFactory for " + nfi.name); } /** @@ -5527,8 +5580,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); - for (AsyncChannel ac : mNetworkFactories) { - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); } } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 50553ee..5cb2a8a 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -3439,7 +3439,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub + " mShowExplicitlyRequested=" + mShowExplicitlyRequested + " mShowForced=" + mShowForced + " mInputShown=" + mInputShown); - p.println(" mSystemReady=" + mSystemReady + " mScreenOn=" + mScreenOn); + p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mScreenOn); } p.println(" "); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index e54e5d0..11fc941 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -1847,10 +1847,10 @@ public class LocationManagerService extends ILocationManager.Stub { return true; } if (mGeocodeProvider != null) { - if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return true; + if (doesUidHavePackage(uid, mGeocodeProvider.getConnectedPackageName())) return true; } for (LocationProviderProxy proxy : mProxyProviders) { - if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return true; + if (doesUidHavePackage(uid, proxy.getConnectedPackageName())) return true; } return false; } @@ -1876,19 +1876,23 @@ public class LocationManagerService extends ILocationManager.Stub { "or UID of a currently bound location provider"); } - private boolean doesPackageHaveUid(int uid, String packageName) { + /** + * Returns true if the given package belongs to the given uid. + */ + private boolean doesUidHavePackage(int uid, String packageName) { if (packageName == null) { return false; } - try { - ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0); - if (appInfo.uid != uid) { - return false; - } - } catch (NameNotFoundException e) { + String[] packageNames = mPackageManager.getPackagesForUid(uid); + if (packageNames == null) { return false; } - return true; + for (String name : packageNames) { + if (packageName.equals(name)) { + return true; + } + } + return false; } @Override diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7abc75f..7cd4ef8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -13837,7 +13837,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) { - ProxyInfo proxy = intent.getParcelableExtra("proxy"); + ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO); mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy)); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index c1e5e5b..33e59a7 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -742,19 +742,10 @@ final class ActivityStack { int w = mThumbnailWidth; int h = mThumbnailHeight; if (w < 0) { - Configuration config = res.getConfiguration(); - boolean useAlternateRecents = (config.smallestScreenWidthDp < 600); - if (useAlternateRecents) { - mThumbnailWidth = w = - res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width); - mThumbnailHeight = h = - res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height); - } else { - mThumbnailWidth = w = - res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width); - mThumbnailHeight = h = - res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height); - } + mThumbnailWidth = w = + res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width); + mThumbnailHeight = h = + res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height); } if (w > 0) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 3d5fb57..bc264fa 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -421,6 +421,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final boolean mustNotify; boolean mustInitialize = false; boolean wasDimOrDoze = false; + boolean autoBrightnessAdjustmentChanged = false; synchronized (mLock) { mPendingUpdatePowerStateLocked = false; @@ -437,6 +438,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } else if (mPendingRequestChangedLocked) { wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE); + autoBrightnessAdjustmentChanged = (mPowerRequest.screenAutoBrightnessAdjustment + != mPendingRequestLocked.screenAutoBrightnessAdjustment); mPowerRequest.copyFrom(mPendingRequestLocked); mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; mPendingWaitForNegativeProximityLocked = false; @@ -494,7 +497,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (screenAutoBrightness >= 0 && mPowerRequest.useAutoBrightness) { // Use current auto-brightness value. target = screenAutoBrightness; - slow = mUsingScreenAutoBrightness; + slow = mUsingScreenAutoBrightness && !autoBrightnessAdjustmentChanged; mUsingScreenAutoBrightness = true; } else { // Light sensor is disabled or not ready yet. diff --git a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java index 1c5cacd..b31153b 100644 --- a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java +++ b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java @@ -26,7 +26,7 @@ import android.media.routeprovider.RouteProviderService; import android.media.routeprovider.RouteRequest; import android.media.session.RouteEvent; import android.media.session.RouteInfo; -import android.media.session.Session; +import android.media.session.MediaSession; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 9677577..00d364b 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -24,16 +24,16 @@ import android.media.session.ISessionController; import android.media.session.ISessionControllerCallback; import android.media.session.ISession; import android.media.session.ISessionCallback; -import android.media.session.SessionController; -import android.media.session.MediaMetadata; +import android.media.session.MediaController; import android.media.session.RouteCommand; import android.media.session.RouteInfo; import android.media.session.RouteOptions; import android.media.session.RouteEvent; -import android.media.session.Session; -import android.media.session.SessionInfo; +import android.media.session.MediaSession; +import android.media.session.MediaSessionInfo; import android.media.session.RouteInterface; import android.media.session.PlaybackState; +import android.media.MediaMetadata; import android.media.Rating; import android.os.Bundle; import android.os.Handler; @@ -85,7 +85,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private final int mOwnerPid; private final int mOwnerUid; private final int mUserId; - private final SessionInfo mSessionInfo; + private final MediaSessionInfo mSessionInfo; private final String mTag; private final ControllerStub mController; private final SessionStub mSession; @@ -120,7 +120,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mOwnerPid = ownerPid; mOwnerUid = ownerUid; mUserId = userId; - mSessionInfo = new SessionInfo(UUID.randomUUID().toString(), ownerPackageName); + mSessionInfo = new MediaSessionInfo(UUID.randomUUID().toString(), ownerPackageName); mTag = tag; mController = new ControllerStub(); mSession = new SessionStub(); @@ -130,7 +130,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } /** - * Get the binder for the {@link Session}. + * Get the binder for the {@link MediaSession}. * * @return The session binder apps talk to. */ @@ -139,7 +139,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } /** - * Get the binder for the {@link SessionController}. + * Get the binder for the {@link MediaController}. * * @return The controller binder apps talk to. */ @@ -170,7 +170,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { * * @return Info that identifies this session. */ - public SessionInfo getSessionInfo() { + public MediaSessionInfo getSessionInfo() { return mSessionInfo; } @@ -209,7 +209,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { * @return True if this is a system priority session, false otherwise */ public boolean isSystemPriority() { - return (mFlags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0; + return (mFlags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0; } /** @@ -221,7 +221,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { public void selectRoute(RouteInfo route) { synchronized (mLock) { if (route != mRoute) { - disconnect(Session.DISCONNECT_REASON_ROUTE_CHANGED); + disconnect(MediaSession.DISCONNECT_REASON_ROUTE_CHANGED); } mRoute = route; } @@ -335,7 +335,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } public boolean isTransportControlEnabled() { - return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS); + return hasFlag(MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); } @Override @@ -353,7 +353,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { return; } if (isConnected()) { - disconnectLocked(Session.DISCONNECT_REASON_SESSION_DESTROYED); + disconnectLocked(MediaSession.DISCONNECT_REASON_SESSION_DESTROYED); } mRoute = null; mRequest = null; @@ -365,6 +365,10 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { return mSessionCb.mCb; } + public void sendMediaButton(KeyEvent ke, ResultReceiver cb) { + mSessionCb.sendMediaButton(ke, cb); + } + public void dump(PrintWriter pw, String prefix) { pw.println(prefix + mTag + " " + this); @@ -536,7 +540,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { @Override public void disconnect() { - MediaSessionRecord.this.disconnect(Session.DISCONNECT_REASON_PROVIDER_DISCONNECTED); + MediaSessionRecord.this.disconnect(MediaSession.DISCONNECT_REASON_PROVIDER_DISCONNECTED); } }; @@ -565,7 +569,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { @Override public void setFlags(int flags) { - if ((flags & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { + if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { int pid = getCallingPid(); int uid = getCallingUid(); mService.enforcePhoneStatePermission(pid, uid); @@ -623,7 +627,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { public void disconnectFromRoute(RouteInfo route) { if (route != null && mRoute != null && TextUtils.equals(route.getId(), mRoute.getId())) { - disconnect(Session.DISCONNECT_REASON_SESSION_DISCONNECTED); + disconnect(MediaSession.DISCONNECT_REASON_SESSION_DISCONNECTED); } } @@ -645,11 +649,11 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mCb = cb; } - public void sendMediaButton(KeyEvent keyEvent) { + public void sendMediaButton(KeyEvent keyEvent, ResultReceiver cb) { Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); try { - mCb.onMediaButton(mediaButtonIntent); + mCb.onMediaButton(mediaButtonIntent, cb); } catch (RemoteException e) { Slog.e(TAG, "Remote failure in sendMediaRequest.", e); } @@ -785,7 +789,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { @Override public void sendMediaButton(KeyEvent mediaButtonIntent) { - mSessionCb.sendMediaButton(mediaButtonIntent); + mSessionCb.sendMediaButton(mediaButtonIntent, null); } @Override diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 78f3b5f..d9e45f5ba 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -17,9 +17,12 @@ package com.android.server.media; import android.Manifest; +import android.app.Activity; import android.app.ActivityManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.media.routeprovider.RouteRequest; import android.media.session.ISession; @@ -27,16 +30,20 @@ import android.media.session.ISessionCallback; import android.media.session.ISessionManager; import android.media.session.RouteInfo; import android.media.session.RouteOptions; -import android.media.session.Session; +import android.media.session.MediaSession; import android.os.Binder; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.PowerManager; import android.os.RemoteException; +import android.os.ResultReceiver; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; +import android.view.KeyEvent; import com.android.server.SystemService; import com.android.server.Watchdog; @@ -64,6 +71,7 @@ public class MediaSessionService extends SystemService implements Monitor { // = new ArrayList<MediaRouteProviderProxy>(); private final Object mLock = new Object(); private final Handler mHandler = new Handler(); + private final PowerManager.WakeLock mMediaEventWakeLock; private MediaSessionRecord mPrioritySession; private int mCurrentUserId = -1; @@ -79,6 +87,8 @@ public class MediaSessionService extends SystemService implements Monitor { super(context); mSessionManagerImpl = new SessionManagerImpl(); mPriorityStack = new MediaSessionStack(); + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent"); } @Override @@ -377,7 +387,7 @@ public class MediaSessionService extends SystemService implements Monitor { /* * When a session is created the following things need to happen. - * 1. It's callback binder needs a link to death + * 1. Its callback binder needs a link to death * 2. It needs to be added to all sessions. * 3. It needs to be added to the priority stack. * 4. It needs to be added to the relevant user record. @@ -493,7 +503,7 @@ public class MediaSessionService extends SystemService implements Monitor { MediaSessionRecord session = mSessions.get(i); MediaSessionService.this.destroySessionLocked(session); if (session.isConnected()) { - session.disconnect(Session.DISCONNECT_REASON_USER_STOPPING); + session.disconnect(MediaSession.DISCONNECT_REASON_USER_STOPPING); } } } @@ -585,9 +595,10 @@ public class MediaSessionService extends SystemService implements Monitor { } class SessionManagerImpl extends ISessionManager.Stub { - // TODO add createSessionAsUser, pass user-id to - // ActivityManagerNative.handleIncomingUser and stash result for use - // when starting services on that session's behalf. + private static final String EXTRA_WAKELOCK_ACQUIRED = + "android.media.AudioService.WAKELOCK_ACQUIRED"; + private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number + @Override public ISession createSession(String packageName, ISessionCallback cb, String tag, int userId) throws RemoteException { @@ -644,6 +655,59 @@ public class MediaSessionService extends SystemService implements Monitor { } } + /** + * Handles the dispatching of the media button events to one of the + * registered listeners, or if there was none, broadcast an + * ACTION_MEDIA_BUTTON intent to the rest of the system. + * + * @param keyEvent a non-null KeyEvent whose key code is one of the + * supported media buttons + * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held + * while this key event is dispatched. + */ + @Override + public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { + if (keyEvent == null || !KeyEvent.isMediaKey(keyEvent.getKeyCode())) { + Log.w(TAG, "Attempted to dispatch null or non-media key event."); + return; + } + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + + try { + if (needWakeLock) { + mMediaEventWakeLock.acquire(); + } + synchronized (mLock) { + MediaSessionRecord mbSession = mPriorityStack + .getDefaultMediaButtonSession(mCurrentUserId); + if (mbSession != null) { + if (DEBUG) { + Log.d(TAG, "Sending media key to " + mbSession.getSessionInfo()); + } + mbSession.sendMediaButton(keyEvent, + needWakeLock ? mKeyEventDoneReceiver : null); + } else { + if (DEBUG) { + Log.d(TAG, "Sending media key ordered broadcast"); + } + // Fallback to legacy behavior + Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); + keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); + if (needWakeLock) { + keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, + WAKELOCK_RELEASE_ON_FINISHED); + } + getContext().sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, + null, mKeyEventDone, mHandler, Activity.RESULT_OK, null, null); + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { if (getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP) @@ -678,6 +742,36 @@ public class MediaSessionService extends SystemService implements Monitor { } } } + + ResultReceiver mKeyEventDoneReceiver = new ResultReceiver(mHandler) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + synchronized (mLock) { + if (mMediaEventWakeLock.isHeld()) { + mMediaEventWakeLock.release(); + } + } + } + }; + + BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) { + return; + } + Bundle extras = intent.getExtras(); + if (extras == null) { + return; + } + synchronized (mLock) { + if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED) + && mMediaEventWakeLock.isHeld()) { + mMediaEventWakeLock.release(); + } + } + } + }; } } diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index f89b14a..7ba9212 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -17,7 +17,7 @@ package com.android.server.media; import android.media.session.PlaybackState; -import android.media.session.Session; +import android.media.session.MediaSession; import android.os.UserHandle; import java.io.PrintWriter; @@ -62,7 +62,7 @@ public class MediaSessionStack { */ public void addSession(MediaSessionRecord record) { mSessions.add(record); - if ((record.getFlags() & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { + if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) { mGlobalPrioritySession = record; } clearCache(); @@ -134,7 +134,7 @@ public class MediaSessionStack { public ArrayList<MediaSessionRecord> getTransportControlSessions(int userId) { if (mCachedTransportControlList == null) { mCachedTransportControlList = getPriorityListLocked(true, - Session.FLAG_HANDLES_TRANSPORT_CONTROLS, userId); + MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS, userId); } return mCachedTransportControlList; } @@ -170,7 +170,7 @@ public class MediaSessionStack { return mCachedButtonReceiver; } ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, - Session.FLAG_HANDLES_MEDIA_BUTTONS, userId); + MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userId); if (records.size() > 0) { mCachedButtonReceiver = records.get(0); } diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index 007032e..dbfb1cf 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -88,6 +88,8 @@ public class ConditionProviders extends ManagedServices { for (int i = 0; i < mRecords.size(); i++) { pw.print(" "); pw.println(mRecords.get(i)); } + pw.print(" mCountdownHelper: "); + pw.println(mCountdownHelper.getCurrentConditionDescription()); } } @@ -474,6 +476,16 @@ public class ConditionProviders extends ManagedServices { } } + public String getCurrentConditionDescription() { + if (mCurrent == 0) return null; + final long time = mCurrent; + final long now = System.currentTimeMillis(); + final CharSequence span = + DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS); + return String.format("Scheduled for %s, %s in the future (%s), now=%s", + ts(time), time - now, span, ts(now)); + } + private String ts(long time) { return new Date(time) + " (" + time + ")"; } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1734a33..9569c0d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -63,7 +63,7 @@ import android.service.notification.INotificationListener; import android.service.notification.IConditionListener; import android.service.notification.IConditionProvider; import android.service.notification.NotificationListenerService; -import android.service.notification.NotificationOrderUpdate; +import android.service.notification.NotificationRankingUpdate; import android.service.notification.StatusBarNotification; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; @@ -1744,7 +1744,7 @@ public class NotificationManagerService extends SystemService { sendAccessibilityEvent(notification, pkg); } - mListeners.notifyPostedLocked(r.sbn); + mListeners.notifyPostedLocked(r.sbn, cloneNotificationListLocked()); } else { Slog.e(TAG, "Not posting notification with icon==0: " + notification); if (old != null && old.statusBarKey != null) { @@ -1755,7 +1755,7 @@ public class NotificationManagerService extends SystemService { Binder.restoreCallingIdentity(identity); } - mListeners.notifyRemovedLocked(r.sbn); + mListeners.notifyRemovedLocked(r.sbn, cloneNotificationListLocked()); } // ATTENTION: in a future release we will bail out here // so that we do not play sounds, show lights, etc. for invalid @@ -2041,14 +2041,17 @@ public class NotificationManagerService extends SystemService { private void handleSendRankingUpdate() { synchronized (mNotificationList) { - final int N = mNotificationList.size(); - ArrayList<StatusBarNotification> sbns = - new ArrayList<StatusBarNotification>(N); - for (int i = 0; i < N; i++ ) { - sbns.add(mNotificationList.get(i).sbn); - } - mListeners.notifyOrderUpdateLocked(sbns); + mListeners.notifyRankingUpdateLocked(cloneNotificationListLocked()); + } + } + + private ArrayList<StatusBarNotification> cloneNotificationListLocked() { + final int N = mNotificationList.size(); + ArrayList<StatusBarNotification> sbns = new ArrayList<StatusBarNotification>(N); + for (int i = 0; i < N; i++) { + sbns.add(mNotificationList.get(i).sbn); } + return sbns; } private final class WorkerHandler extends Handler @@ -2136,7 +2139,7 @@ public class NotificationManagerService extends SystemService { Binder.restoreCallingIdentity(identity); } r.statusBarKey = null; - mListeners.notifyRemovedLocked(r.sbn); + mListeners.notifyRemovedLocked(r.sbn, cloneNotificationListLocked()); } // sound @@ -2442,6 +2445,33 @@ public class NotificationManagerService extends SystemService { } } + /** + * Generates a NotificationRankingUpdate from 'sbns', considering only + * notifications visible to the given listener. + */ + private static NotificationRankingUpdate makeRankingUpdateForListener(ManagedServiceInfo info, + ArrayList<StatusBarNotification> sbns) { + int speedBumpIndex = -1; + ArrayList<String> keys = new ArrayList<String>(sbns.size()); + ArrayList<String> dndKeys = new ArrayList<String>(sbns.size()); + for (StatusBarNotification sbn: sbns) { + if (!info.enabledAndUserMatches(sbn.getUserId())) { + continue; + } + keys.add(sbn.getKey()); + if (sbn.getNotification().extras.getBoolean(EXTRA_INTERCEPT)) { + dndKeys.add(sbn.getKey()); + } + if (speedBumpIndex == -1 && + sbn.getNotification().priority == Notification.PRIORITY_MIN) { + speedBumpIndex = keys.size() - 1; + } + } + String[] keysAr = keys.toArray(new String[keys.size()]); + String[] dndKeysAr = dndKeys.toArray(new String[dndKeys.size()]); + return new NotificationRankingUpdate(keysAr, dndKeysAr, speedBumpIndex); + } + public class NotificationListeners extends ManagedServices { public NotificationListeners() { @@ -2468,9 +2498,12 @@ public class NotificationManagerService extends SystemService { @Override public void onServiceAdded(ManagedServiceInfo info) { final INotificationListener listener = (INotificationListener) info.service; - final String[] keys = getActiveNotificationKeys(listener); + final ArrayList<StatusBarNotification> sbns; + synchronized (mNotificationList) { + sbns = cloneNotificationListLocked(); + } try { - listener.onListenerConnected(new NotificationOrderUpdate(keys)); + listener.onListenerConnected(makeRankingUpdateForListener(info, sbns)); } catch (RemoteException e) { // we tried } @@ -2479,44 +2512,47 @@ public class NotificationManagerService extends SystemService { /** * asynchronously notify all listeners about a new notification */ - public void notifyPostedLocked(StatusBarNotification sbn) { + public void notifyPostedLocked(StatusBarNotification sbn, + final ArrayList<StatusBarNotification> sbns) { // make a copy in case changes are made to the underlying Notification object final StatusBarNotification sbnClone = sbn.clone(); for (final ManagedServiceInfo info : mServices) { - if (info.isEnabledForCurrentProfiles()) { - final INotificationListener listener = (INotificationListener) info.service; - final String[] keys = getActiveNotificationKeys(listener); - if (keys.length > 0) { - mHandler.post(new Runnable() { - @Override - public void run() { - notifyPostedIfUserMatch(info, sbnClone, keys); - } - }); - } + if (!info.isEnabledForCurrentProfiles()) { + continue; } + final NotificationRankingUpdate update = makeRankingUpdateForListener(info, sbns); + if (update.getOrderedKeys().length == 0) { + continue; + } + mHandler.post(new Runnable() { + @Override + public void run() { + notifyPostedIfUserMatch(info, sbnClone, update); + } + }); } } /** * asynchronously notify all listeners about a removed notification */ - public void notifyRemovedLocked(StatusBarNotification sbn) { + public void notifyRemovedLocked(StatusBarNotification sbn, + final ArrayList<StatusBarNotification> sbns) { // make a copy in case changes are made to the underlying Notification object // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the // notification final StatusBarNotification sbnLight = sbn.cloneLight(); for (final ManagedServiceInfo info : mServices) { - if (info.isEnabledForCurrentProfiles()) { - final INotificationListener listener = (INotificationListener) info.service; - final String[] keys = getActiveNotificationKeys(listener); - mHandler.post(new Runnable() { - @Override - public void run() { - notifyRemovedIfUserMatch(info, sbnLight, keys); - } - }); + if (!info.isEnabledForCurrentProfiles()) { + continue; } + mHandler.post(new Runnable() { + @Override + public void run() { + notifyRemovedIfUserMatch(info, sbnLight, + makeRankingUpdateForListener(info, sbns)); + } + }); } } @@ -2526,60 +2562,52 @@ public class NotificationManagerService extends SystemService { * must not rely on mutable members of these objects, such as the * {@link Notification}. */ - public void notifyOrderUpdateLocked(final ArrayList<StatusBarNotification> sbns) { + public void notifyRankingUpdateLocked(final ArrayList<StatusBarNotification> sbns) { for (final ManagedServiceInfo serviceInfo : mServices) { + if (!serviceInfo.isEnabledForCurrentProfiles()) { + continue; + } mHandler.post(new Runnable() { @Override public void run() { - notifyOrderUpdateIfUserMatch(serviceInfo, sbns); + notifyRankingUpdate(serviceInfo, + makeRankingUpdateForListener(serviceInfo, sbns)); } }); } } private void notifyPostedIfUserMatch(final ManagedServiceInfo info, - final StatusBarNotification sbn, String[] keys) { + final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { if (!info.enabledAndUserMatches(sbn.getUserId())) { return; } final INotificationListener listener = (INotificationListener)info.service; try { - listener.onNotificationPosted(sbn, new NotificationOrderUpdate(keys)); + listener.onNotificationPosted(sbn, rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (posted): " + listener, ex); } } private void notifyRemovedIfUserMatch(ManagedServiceInfo info, StatusBarNotification sbn, - String[] keys) { + NotificationRankingUpdate rankingUpdate) { if (!info.enabledAndUserMatches(sbn.getUserId())) { return; } - final INotificationListener listener = (INotificationListener)info.service; + final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationRemoved(sbn, new NotificationOrderUpdate(keys)); + listener.onNotificationRemoved(sbn, rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (removed): " + listener, ex); } } - /** - * @param sbns an array of {@link StatusBarNotification}s to consider. This code - * must not rely on mutable members of these objects, such as the - * {@link Notification}. - */ - public void notifyOrderUpdateIfUserMatch(ManagedServiceInfo info, - ArrayList<StatusBarNotification> sbns) { - ArrayList<String> keys = new ArrayList<String>(sbns.size()); - for (StatusBarNotification sbn: sbns) { - if (info.enabledAndUserMatches(sbn.getUserId())) { - keys.add(sbn.getKey()); - } - } - final INotificationListener listener = (INotificationListener)info.service; + private void notifyRankingUpdate(ManagedServiceInfo info, + NotificationRankingUpdate rankingUpdate) { + final INotificationListener listener = (INotificationListener) info.service; try { - listener.onNotificationOrderUpdate( - new NotificationOrderUpdate(keys.toArray(new String[keys.size()]))); + listener.onNotificationRankingUpdate(rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 61b3a89..46c5482 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -11876,6 +11876,7 @@ public class PackageManagerService extends IPackageManager.Stub { pw.println(" cmd may be one of:"); pw.println(" l[ibraries]: list known shared libraries"); pw.println(" f[ibraries]: list device features"); + pw.println(" k[eysets]: print known keysets"); pw.println(" r[esolvers]: dump intent resolvers"); pw.println(" perm[issions]: dump permissions"); pw.println(" pref[erred]: print preferred package settings"); @@ -11886,8 +11887,8 @@ public class PackageManagerService extends IPackageManager.Stub { pw.println(" m[essages]: print collected runtime messages"); pw.println(" v[erifiers]: print package verifier info"); pw.println(" version: print database version info"); + pw.println(" write: write current settings now"); pw.println(" <package.name>: info about given package"); - pw.println(" k[eysets]: print known keysets"); return; } else if ("--checkin".equals(opt)) { checkin = true; @@ -11938,6 +11939,12 @@ public class PackageManagerService extends IPackageManager.Stub { dumpState.setDump(DumpState.DUMP_VERSION); } else if ("k".equals(cmd) || "keysets".equals(cmd)) { dumpState.setDump(DumpState.DUMP_KEYSETS); + } else if ("write".equals(cmd)) { + synchronized (mPackages) { + mSettings.writeLPr(); + pw.println("Settings written."); + return; + } } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 131d05b..fd180bf 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -511,8 +511,16 @@ public class UserManagerService extends IUserManager.Stub { * Check if we've hit the limit of how many users can be created. */ private boolean isUserLimitReachedLocked() { - int nUsers = mUsers.size(); - return nUsers >= UserManager.getMaxSupportedUsers(); + int aliveUserCount = 0; + final int totalUserCount = mUsers.size(); + // Skip over users being removed + for (int i = 0; i < totalUserCount; i++) { + UserInfo user = mUsers.valueAt(i); + if (!mRemovingUserIds.get(user.id)) { + aliveUserCount++; + } + } + return aliveUserCount >= UserManager.getMaxSupportedUsers(); } /** diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 738ad32..8b8c73d 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -460,6 +460,24 @@ public class StatusBarManagerService extends IStatusBarService.Stub } @Override + public void showRecentApps(boolean triggeredFromAltTab) { + if (mBar != null) { + try { + mBar.showRecentApps(triggeredFromAltTab); + } catch (RemoteException ex) {} + } + } + + @Override + public void hideRecentApps(boolean triggeredFromAltTab) { + if (mBar != null) { + try { + mBar.hideRecentApps(triggeredFromAltTab); + } catch (RemoteException ex) {} + } + } + + @Override public void setCurrentUser(int newUserId) { if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId); mCurrentUserId = newUserId; diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index c1b9a33..efaa91b 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -324,8 +324,6 @@ public class TrustManagerService extends SystemService { mTrustListeners.get(i).onTrustChanged(enabled, userId); } catch (RemoteException e) { Slog.e(TAG, "Exception while notifying TrustListener. Removing listener.", e); - mTrustListeners.get(i); - i--; } } } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 99ec242..e2d2ac6 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.IRemoteCallback; import android.os.SystemProperties; import android.util.Slog; +import android.view.View; import android.view.WindowManager; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; @@ -34,7 +35,6 @@ import android.view.animation.AnimationUtils; import android.view.animation.ClipRectAnimation; import android.view.animation.Interpolator; import android.view.animation.ScaleAnimation; - import android.view.animation.TranslateAnimation; import com.android.internal.util.DumpUtils.Dump; import com.android.server.AttributeCache; @@ -500,7 +500,8 @@ public class AppTransition implements Dump { */ Animation createAlternateThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth, int appHeight, int orientation, int transit, - Rect containingFrame, Rect contentInsets) { + Rect containingFrame, Rect contentInsets, + boolean isFullScreen) { Animation a; final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; @@ -520,6 +521,9 @@ public class AppTransition implements Dump { scaledTopDecor = (int) (scale * contentInsets.top); int unscaledThumbHeight = (int) (thumbHeight / scale); mTmpFromClipRect.set(containingFrame); + if (isFullScreen) { + mTmpFromClipRect.top = contentInsets.top; + } mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); mTmpToClipRect.set(containingFrame); } else { @@ -527,7 +531,12 @@ public class AppTransition implements Dump { scale = thumbHeight / (appHeight - contentInsets.top); scaledTopDecor = (int) (scale * contentInsets.top); int unscaledThumbWidth = (int) (thumbWidth / scale); + int unscaledThumbHeight = (int) (thumbHeight / scale); mTmpFromClipRect.set(containingFrame); + if (isFullScreen) { + mTmpFromClipRect.top = contentInsets.top; + mTmpFromClipRect.bottom = (mTmpFromClipRect.top + unscaledThumbHeight); + } mTmpFromClipRect.right = (mTmpFromClipRect.left + unscaledThumbWidth); mTmpToClipRect.set(containingFrame); } @@ -575,14 +584,22 @@ public class AppTransition implements Dump { int unscaledThumbHeight = (int) (thumbHeight / scale); mTmpFromClipRect.set(containingFrame); mTmpToClipRect.set(containingFrame); + if (isFullScreen) { + mTmpToClipRect.top = contentInsets.top; + } mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); } else { // In landscape, we scale the height and clip to the top/left square scale = thumbHeight / (appHeight - contentInsets.top); scaledTopDecor = (int) (scale * contentInsets.top); int unscaledThumbWidth = (int) (thumbWidth / scale); + int unscaledThumbHeight = (int) (thumbHeight / scale); mTmpFromClipRect.set(containingFrame); mTmpToClipRect.set(containingFrame); + if (isFullScreen) { + mTmpToClipRect.top = contentInsets.top; + mTmpToClipRect.bottom = (mTmpToClipRect.top + unscaledThumbHeight); + } mTmpToClipRect.right = (mTmpToClipRect.left + unscaledThumbWidth); } @@ -679,7 +696,7 @@ public class AppTransition implements Dump { Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, int appWidth, int appHeight, int orientation, - Rect containingFrame, Rect contentInsets, Configuration configuration) { + Rect containingFrame, Rect contentInsets, boolean isFullScreen) { Animation a; if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) { a = loadAnimation(mNextAppTransitionPackage, enter ? @@ -700,15 +717,9 @@ public class AppTransition implements Dump { mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) { mNextAppTransitionScaleUp = (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP); - boolean useAlternateThumbnailAnimation = (configuration.smallestScreenWidthDp < 600); - if (useAlternateThumbnailAnimation) { - a = createAlternateThumbnailEnterExitAnimationLocked( - getThumbnailTransitionState(enter), appWidth, appHeight, orientation, - transit, containingFrame, contentInsets); - } else { - a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter), - appWidth, appHeight, transit); - } + a = createAlternateThumbnailEnterExitAnimationLocked( + getThumbnailTransitionState(enter), appWidth, appHeight, orientation, + transit, containingFrame, contentInsets, isFullScreen); if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { String animName = mNextAppTransitionScaleUp ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN"; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b61ba5c..63a4f52 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -289,6 +289,11 @@ public class WindowManagerService extends IWindowManager.Stub private static final int MAX_SCREENSHOT_RETRIES = 3; + // The flag describing a full screen app window (where the app takes care of drawing under the + // SystemUI bars) + private static final int SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN = + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + final private KeyguardDisableHandler mKeyguardDisableHandler; final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -3193,8 +3198,11 @@ public class WindowManagerService extends IWindowManager.Stub } } + boolean isFullScreen = + ((win.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) + == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN); Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height, - mCurConfiguration.orientation, containingFrame, contentInsets, mCurConfiguration); + mCurConfiguration.orientation, containingFrame, contentInsets, isFullScreen); if (a != null) { if (DEBUG_ANIM) { RuntimeException e = null; @@ -8677,7 +8685,7 @@ public class WindowManagerService extends IWindowManager.Stub wtoken.deferClearAllDrawn = false; } - boolean useAlternateThumbnailAnimation = (mCurConfiguration.smallestScreenWidthDp < 600); + boolean useAlternateThumbnailAnimation = true; AppWindowAnimator appAnimator = topOpeningApp == null ? null : topOpeningApp.mAppAnimator; Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 3c9d53e..1e79dcb 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -46,6 +46,7 @@ import android.view.MagnificationSpec; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; import android.view.SurfaceSession; +import android.view.View; import android.view.WindowManager; import android.view.WindowManagerPolicy; import android.view.WindowManager.LayoutParams; @@ -151,6 +152,10 @@ class WindowStateAnimator { static final int READY_TO_SHOW = 3; /** Set when the window has been shown in the screen the first time. */ static final int HAS_DRAWN = 4; + + private static final int SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN = + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + static String drawStateToString(int state) { switch (state) { case NO_SURFACE: return "NO_SURFACE"; @@ -1176,9 +1181,15 @@ class WindowStateAnimator { // content insets as well. int offsetTop = Math.max(w.mSystemDecorRect.top, w.mContentInsets.top); mTmpClipRect.set(w.mSystemDecorRect); - mTmpClipRect.offset(0, -offsetTop); - mTmpClipRect.intersect(mClipRect); - mTmpClipRect.offset(0, offsetTop); + // Don't apply the workaround to apps explicitly requesting fullscreen layout. + if ((w.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) + == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) { + mTmpClipRect.intersect(mClipRect); + } else { + mTmpClipRect.offset(0, -offsetTop); + mTmpClipRect.intersect(mClipRect); + mTmpClipRect.offset(0, offsetTop); + } clipRect = mTmpClipRect; } |