incidentd: Adding proto dump for AlarmManager.
Test: flash device and check incident.proto output.
Bug: 65750801
Change-Id: If1e42c70908a0b11358cf48766c028e37c0329ae
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 2813e8b..55f9e28 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -33,6 +33,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import libcore.util.ZoneInfoDB;
@@ -48,7 +49,7 @@
* if it is not already running. Registered alarms are retained while the
* device is asleep (and can optionally wake the device up if they go off
* during that time), but will be cleared if it is turned off and rebooted.
- *
+ *
* <p>The Alarm Manager holds a CPU wake lock as long as the alarm receiver's
* onReceive() method is executing. This guarantees that the phone will not sleep
* until you have finished handling the broadcast. Once onReceive() returns, the
@@ -296,7 +297,7 @@
* {@link Intent#EXTRA_ALARM_COUNT Intent.EXTRA_ALARM_COUNT} that indicates
* how many past alarm events have been accumulated into this intent
* broadcast. Recurring alarms that have gone undelivered because the
- * phone was asleep may have a count greater than one when delivered.
+ * phone was asleep may have a count greater than one when delivered.
*
* <div class="note">
* <p>
@@ -396,10 +397,10 @@
* set a recurring alarm for the top of every hour but the phone was asleep
* from 7:45 until 8:45, an alarm will be sent as soon as the phone awakens,
* then the next alarm will be sent at 9:00.
- *
- * <p>If your application wants to allow the delivery times to drift in
+ *
+ * <p>If your application wants to allow the delivery times to drift in
* order to guarantee that at least a certain time interval always elapses
- * between alarms, then the approach to take is to use one-time alarms,
+ * between alarms, then the approach to take is to use one-time alarms,
* scheduling the next one yourself when handling each alarm delivery.
*
* <p class="note">
@@ -1056,7 +1057,7 @@
/**
* Creates a new alarm clock description.
*
- * @param triggerTime time at which the underlying alarm is triggered in wall time
+ * @param triggerTime time at which the underlying alarm is triggered in wall time
* milliseconds since the epoch
* @param showIntent an intent that can be used to show or edit details of
* the alarm clock.
@@ -1089,7 +1090,7 @@
* Returns an intent that can be used to show or edit details of the alarm clock in
* the application that scheduled it.
*
- * <p class="note">Beware that any application can retrieve and send this intent,
+ * <p class="note">Beware that any application can retrieve and send this intent,
* potentially with additional fields filled in. See
* {@link PendingIntent#send(android.content.Context, int, android.content.Intent)
* PendingIntent.send()} and {@link android.content.Intent#fillIn Intent.fillIn()}
@@ -1121,5 +1122,13 @@
return new AlarmClockInfo[size];
}
};
+
+ /** @hide */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(AlarmClockInfoProto.TRIGGER_TIME_MS, mTriggerTime);
+ mShowIntent.writeToProto(proto, AlarmClockInfoProto.SHOW_INTENT);
+ proto.end(token);
+ }
}
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index a25c226..baeabc3 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -33,6 +33,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AndroidException;
+import android.util.proto.ProtoOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1081,7 +1082,16 @@
sb.append('}');
return sb.toString();
}
-
+
+ /** @hide */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ if (mTarget != null) {
+ proto.write(PendingIntentProto.TARGET, mTarget.asBinder().toString());
+ }
+ proto.end(token);
+ }
+
public int describeContents() {
return 0;
}
diff --git a/core/java/com/android/internal/util/LocalLog.java b/core/java/com/android/internal/util/LocalLog.java
index f0e6171..8edb739 100644
--- a/core/java/com/android/internal/util/LocalLog.java
+++ b/core/java/com/android/internal/util/LocalLog.java
@@ -20,6 +20,7 @@
import java.util.ArrayList;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
/**
* Helper class for logging serious issues, which also keeps a small
@@ -63,4 +64,16 @@
return true;
}
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ synchronized (mLines) {
+ for (int i = 0; i < mLines.size(); ++i) {
+ proto.write(LocalLogProto.LINES, mLines.get(i));
+ }
+ }
+
+ proto.end(token);
+ }
}
diff --git a/core/proto/android/app/alarmmanager.proto b/core/proto/android/app/alarmmanager.proto
new file mode 100644
index 0000000..789e3d6
--- /dev/null
+++ b/core/proto/android/app/alarmmanager.proto
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/app/pendingintent.proto";
+
+option java_multiple_files = true;
+
+package android.app;
+
+/**
+ * An android.app.AlarmManager object.
+ */
+message AlarmManagerProto {
+ enum AlarmType {
+ // Alarm time in System.currentTimeMillis() (wall clock time in UTC), which
+ // will wake up the device when it goes off.
+ RTC_WAKEUP = 0;
+ // Alarm time in System.currentTimeMillis() (wall clock time in UTC). This
+ // alarm does not wake the device up; if it goes off while the device is
+ // asleep, it will not be delivered until the next time the device wakes up.
+ RTC = 1;
+ // Alarm time in SystemClock.elapsedRealtime() (time since boot, including
+ // sleep), which will wake up the device when it goes off.
+ ELAPSED_REALTIME_WAKEUP = 2;
+ // Alarm time in SystemClock.elapsedRealtime() (time since boot, including
+ // sleep). This alarm does not wake the device up; if it goes off while the
+ // device is asleep, it will not be delivered until the next time the device
+ // wakes up.
+ ELAPSED_REALTIME = 3;
+ }
+}
+
+// An android.app.AlarmManager.AlarmClockInfo object.
+message AlarmClockInfoProto {
+ // This value is UTC wall clock time in milliseconds, as returned by
+ // System#currentTimeMillis() for example.
+ optional int64 trigger_time_ms = 1;
+ optional android.app.PendingIntentProto show_intent = 2;
+}
diff --git a/core/proto/android/app/pendingintent.proto b/core/proto/android/app/pendingintent.proto
new file mode 100644
index 0000000..b562c0b
--- /dev/null
+++ b/core/proto/android/app/pendingintent.proto
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+option java_multiple_files = true;
+
+package android.app;
+
+/**
+ * An android.app.PendingIntent object.
+ */
+message PendingIntentProto {
+ optional string target = 1;
+}
diff --git a/core/proto/android/internal/locallog.proto b/core/proto/android/internal/locallog.proto
new file mode 100644
index 0000000..51f6c1c
--- /dev/null
+++ b/core/proto/android/internal/locallog.proto
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package com.android.internal.util;
+
+option java_multiple_files = true;
+
+message LocalLogProto {
+ repeated string lines = 1;
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 5a5454e..0887f03 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -32,6 +32,7 @@
import "frameworks/base/core/proto/android/service/print.proto";
import "frameworks/base/core/proto/android/service/procstats.proto";
import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
+import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/os/incidentheader.proto";
import "frameworks/base/core/proto/android/os/kernelwake.proto";
@@ -125,4 +126,9 @@
optional com.android.server.am.proto.ServiceProto amservices = 3014;
optional com.android.server.am.proto.ProcessProto amprocesses = 3015;
+
+ optional com.android.server.AlarmManagerServiceProto alarm = 3016 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "alarm --proto"
+ ];
}
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
new file mode 100644
index 0000000..d2cd190
--- /dev/null
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/app/alarmmanager.proto";
+import "frameworks/base/core/proto/android/app/pendingintent.proto";
+import "frameworks/base/core/proto/android/internal/locallog.proto";
+import "frameworks/base/core/proto/android/os/worksource.proto";
+
+package com.android.server;
+
+option java_multiple_files = true;
+
+message AlarmManagerServiceProto {
+ optional int64 current_time = 1;
+ optional int64 elapsed_realtime = 2;
+ optional int64 last_time_change_clock_time = 3;
+ optional int64 last_time_change_realtime = 4;
+ // Current settings
+ optional ConstantsProto settings = 5;
+ // UIDs currently in the foreground.
+ repeated int32 foreground_uids = 6;
+ // Packages forced into app standby.
+ repeated string forced_app_standby_packages = 7;
+
+ optional bool is_interactive = 8;
+ // Only valid if is_interactive is false.
+ optional int64 time_since_non_interactive_ms = 9;
+ // Only valid if is_interactive is false.
+ optional int64 max_wakeup_delay_ms = 10;
+ // Only valid if is_interactive is false.
+ optional int64 time_since_last_dispatch_ms = 11;
+ // Only valid if is_interactive is false.
+ optional int64 time_until_next_non_wakeup_delivery_ms = 12;
+
+ optional int64 time_until_next_non_wakeup_alarm_ms = 13;
+ optional int64 time_until_next_wakeup_ms = 14;
+ optional int64 time_since_last_wakeup_ms = 15;
+ // Time since the last wakeup was set.
+ optional int64 time_since_last_wakeup_set_ms = 16;
+ optional int64 time_change_event_count = 17;
+ // The current set of user whitelisted apps for device idle mode, meaning
+ // these are allowed to freely schedule alarms. These are app IDs, not UIDs.
+ repeated int32 device_idle_user_whitelist_app_ids = 18;
+
+ repeated AlarmClockMetadataProto next_alarm_clock_metadata = 19;
+
+ repeated BatchProto pending_alarm_batches = 20;
+
+ // List of alarms per uid deferred due to user applied background restrictions
+ // on the source app.
+ repeated AlarmProto pending_user_blocked_background_alarms = 21;
+
+ // When idling mode will end. Will be empty if the device is not currently
+ // idling.
+ optional AlarmProto pending_idle_until = 22;
+
+ // Any alarms that we don't want to run during idle mode. Will be empty if the
+ // device is not currently idling.
+ repeated AlarmProto pending_while_idle_alarms = 23;
+
+ // This is a special alarm that will put the system into idle until it goes
+ // off. The caller has given the time they want this to happen at.
+ optional AlarmProto next_wake_from_idle = 24;
+
+ repeated AlarmProto past_due_non_wakeup_alarms = 25;
+
+ // Number of delayed alarms.
+ optional int32 delayed_alarm_count = 26;
+ // The total amount of time alarms had been delayed. Overlapping alarms are
+ // only counted once (ie. If two alarms were meant to trigger at the same time
+ // but were delayed by 5 seconds, the total time would be 5 seconds).
+ optional int64 total_delay_time_ms = 27;
+ optional int64 max_delay_duration_ms = 28;
+ optional int64 max_non_interactive_duration_ms = 29;
+
+ optional int32 broadcast_ref_count = 30;
+ // Canonical count of (operation.send() - onSendFinished()) and listener
+ // send/complete/timeout invocations.
+ optional int32 pending_intent_send_count = 31;
+ optional int32 pending_intent_finish_count = 32;
+ optional int32 listener_send_count = 33;
+ optional int32 listener_finish_count = 34;
+
+ repeated InFlightProto outstanding_deliveries = 35;
+
+ // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling. It
+ // should be either CosntantsProto.allow_while_idle_short_duration_ms or
+ // ConstantsProto.allow_while_idle_long_duration_ms.
+ optional int64 allow_while_idle_min_duration_ms = 36;
+
+ message LastAllowWhileIdleDispatch {
+ optional int32 uid = 1;
+ // In the 'elapsed' timebase.
+ optional int64 time_ms = 2;
+ }
+ // For each uid, this is the last time we dispatched an "allow while idle"
+ // alarm, used to determine the earliest we can dispatch the next such alarm.
+ repeated LastAllowWhileIdleDispatch last_allow_while_idle_dispatch_times = 37;
+
+ optional com.android.internal.util.LocalLogProto recent_problems = 38;
+
+ message TopAlarm {
+ optional int32 uid = 1;
+ optional string package_name = 2;
+ optional FilterStatsProto filter = 3;
+ }
+ repeated TopAlarm top_alarms = 39;
+
+ message AlarmStat {
+ optional BroadcastStatsProto broadcast = 1;
+ repeated FilterStatsProto filters = 2;
+ }
+ repeated AlarmStat alarm_stats = 40;
+
+ repeated IdleDispatchEntryProto allow_while_idle_dispatches = 41;
+ repeated WakeupEventProto recent_wakeup_history = 42;
+}
+
+// This is a soft wrapper for alarm clock information. It is not representative
+// of an android.app.AlarmManager.AlarmClockInfo object.
+message AlarmClockMetadataProto {
+ optional int32 user = 1;
+ optional bool is_pending_send = 2;
+ // This value is UTC wall clock time in milliseconds, as returned by
+ // System#currentTimeMillis() for example.
+ optional int64 trigger_time_ms = 3;
+}
+
+// A com.android.server.AlarmManagerService.Alarm object.
+message AlarmProto {
+ optional string tag = 1;
+ optional .android.app.AlarmManagerProto.AlarmType type = 2;
+ // How long until the alarm goes off, in the 'elapsed' timebase.
+ optional int64 when_elapsed_ms = 3;
+ optional int64 window_length_ms = 4;
+ optional int64 repeat_interval_ms = 5;
+ optional int32 count = 6;
+ optional int32 flags = 7;
+ optional .android.app.AlarmClockInfoProto alarm_clock = 8;
+ optional .android.app.PendingIntentProto operation = 9;
+ optional string listener = 10;
+}
+
+// A com.android.server.AlarmManagerService.Batch object.
+message BatchProto {
+ // Start time in terms of elapsed realtime.
+ optional int64 start_realtime = 1;
+ // End time in terms of elapsed realtime.
+ optional int64 end_realtime = 2;
+ optional int32 flags = 3;
+ repeated AlarmProto alarms = 4;
+}
+
+// A com.android.server.AlarmManagerService.BroadcastStats object.
+message BroadcastStatsProto {
+ optional int32 uid = 1;
+ optional string package_name = 2;
+ // The total amount of time this broadcast was in flight.
+ optional int64 total_flight_duration_ms = 3;
+ optional int32 count = 4;
+ optional int32 wakeup_count = 5;
+ // The last time this first became active (when nesting changed from 0 to 1)
+ // in terms of elapsed realtime.
+ optional int64 start_time_realtime = 6;
+ // The broadcast is active if nesting > 0.
+ optional int32 nesting = 7;
+}
+
+// A com.android.server.AlarmManagerService.Constants object.
+message ConstantsProto {
+ // Minimum futurity of a new alarm.
+ optional int64 min_futurity_duration_ms = 1;
+ // Minimum alarm recurrence interval.
+ optional int64 min_interval_duration_ms = 2;
+ // Direct alarm listener callback timeout.
+ optional int64 listener_timeout_duration_ms = 3;
+ // Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle.
+ optional int64 allow_while_idle_short_duration_ms = 4;
+ // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling.
+ optional int64 allow_while_idle_long_duration_ms = 5;
+ // BroadcastOptions.setTemporaryAppWhitelistDuration() to use for FLAG_ALLOW_WHILE_IDLE.
+ optional int64 allow_while_idle_whitelist_duration_ms = 6;
+}
+
+// A com.android.server.AlarmManagerService.FilterStats object.
+message FilterStatsProto {
+ optional string tag = 1;
+ // The last time this filter when in flight, in terms of elapsed realtime.
+ optional int64 last_flight_time_realtime = 2;
+ // The total amount of time this filter was in flight.
+ optional int64 total_flight_duration_ms = 3;
+ optional int32 count = 4;
+ optional int32 wakeup_count = 5;
+ // The last time this first became active (when nesting changed from 0 to 1)
+ // in terms of elapsed realtime.
+ optional int64 start_time_realtime = 6;
+ // The filter is active if nesting > 0.
+ optional int32 nesting = 7;
+}
+
+// A com.android.server.AlarmManagerService.IdleDispatchEntry object.
+message IdleDispatchEntryProto {
+ optional int32 uid = 1;
+ optional string pkg = 2;
+ optional string tag = 3;
+ optional string op = 4;
+ // Time when this entry was created, in terms of elapsed realtime.
+ optional int64 entry_creation_realtime = 5;
+ // For a RESCHEDULED op, this is the last time we dispatched an "allow while
+ // idle" alarm for the UID. For a SET op, this is when the alarm was
+ // triggered. Times are in the 'elapsed' timebase.
+ optional int64 arg_realtime = 6;
+}
+
+// A com.android.server.AlarmManagerService.InFlight object.
+message InFlightProto {
+ optional int32 uid = 1;
+ optional string tag = 2;
+ optional int64 when_elapsed_ms = 3;
+ optional .android.app.AlarmManagerProto.AlarmType alarm_type = 4;
+ optional .android.app.PendingIntentProto pending_intent = 5;
+ optional BroadcastStatsProto broadcast_stats = 6;
+ optional FilterStatsProto filter_stats = 7;
+ optional .android.os.WorkSourceProto work_source = 8;
+}
+
+// A com.android.server.AlarmManagerService.WakeupEvent object.
+message WakeupEventProto {
+ optional int32 uid = 1;
+ optional string action = 2;
+ optional int64 when = 3;
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4c08f62..3904fc9 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -63,6 +63,7 @@
import android.util.SparseBooleanArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
@@ -190,7 +191,8 @@
/**
* For each uid, this is the last time we dispatched an "allow while idle" alarm,
- * used to determine the earliest we can dispatch the next such alarm.
+ * used to determine the earliest we can dispatch the next such alarm. Times are in the
+ * 'elapsed' timebase.
*/
final SparseLongArray mLastAllowWhileIdleDispatch = new SparseLongArray();
@@ -355,6 +357,22 @@
TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
pw.println();
}
+
+ void dumpProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ proto.write(ConstantsProto.MIN_FUTURITY_DURATION_MS, MIN_FUTURITY);
+ proto.write(ConstantsProto.MIN_INTERVAL_DURATION_MS, MIN_INTERVAL);
+ proto.write(ConstantsProto.LISTENER_TIMEOUT_DURATION_MS, LISTENER_TIMEOUT);
+ proto.write(ConstantsProto.ALLOW_WHILE_IDLE_SHORT_DURATION_MS,
+ ALLOW_WHILE_IDLE_SHORT_TIME);
+ proto.write(ConstantsProto.ALLOW_WHILE_IDLE_LONG_DURATION_MS,
+ ALLOW_WHILE_IDLE_LONG_TIME);
+ proto.write(ConstantsProto.ALLOW_WHILE_IDLE_WHITELIST_DURATION_MS,
+ ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+
+ proto.end(token);
+ }
}
final Constants mConstants;
@@ -632,6 +650,20 @@
b.append('}');
return b.toString();
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId, long nowElapsed,
+ long nowRTC) {
+ final long token = proto.start(fieldId);
+
+ proto.write(BatchProto.START_REALTIME, start);
+ proto.write(BatchProto.END_REALTIME, end);
+ proto.write(BatchProto.FLAGS, flags);
+ for (Alarm a : alarms) {
+ a.writeToProto(proto, BatchProto.ALARMS, nowElapsed, nowRTC);
+ }
+
+ proto.end(token);
+ }
}
static class BatchTimeOrder implements Comparator<Batch> {
@@ -1007,6 +1039,29 @@
+ ", alarmType=" + mAlarmType
+ "}";
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ proto.write(InFlightProto.UID, mUid);
+ proto.write(InFlightProto.TAG, mTag);
+ proto.write(InFlightProto.WHEN_ELAPSED_MS, mWhenElapsed);
+ proto.write(InFlightProto.ALARM_TYPE, mAlarmType);
+ if (mPendingIntent != null) {
+ mPendingIntent.writeToProto(proto, InFlightProto.PENDING_INTENT);
+ }
+ if (mBroadcastStats != null) {
+ mBroadcastStats.writeToProto(proto, InFlightProto.BROADCAST_STATS);
+ }
+ if (mFilterStats != null) {
+ mFilterStats.writeToProto(proto, InFlightProto.FILTER_STATS);
+ }
+ if (mWorkSource != null) {
+ mWorkSource.writeToProto(proto, InFlightProto.WORK_SOURCE);
+ }
+
+ proto.end(token);
+ }
}
static final class FilterStats {
@@ -1037,6 +1092,20 @@
+ ", nesting=" + nesting
+ "}";
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ proto.write(FilterStatsProto.TAG, mTag);
+ proto.write(FilterStatsProto.LAST_FLIGHT_TIME_REALTIME, lastTime);
+ proto.write(FilterStatsProto.TOTAL_FLIGHT_DURATION_MS, aggregateTime);
+ proto.write(FilterStatsProto.COUNT, count);
+ proto.write(FilterStatsProto.WAKEUP_COUNT, numWakeup);
+ proto.write(FilterStatsProto.START_TIME_REALTIME, startTime);
+ proto.write(FilterStatsProto.NESTING, nesting);
+
+ proto.end(token);
+ }
}
static final class BroadcastStats {
@@ -1067,6 +1136,20 @@
+ ", nesting=" + nesting
+ "}";
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ proto.write(BroadcastStatsProto.UID, mUid);
+ proto.write(BroadcastStatsProto.PACKAGE_NAME, mPackageName);
+ proto.write(BroadcastStatsProto.TOTAL_FLIGHT_DURATION_MS, aggregateTime);
+ proto.write(BroadcastStatsProto.COUNT, count);
+ proto.write(BroadcastStatsProto.WAKEUP_COUNT, numWakeup);
+ proto.write(BroadcastStatsProto.START_TIME_REALTIME, startTime);
+ proto.write(BroadcastStatsProto.NESTING, nesting);
+
+ proto.end(token);
+ }
}
final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
@@ -1128,14 +1211,14 @@
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
-
+
// now that we have initied the driver schedule the alarm
mClockReceiver = new ClockReceiver();
mClockReceiver.scheduleTimeTickEvent();
mClockReceiver.scheduleDateChangedEvent();
mInteractiveStateReceiver = new InteractiveStateReceiver();
mUninstallReceiver = new UninstallReceiver();
-
+
if (mNativeData != 0) {
AlarmThread waitThread = new AlarmThread();
waitThread.start();
@@ -1568,7 +1651,12 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
- dumpImpl(pw);
+
+ if (args.length > 0 && "--proto".equals(args[0])) {
+ dumpProto(fd);
+ } else {
+ dumpImpl(pw);
+ }
}
};
@@ -1681,7 +1769,7 @@
pw.print(" Idling until: ");
if (mPendingIdleUntil != null) {
pw.println(mPendingIdleUntil);
- mPendingIdleUntil.dump(pw, " ", nowRTC, nowELAPSED, sdf);
+ mPendingIdleUntil.dump(pw, " ", nowELAPSED, nowRTC, sdf);
} else {
pw.println("null");
}
@@ -1691,7 +1779,7 @@
if (mNextWakeFromIdle != null) {
pw.println();
pw.print(" Next wake from idle: "); pw.println(mNextWakeFromIdle);
- mNextWakeFromIdle.dump(pw, " ", nowRTC, nowELAPSED, sdf);
+ mNextWakeFromIdle.dump(pw, " ", nowELAPSED, nowRTC, sdf);
}
pw.println();
@@ -1760,6 +1848,7 @@
}
};
int len = 0;
+ // Get the top 10 FilterStats, ordered by aggregateTime.
for (int iu=0; iu<mBroadcastStats.size(); iu++) {
ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
for (int ip=0; ip<uidStats.size(); ip++) {
@@ -1886,6 +1975,244 @@
}
}
+ void dumpProto(FileDescriptor fd) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+ synchronized (mLock) {
+ final long nowRTC = System.currentTimeMillis();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ proto.write(AlarmManagerServiceProto.CURRENT_TIME, nowRTC);
+ proto.write(AlarmManagerServiceProto.ELAPSED_REALTIME, nowElapsed);
+ proto.write(AlarmManagerServiceProto.LAST_TIME_CHANGE_CLOCK_TIME,
+ mLastTimeChangeClockTime);
+ proto.write(AlarmManagerServiceProto.LAST_TIME_CHANGE_REALTIME,
+ mLastTimeChangeRealtime);
+
+ mConstants.dumpProto(proto, AlarmManagerServiceProto.SETTINGS);
+
+ final int foregroundUidsSize = mForegroundUids.size();
+ for (int i = 0; i < foregroundUidsSize; i++) {
+ if (mForegroundUids.valueAt(i)) {
+ proto.write(AlarmManagerServiceProto.FOREGROUND_UIDS, mForegroundUids.keyAt(i));
+ }
+ }
+ for (String pkg : mForcedAppStandbyPackages) {
+ proto.write(AlarmManagerServiceProto.FORCED_APP_STANDBY_PACKAGES, pkg);
+ }
+
+ proto.write(AlarmManagerServiceProto.IS_INTERACTIVE, mInteractive);
+ if (!mInteractive) {
+ // Durations
+ proto.write(AlarmManagerServiceProto.TIME_SINCE_NON_INTERACTIVE_MS,
+ nowElapsed - mNonInteractiveStartTime);
+ proto.write(AlarmManagerServiceProto.MAX_WAKEUP_DELAY_MS,
+ currentNonWakeupFuzzLocked(nowElapsed));
+ proto.write(AlarmManagerServiceProto.TIME_SINCE_LAST_DISPATCH_MS,
+ nowElapsed - mLastAlarmDeliveryTime);
+ proto.write(AlarmManagerServiceProto.TIME_UNTIL_NEXT_NON_WAKEUP_DELIVERY_MS,
+ nowElapsed - mNextNonWakeupDeliveryTime);
+ }
+
+ proto.write(AlarmManagerServiceProto.TIME_UNTIL_NEXT_NON_WAKEUP_ALARM_MS,
+ mNextNonWakeup - nowElapsed);
+ proto.write(AlarmManagerServiceProto.TIME_UNTIL_NEXT_WAKEUP_MS,
+ mNextWakeup - nowElapsed);
+ proto.write(AlarmManagerServiceProto.TIME_SINCE_LAST_WAKEUP_MS,
+ nowElapsed - mLastWakeup);
+ proto.write(AlarmManagerServiceProto.TIME_SINCE_LAST_WAKEUP_SET_MS,
+ nowElapsed - mLastWakeupSet);
+ proto.write(AlarmManagerServiceProto.TIME_CHANGE_EVENT_COUNT, mNumTimeChanged);
+ for (int i : mDeviceIdleUserWhitelist) {
+ proto.write(AlarmManagerServiceProto.DEVICE_IDLE_USER_WHITELIST_APP_IDS, i);
+ }
+
+ final TreeSet<Integer> users = new TreeSet<>();
+ final int nextAlarmClockForUserSize = mNextAlarmClockForUser.size();
+ for (int i = 0; i < nextAlarmClockForUserSize; i++) {
+ users.add(mNextAlarmClockForUser.keyAt(i));
+ }
+ final int pendingSendNextAlarmClockChangedForUserSize =
+ mPendingSendNextAlarmClockChangedForUser.size();
+ for (int i = 0; i < pendingSendNextAlarmClockChangedForUserSize; i++) {
+ users.add(mPendingSendNextAlarmClockChangedForUser.keyAt(i));
+ }
+ for (int user : users) {
+ final AlarmManager.AlarmClockInfo next = mNextAlarmClockForUser.get(user);
+ final long time = next != null ? next.getTriggerTime() : 0;
+ final boolean pendingSend = mPendingSendNextAlarmClockChangedForUser.get(user);
+ final long aToken = proto.start(AlarmManagerServiceProto.NEXT_ALARM_CLOCK_METADATA);
+ proto.write(AlarmClockMetadataProto.USER, user);
+ proto.write(AlarmClockMetadataProto.IS_PENDING_SEND, pendingSend);
+ proto.write(AlarmClockMetadataProto.TRIGGER_TIME_MS, time);
+ proto.end(aToken);
+ }
+ for (Batch b : mAlarmBatches) {
+ b.writeToProto(proto, AlarmManagerServiceProto.PENDING_ALARM_BATCHES,
+ nowElapsed, nowRTC);
+ }
+ for (int i = 0; i < mPendingBackgroundAlarms.size(); i++) {
+ final ArrayList<Alarm> blockedAlarms = mPendingBackgroundAlarms.valueAt(i);
+ if (blockedAlarms != null) {
+ for (Alarm a : blockedAlarms) {
+ a.writeToProto(proto,
+ AlarmManagerServiceProto.PENDING_USER_BLOCKED_BACKGROUND_ALARMS,
+ nowElapsed, nowRTC);
+ }
+ }
+ }
+ if (mPendingIdleUntil != null) {
+ mPendingIdleUntil.writeToProto(
+ proto, AlarmManagerServiceProto.PENDING_IDLE_UNTIL, nowElapsed, nowRTC);
+ }
+ for (Alarm a : mPendingWhileIdleAlarms) {
+ a.writeToProto(proto, AlarmManagerServiceProto.PENDING_WHILE_IDLE_ALARMS,
+ nowElapsed, nowRTC);
+ }
+ if (mNextWakeFromIdle != null) {
+ mNextWakeFromIdle.writeToProto(proto, AlarmManagerServiceProto.NEXT_WAKE_FROM_IDLE,
+ nowElapsed, nowRTC);
+ }
+
+ for (Alarm a : mPendingNonWakeupAlarms) {
+ a.writeToProto(proto, AlarmManagerServiceProto.PAST_DUE_NON_WAKEUP_ALARMS,
+ nowElapsed, nowRTC);
+ }
+
+ proto.write(AlarmManagerServiceProto.DELAYED_ALARM_COUNT, mNumDelayedAlarms);
+ proto.write(AlarmManagerServiceProto.TOTAL_DELAY_TIME_MS, mTotalDelayTime);
+ proto.write(AlarmManagerServiceProto.MAX_DELAY_DURATION_MS, mMaxDelayTime);
+ proto.write(AlarmManagerServiceProto.MAX_NON_INTERACTIVE_DURATION_MS,
+ mNonInteractiveTime);
+
+ proto.write(AlarmManagerServiceProto.BROADCAST_REF_COUNT, mBroadcastRefCount);
+ proto.write(AlarmManagerServiceProto.PENDING_INTENT_SEND_COUNT, mSendCount);
+ proto.write(AlarmManagerServiceProto.PENDING_INTENT_FINISH_COUNT, mSendFinishCount);
+ proto.write(AlarmManagerServiceProto.LISTENER_SEND_COUNT, mListenerCount);
+ proto.write(AlarmManagerServiceProto.LISTENER_FINISH_COUNT, mListenerFinishCount);
+
+ for (InFlight f : mInFlight) {
+ f.writeToProto(proto, AlarmManagerServiceProto.OUTSTANDING_DELIVERIES);
+ }
+
+ proto.write(AlarmManagerServiceProto.ALLOW_WHILE_IDLE_MIN_DURATION_MS,
+ mAllowWhileIdleMinTime);
+ for (int i = 0; i < mLastAllowWhileIdleDispatch.size(); ++i) {
+ final long token = proto.start(
+ AlarmManagerServiceProto.LAST_ALLOW_WHILE_IDLE_DISPATCH_TIMES);
+ proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.UID,
+ mLastAllowWhileIdleDispatch.keyAt(i));
+ proto.write(AlarmManagerServiceProto.LastAllowWhileIdleDispatch.TIME_MS,
+ mLastAllowWhileIdleDispatch.valueAt(i));
+ proto.end(token);
+ }
+
+ mLog.writeToProto(proto, AlarmManagerServiceProto.RECENT_PROBLEMS);
+
+ 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;
+ // Get the top 10 FilterStats, ordered by aggregateTime.
+ for (int iu = 0; iu < mBroadcastStats.size(); ++iu) {
+ ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+ for (int ip = 0; ip < uidStats.size(); ++ip) {
+ BroadcastStats bs = uidStats.valueAt(ip);
+ for (int is = 0; is < bs.filterStats.size(); ++is) {
+ FilterStats fs = bs.filterStats.valueAt(is);
+ 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++;
+ }
+ }
+ }
+ }
+ }
+ for (int i = 0; i < len; ++i) {
+ final long token = proto.start(AlarmManagerServiceProto.TOP_ALARMS);
+ FilterStats fs = topFilters[i];
+
+ proto.write(AlarmManagerServiceProto.TopAlarm.UID, fs.mBroadcastStats.mUid);
+ proto.write(AlarmManagerServiceProto.TopAlarm.PACKAGE_NAME,
+ fs.mBroadcastStats.mPackageName);
+ fs.writeToProto(proto, AlarmManagerServiceProto.TopAlarm.FILTER);
+
+ proto.end(token);
+ }
+
+ final ArrayList<FilterStats> tmpFilters = new ArrayList<FilterStats>();
+ for (int iu = 0; iu < mBroadcastStats.size(); ++iu) {
+ ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(iu);
+ for (int ip = 0; ip < uidStats.size(); ++ip) {
+ final long token = proto.start(AlarmManagerServiceProto.ALARM_STATS);
+
+ BroadcastStats bs = uidStats.valueAt(ip);
+ bs.writeToProto(proto, AlarmManagerServiceProto.AlarmStat.BROADCAST);
+
+ // uidStats is an ArrayMap, which we can't sort.
+ tmpFilters.clear();
+ for (int is = 0; is < bs.filterStats.size(); ++is) {
+ tmpFilters.add(bs.filterStats.valueAt(is));
+ }
+ Collections.sort(tmpFilters, comparator);
+ for (FilterStats fs : tmpFilters) {
+ fs.writeToProto(proto, AlarmManagerServiceProto.AlarmStat.FILTERS);
+ }
+
+ proto.end(token);
+ }
+ }
+
+ if (RECORD_DEVICE_IDLE_ALARMS) {
+ for (int i = 0; i < mAllowWhileIdleDispatches.size(); i++) {
+ IdleDispatchEntry ent = mAllowWhileIdleDispatches.get(i);
+ final long token = proto.start(
+ AlarmManagerServiceProto.ALLOW_WHILE_IDLE_DISPATCHES);
+
+ proto.write(IdleDispatchEntryProto.UID, ent.uid);
+ proto.write(IdleDispatchEntryProto.PKG, ent.pkg);
+ proto.write(IdleDispatchEntryProto.TAG, ent.tag);
+ proto.write(IdleDispatchEntryProto.OP, ent.op);
+ proto.write(IdleDispatchEntryProto.ENTRY_CREATION_REALTIME,
+ ent.elapsedRealtime);
+ proto.write(IdleDispatchEntryProto.ARG_REALTIME, ent.argRealtime);
+
+ proto.end(token);
+ }
+ }
+
+ if (WAKEUP_STATS) {
+ for (WakeupEvent event : mRecentWakeups) {
+ final long token = proto.start(AlarmManagerServiceProto.RECENT_WAKEUP_HISTORY);
+ proto.write(WakeupEventProto.UID, event.uid);
+ proto.write(WakeupEventProto.ACTION, event.action);
+ proto.write(WakeupEventProto.WHEN, event.when);
+ proto.end(token);
+ }
+ }
+ }
+
+ proto.flush();
+ }
+
private void logBatchesLocked(SimpleDateFormat sdf) {
ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
PrintWriter pw = new PrintWriter(bs);
@@ -2328,24 +2655,24 @@
alarmSeconds = when / 1000;
alarmNanoseconds = (when % 1000) * 1000 * 1000;
}
-
+
set(mNativeData, type, alarmSeconds, alarmNanoseconds);
} else {
Message msg = Message.obtain();
msg.what = ALARM_EVENT;
-
+
mHandler.removeMessages(ALARM_EVENT);
mHandler.sendMessageAtTime(msg, when);
}
}
private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
- String prefix, String label, long nowRTC, long nowELAPSED, SimpleDateFormat sdf) {
+ String prefix, String label, long nowELAPSED, long nowRTC, 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 + " ", nowRTC, nowELAPSED, sdf);
+ a.dump(pw, prefix + " ", nowELAPSED, nowRTC, sdf);
}
}
@@ -2355,8 +2682,6 @@
case RTC_WAKEUP : return "RTC_WAKEUP";
case ELAPSED_REALTIME : return "ELAPSED";
case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
- default:
- break;
}
return "--unknown--";
}
@@ -2368,7 +2693,7 @@
final String label = labelForType(a.type);
pw.print(prefix); pw.print(label); pw.print(" #"); pw.print(i);
pw.print(": "); pw.println(a);
- a.dump(pw, prefix + " ", nowRTC, nowELAPSED, sdf);
+ a.dump(pw, prefix + " ", nowELAPSED, nowRTC, sdf);
}
}
@@ -2533,7 +2858,7 @@
return 0;
}
}
-
+
private static class Alarm {
public final int type;
public final long origWhen;
@@ -2627,7 +2952,7 @@
return sb.toString();
}
- public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
+ public void dump(PrintWriter pw, String prefix, long nowELAPSED, long nowRTC,
SimpleDateFormat sdf) {
final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
pw.print(prefix); pw.print("tag="); pw.println(statsTag);
@@ -2656,6 +2981,30 @@
pw.print(prefix); pw.print("listener="); pw.println(listener.asBinder());
}
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId, long nowElapsed,
+ long nowRTC) {
+ final long token = proto.start(fieldId);
+
+ proto.write(AlarmProto.TAG, statsTag);
+ proto.write(AlarmProto.TYPE, type);
+ proto.write(AlarmProto.WHEN_ELAPSED_MS, whenElapsed - nowElapsed);
+ proto.write(AlarmProto.WINDOW_LENGTH_MS, windowLength);
+ proto.write(AlarmProto.REPEAT_INTERVAL_MS, repeatInterval);
+ proto.write(AlarmProto.COUNT, count);
+ proto.write(AlarmProto.FLAGS, flags);
+ if (alarmClock != null) {
+ alarmClock.writeToProto(proto, AlarmProto.ALARM_CLOCK);
+ }
+ if (operation != null) {
+ operation.writeToProto(proto, AlarmProto.OPERATION);
+ }
+ if (listener != null) {
+ proto.write(AlarmProto.LISTENER, listener.asBinder().toString());
+ }
+
+ proto.end(token);
+ }
}
void recordWakeupAlarms(ArrayList<Batch> batches, long nowELAPSED, long nowRTC) {
@@ -2752,7 +3101,7 @@
{
super("AlarmManager");
}
-
+
public void run()
{
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
@@ -2918,10 +3267,10 @@
public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 2;
public static final int LISTENER_TIMEOUT = 3;
public static final int REPORT_ALARMS_ACTIVE = 4;
-
+
public AlarmHandler() {
}
-
+
public void handleMessage(Message msg) {
switch (msg.what) {
case ALARM_EVENT: {
@@ -2969,7 +3318,7 @@
}
}
}
-
+
class ClockReceiver extends BroadcastReceiver {
public ClockReceiver() {
IntentFilter filter = new IntentFilter();
@@ -2977,7 +3326,7 @@
filter.addAction(Intent.ACTION_DATE_CHANGED);
getContext().registerReceiver(this, filter);
}
-
+
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
@@ -2996,7 +3345,7 @@
scheduleDateChangedEvent();
}
}
-
+
public void scheduleTimeTickEvent() {
final long currentTime = System.currentTimeMillis();
final long nextTime = 60000 * ((currentTime / 60000) + 1);
@@ -3026,7 +3375,7 @@
Process.myUid(), "android");
}
}
-
+
class InteractiveStateReceiver extends BroadcastReceiver {
public InteractiveStateReceiver() {
IntentFilter filter = new IntentFilter();
@@ -3059,7 +3408,7 @@
sdFilter.addAction(Intent.ACTION_UID_REMOVED);
getContext().registerReceiver(this, sdFilter);
}
-
+
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {