summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/AlarmManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/AlarmManagerService.java')
-rw-r--r--services/java/com/android/server/AlarmManagerService.java232
1 files changed, 193 insertions, 39 deletions
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 440f8e1..cbd00f3 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -22,6 +22,7 @@ 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;
@@ -38,6 +39,7 @@ import android.os.UserHandle;
import android.os.WorkSource;
import android.text.TextUtils;
import android.text.format.Time;
+import android.util.Pair;
import android.util.Slog;
import android.util.TimeUtils;
@@ -45,16 +47,18 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.Map;
import java.util.TimeZone;
+import com.android.internal.util.LocalLog;
+
class AlarmManagerService extends IAlarmManager.Stub {
// The threshold for how long an alarm can be late before we print a
// warning message. The time duration is in milliseconds.
@@ -79,7 +83,9 @@ class AlarmManagerService extends IAlarmManager.Stub {
= new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
private final Context mContext;
-
+
+ private final LocalLog mLog = new LocalLog(TAG);
+
private Object mLock = new Object();
private final ArrayList<Alarm> mRtcWakeupAlarms = new ArrayList<Alarm>();
@@ -91,7 +97,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
private int mDescriptor;
private int mBroadcastRefCount = 0;
private PowerManager.WakeLock mWakeLock;
- private LinkedList<PendingIntent> mInFlight = new LinkedList<PendingIntent>();
+ private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
private final AlarmThread mWaitThread = new AlarmThread();
private final AlarmHandler mHandler = new AlarmHandler();
private ClockReceiver mClockReceiver;
@@ -99,18 +105,59 @@ class AlarmManagerService extends IAlarmManager.Stub {
private final ResultReceiver mResultReceiver = new ResultReceiver();
private final PendingIntent mTimeTickSender;
private final PendingIntent mDateChangeSender;
-
+
+ private static final class InFlight extends Intent {
+ final PendingIntent mPendingIntent;
+ final Pair<String, ComponentName> mTarget;
+ final BroadcastStats mBroadcastStats;
+ final FilterStats mFilterStats;
+
+ InFlight(AlarmManagerService service, PendingIntent pendingIntent) {
+ mPendingIntent = pendingIntent;
+ Intent intent = pendingIntent.getIntent();
+ mTarget = intent != null
+ ? new Pair<String, ComponentName>(intent.getAction(), intent.getComponent())
+ : null;
+ mBroadcastStats = service.getStatsLocked(pendingIntent);
+ FilterStats fs = mBroadcastStats.filterStats.get(mTarget);
+ if (fs == null) {
+ fs = new FilterStats(mBroadcastStats, mTarget);
+ mBroadcastStats.filterStats.put(mTarget, fs);
+ }
+ mFilterStats = fs;
+ }
+ }
+
private static final class FilterStats {
+ final BroadcastStats mBroadcastStats;
+ final Pair<String, ComponentName> mTarget;
+
+ long aggregateTime;
int count;
+ int numWakeup;
+ long startTime;
+ int nesting;
+
+ FilterStats(BroadcastStats broadcastStats, Pair<String, ComponentName> target) {
+ mBroadcastStats = broadcastStats;
+ mTarget = target;
+ }
}
private static final class BroadcastStats {
+ final String mPackageName;
+
long aggregateTime;
+ int count;
int numWakeup;
long startTime;
int nesting;
- HashMap<Intent.FilterComparison, FilterStats> filterStats
- = new HashMap<Intent.FilterComparison, FilterStats>();
+ final HashMap<Pair<String, ComponentName>, FilterStats> filterStats
+ = new HashMap<Pair<String, ComponentName>, FilterStats>();
+
+ BroadcastStats(String packageName) {
+ mPackageName = packageName;
+ }
}
private final HashMap<String, BroadcastStats> mBroadcastStats
@@ -496,24 +543,104 @@ class AlarmManagerService extends IAlarmManager.Stub {
dumpAlarmList(pw, mElapsedRealtimeAlarms, " ", "ELAPSED", now);
}
}
-
- pw.println(" ");
+
+ pw.println();
pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
-
+ pw.println();
+
+ if (mLog.dump(pw, " Recent problems", " ")) {
+ pw.println();
+ }
+
+ final FilterStats[] topFilters = new FilterStats[10];
+ final Comparator<FilterStats> comparator = new Comparator<FilterStats>() {
+ @Override
+ public int compare(FilterStats lhs, FilterStats rhs) {
+ if (lhs.aggregateTime < rhs.aggregateTime) {
+ return 1;
+ } else if (lhs.aggregateTime > rhs.aggregateTime) {
+ return -1;
+ }
+ return 0;
+ }
+ };
+ int len = 0;
+ for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
+ BroadcastStats bs = be.getValue();
+ for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
+ : bs.filterStats.entrySet()) {
+ FilterStats fs = fe.getValue();
+ int pos = len > 0
+ ? Arrays.binarySearch(topFilters, 0, len, fs, comparator) : 0;
+ if (pos < 0) {
+ pos = -pos - 1;
+ }
+ if (pos < topFilters.length) {
+ int copylen = topFilters.length - pos - 1;
+ if (copylen > 0) {
+ System.arraycopy(topFilters, pos, topFilters, pos+1, copylen);
+ }
+ topFilters[pos] = fs;
+ if (len < topFilters.length) {
+ len++;
+ }
+ }
+ }
+ }
+ if (len > 0) {
+ pw.println(" Top Alarms:");
+ for (int i=0; i<len; i++) {
+ FilterStats fs = topFilters[i];
+ pw.print(" ");
+ if (fs.nesting > 0) pw.print("*ACTIVE* ");
+ TimeUtils.formatDuration(fs.aggregateTime, pw);
+ pw.print(" running, "); pw.print(fs.numWakeup);
+ pw.print(" wakeups, "); pw.print(fs.count);
+ pw.print(" alarms: "); 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.println();
+ }
+ }
+
pw.println(" ");
pw.println(" Alarm Stats:");
+ final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
for (Map.Entry<String, BroadcastStats> be : mBroadcastStats.entrySet()) {
BroadcastStats bs = be.getValue();
- pw.print(" "); pw.println(be.getKey());
- pw.print(" "); pw.print(bs.aggregateTime);
- pw.print("ms running, "); pw.print(bs.numWakeup);
- pw.println(" wakeups");
- for (Map.Entry<Intent.FilterComparison, FilterStats> fe
+ pw.print(" ");
+ if (bs.nesting > 0) pw.print("*ACTIVE* ");
+ pw.print(be.getKey());
+ pw.print(" "); TimeUtils.formatDuration(bs.aggregateTime, pw);
+ pw.print(" running, "); pw.print(bs.numWakeup);
+ pw.println(" wakeups:");
+ tmpFilters.clear();
+ for (Map.Entry<Pair<String, ComponentName>, FilterStats> fe
: bs.filterStats.entrySet()) {
- pw.print(" "); pw.print(fe.getValue().count);
- pw.print(" alarms: ");
- pw.println(fe.getKey().getIntent().toShortString(
- false, true, false, true));
+ tmpFilters.add(fe.getValue());
+ }
+ Collections.sort(tmpFilters, comparator);
+ for (int i=0; i<tmpFilters.size(); i++) {
+ FilterStats fs = tmpFilters.get(i);
+ pw.print(" ");
+ if (fs.nesting > 0) pw.print("*ACTIVE* ");
+ 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.println();
}
}
}
@@ -708,18 +835,31 @@ class AlarmManagerService extends IAlarmManager.Stub {
setWakelockWorkSource(alarm.operation);
mWakeLock.acquire();
}
- mInFlight.add(alarm.operation);
+ final InFlight inflight = new InFlight(AlarmManagerService.this,
+ alarm.operation);
+ mInFlight.add(inflight);
mBroadcastRefCount++;
-
- BroadcastStats bs = getStatsLocked(alarm.operation);
+
+ 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 == AlarmManager.ELAPSED_REALTIME_WAKEUP
|| alarm.type == AlarmManager.RTC_WAKEUP) {
bs.numWakeup++;
+ fs.numWakeup++;
ActivityManagerNative.noteWakeupAlarm(
alarm.operation);
}
@@ -908,44 +1048,58 @@ class AlarmManagerService extends IAlarmManager.Stub {
String pkg = pi.getTargetPackage();
BroadcastStats bs = mBroadcastStats.get(pkg);
if (bs == null) {
- bs = new BroadcastStats();
+ bs = new BroadcastStats(pkg);
mBroadcastStats.put(pkg, bs);
}
return bs;
}
-
+
class ResultReceiver implements PendingIntent.OnFinished {
public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
String resultData, Bundle resultExtras) {
synchronized (mLock) {
- BroadcastStats bs = getStatsLocked(pi);
- if (bs != null) {
+ InFlight inflight = null;
+ for (int i=0; i<mInFlight.size(); i++) {
+ if (mInFlight.get(i).mPendingIntent == pi) {
+ inflight = mInFlight.remove(i);
+ break;
+ }
+ }
+ if (inflight != null) {
+ final long nowELAPSED = SystemClock.elapsedRealtime();
+ BroadcastStats bs = inflight.mBroadcastStats;
bs.nesting--;
if (bs.nesting <= 0) {
bs.nesting = 0;
- bs.aggregateTime += SystemClock.elapsedRealtime()
- - bs.startTime;
- Intent.FilterComparison fc = new Intent.FilterComparison(intent);
- FilterStats fs = bs.filterStats.get(fc);
- if (fs == null) {
- fs = new FilterStats();
- bs.filterStats.put(fc, fs);
- }
- fs.count++;
+ bs.aggregateTime += nowELAPSED - bs.startTime;
+ }
+ FilterStats fs = inflight.mFilterStats;
+ fs.nesting--;
+ if (fs.nesting <= 0) {
+ fs.nesting = 0;
+ fs.aggregateTime += nowELAPSED - fs.startTime;
}
+ } else {
+ mLog.w("No in-flight alarm for " + pi + " " + intent);
}
- mInFlight.removeFirst();
mBroadcastRefCount--;
if (mBroadcastRefCount == 0) {
mWakeLock.release();
+ if (mInFlight.size() > 0) {
+ mLog.w("Finished all broadcasts with " + mInFlight.size()
+ + " remaining inflights");
+ for (int i=0; i<mInFlight.size(); i++) {
+ mLog.w(" Remaining #" + i + ": " + mInFlight.get(i));
+ }
+ mInFlight.clear();
+ }
} else {
// the next of our alarms is now in flight. reattribute the wakelock.
- final PendingIntent nowInFlight = mInFlight.peekFirst();
- if (nowInFlight != null) {
- setWakelockWorkSource(nowInFlight);
+ if (mInFlight.size() > 0) {
+ setWakelockWorkSource(mInFlight.get(0).mPendingIntent);
} else {
// should never happen
- Slog.e(TAG, "Alarm wakelock still held but sent queue empty");
+ mLog.w("Alarm wakelock still held but sent queue empty");
mWakeLock.setWorkSource(null);
}
}