Statsd can pull kernel wakelock data
When statsd is told that it is time to poll data, it asks
StatsCompanionService to pull kernel wakelock data, receives the result
(as a string), and outputs it to screen.
Still to do:
1. don't use a string; use a parcel instead
2. don't output it to screen; do something useful instead
3. do more than just kernel wakelocks
4. pull data on demand, in addition to just on periodic pulling
Test: added setPollingAlarms to statsd.main and confirmed that kernel
wakelock information was written to screen
Change-Id: I35f5164420699dea1a00c9e530b938904f1d3055
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index b9ee7ff..2db8eee 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -44,6 +44,7 @@
../../core/java/android/os/IStatsManager.aidl \
src/StatsService.cpp \
src/AnomalyMonitor.cpp \
+ src/StatsPuller.cpp \
src/LogEntryPrinter.cpp \
src/LogReader.cpp \
src/main.cpp \
diff --git a/cmds/statsd/src/StatsPuller.cpp b/cmds/statsd/src/StatsPuller.cpp
new file mode 100644
index 0000000..94e8361
--- /dev/null
+++ b/cmds/statsd/src/StatsPuller.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "StatsPuller"
+#define DEBUG true
+
+#include "StatsPuller.h"
+#include "StatsService.h"
+#include <android/os/IStatsCompanionService.h>
+#include <cutils/log.h>
+
+using namespace android;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+String16 StatsPuller::pull(int pullCode) {
+ if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
+
+ switch (pullCode) {
+ // All stats_companion_service cases go here with fallthroughs
+ case PULL_CODE_KERNEL_WAKELOCKS: {
+ // TODO: Consider caching the statsCompanion service
+ sp <IStatsCompanionService>
+ statsCompanion = StatsService::getStatsCompanionService();
+ String16 returned_value("");
+ Status status = statsCompanion->pullData(pullCode, &returned_value);
+ if (DEBUG) ALOGD("Finished pulling the data");
+ if (!status.isOk()) {
+ ALOGW("error pulling data of type %d", pullCode);
+ }
+ return returned_value;
+ }
+
+ // case OTHER_TYPES: etc.
+
+ default: {
+ ALOGE("invalid pull code %d", pullCode);
+ return String16("");
+ }
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/StatsPuller.h b/cmds/statsd/src/StatsPuller.h
new file mode 100644
index 0000000..05343b5
--- /dev/null
+++ b/cmds/statsd/src/StatsPuller.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef STATSD_STATSPULLER_H
+#define STATSD_STATSPULLER_H
+
+#include <utils/String16.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StatsPuller {
+public:
+ // Enums of pulled data types (pullCodes)
+ // These values must be kept in sync with com/android/server/stats/StatsCompanionService.java.
+ // TODO: pull the constant from stats_events.proto instead
+ const static int PULL_CODE_KERNEL_WAKELOCKS = 20;
+
+ StatsPuller();
+ ~StatsPuller();
+
+ static String16 pull(int pullCode);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif //STATSD_STATSPULLER_H
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index a28f085..ae7d66b 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -177,6 +177,9 @@
if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
// TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.
+ String16 output = StatsPuller::pull(StatsPuller::PULL_CODE_KERNEL_WAKELOCKS);
+ // TODO: do something useful with the output instead of writing a string to screen.
+ ALOGD("%s", String8(output).string());
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index a956cbf..b02579d 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -19,6 +19,7 @@
#include "AnomalyMonitor.h"
#include "StatsLogProcessor.h"
+#include "StatsPuller.h"
#include <android/os/BnStatsManager.h>
#include <android/os/IStatsCompanionService.h>
@@ -67,19 +68,21 @@
/** Inform statsCompanion that statsd is ready. */
virtual void sayHiToStatsCompanion();
-private:
- sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs.
+ // TODO: Move this to a more logical file/class
+ // TODO: Should be private. Temporarily public for testing purposes only.
+ const sp<AnomalyMonitor> mAnomalyMonitor;
- const sp<AnomalyMonitor> mAnomalyMonitor; // TODO: Move this to a more logical file/class
+ /** Fetches and returns the StatsCompanionService. */
+ static sp<IStatsCompanionService> getStatsCompanionService();
+
+ private:
+ sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs.
status_t doPrintStatsLog(FILE* out, const Vector<String8>& args);
void printCmdHelp(FILE* out);
status_t doLoadConfig(FILE* in);
-
- /** Fetches the StatsCompanionService. */
- sp<IStatsCompanionService> getStatsCompanionService();
};
// --- StatsdDeathRecipient ---
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index a83d313..d8f9567 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -20,11 +20,11 @@
* Binder interface to communicate with the Java-based statistics service helper.
* {@hide}
*/
-oneway interface IStatsCompanionService {
+interface IStatsCompanionService {
/**
* Tell statscompanion that stastd is up and running.
*/
- void statsdReady();
+ oneway void statsdReady();
/**
* Register an alarm for anomaly detection to fire at the given timestamp (ms since epoch).
@@ -32,10 +32,10 @@
* Uses AlarmManager.set API, so if the timestamp is in the past, alarm fires immediately, and
* alarm is inexact.
*/
- void setAnomalyAlarm(long timestampMs);
+ oneway void setAnomalyAlarm(long timestampMs);
/** Cancel any anomaly detection alarm. */
- void cancelAnomalyAlarm();
+ oneway void cancelAnomalyAlarm();
/**
* Register a repeating alarm for polling to fire at the given timestamp and every
@@ -44,8 +44,11 @@
* Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
* and alarm is inexact.
*/
- void setPollingAlarms(long timestampMs, long intervalMs);
+ oneway void setPollingAlarms(long timestampMs, long intervalMs);
/** Cancel any repeating polling alarm. */
- void cancelPollingAlarms();
+ oneway void cancelPollingAlarms();
+
+ /** Pull the specified data. Results will be sent to statsd when complete. */
+ String pullData(int pullCode);
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 11ae212..4294f15 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -30,8 +30,12 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.KernelWakelockReader;
+import com.android.internal.os.KernelWakelockStats;
import com.android.server.SystemService;
+import java.util.Map;
+
/**
* Helper service for statsd (the native stats management service in cmds/statsd/).
* Used for registering and receiving alarms on behalf of statsd.
@@ -156,7 +160,44 @@
}
}
- @Override
+ // These values must be kept in sync with cmd/statsd/StatsPuller.h.
+ // TODO: pull the constant from stats_events.proto instead
+ private static final int PULL_CODE_KERNEL_WAKELOCKS = 20;
+
+ private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
+ private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
+
+ @Override // Binder call
+ public String pullData(int pullCode) {
+ enforceCallingPermission();
+ if (DEBUG) Slog.d(TAG, "Fetching " + pullCode);
+
+ StringBuilder s = new StringBuilder(); // TODO: use and return a Parcel instead of a string
+ switch (pullCode) {
+ case PULL_CODE_KERNEL_WAKELOCKS:
+ final KernelWakelockStats wakelockStats =
+ mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
+
+ for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
+ String name = ent.getKey();
+ KernelWakelockStats.Entry kws = ent.getValue();
+ s.append("Wakelock ")
+ .append(name)
+ .append(", time=")
+ .append(kws.mTotalTime)
+ .append(", count=")
+ .append(kws.mCount)
+ .append('\n');
+ }
+ break;
+ default:
+ Slog.w(TAG, "No such pollable data as " + pullCode);
+ return null;
+ }
+ return s.toString();
+ }
+
+ @Override // Binder call
public void statsdReady() {
enforceCallingPermission();
if (DEBUG) Slog.d(TAG, "learned that statsdReady");