Changes pulled data to use Parcel objects.
Previously, pulled data was returned as a string. We instead
return the data as an array of StatsLogEventWrapper, which encodes
using the binary-encoded format liblog uses. StatsD uses the same
parsing as for pushed events to convert these. This CL also fixes
the parsing of log_msg since the strings were previously emptied
before we had a chance to read the values.
Note that the cpp-aidl can't support List of Parcelable, so we
have to return the results as an array.
Test: Manual using the new command in StatsService to print results.
Also created a new unit-test by creating a dummy pull code of -1,
but this test is deleted since it required creating a fake output in
StatsCompanionService.
Change-Id: I1cfb9ea081a59292a60e934e8527adc40982ed80
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 3c2f2d5..8505d4c 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -49,7 +49,8 @@
src/stats_util.cpp
statsd_common_c_includes := \
- $(LOCAL_PATH)/src
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/../../libs/services/include
statsd_common_aidl_includes := \
$(LOCAL_PATH)/../../core/java
@@ -95,7 +96,7 @@
endif
LOCAL_PROTOC_OPTIMIZE_TYPE := lite-static
-LOCAL_AIDL_INCLUDES := $(statsd_common_c_includes)
+LOCAL_AIDL_INCLUDES := $(statsd_common_aidl_includes)
LOCAL_C_INCLUDES += $(statsd_common_c_includes)
LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries)
@@ -117,7 +118,7 @@
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
-LOCAL_AIDL_INCLUDES := $(statsd_common_c_includes)
+LOCAL_AIDL_INCLUDES := $(statsd_common_aidl_includes)
LOCAL_C_INCLUDES += $(statsd_common_c_includes)
LOCAL_CFLAGS += \
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 87616d3..1faeee0 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -63,9 +63,9 @@
// ======================================================================
StatsService::StatsService(const sp<Looper>& handlerLooper)
- : mStatsPullerManager(),
- mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Put this comment somewhere better
+ : mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Put this comment somewhere better
{
+ mStatsPullerManager = new StatsPullerManager();
mUidMap = new UidMap();
mConfigManager = new ConfigManager();
mProcessor = new StatsLogProcessor(mUidMap);
@@ -193,6 +193,10 @@
if (!args[0].compare(String8("dump-report"))) {
return cmd_dump_report(out, err, args);
}
+
+ if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
+ return cmd_print_pulled_metrics(out, args);
+ }
}
print_cmd_help(out);
@@ -210,6 +214,11 @@
fprintf(out, " Prints the UID, app name, version mapping.\n");
fprintf(out, "\n");
fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmds stats pull-source [int] \n");
+ fprintf(out, "\n");
+ fprintf(out, " Prints the output of a pulled metrics source (int indicates source)\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
fprintf(out, "usage: adb shell cmd stats config remove [UID] NAME\n");
fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
fprintf(out, "\n");
@@ -353,6 +362,16 @@
return NO_ERROR;
}
+status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
+ int s = atoi(args[1].c_str());
+ auto stats = mStatsPullerManager->Pull(s);
+ for (const auto& it : stats) {
+ fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+ }
+ fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
+ return NO_ERROR;
+}
+
Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
const vector<String16>& app) {
if (DEBUG) ALOGD("StatsService::informAllUidData was called");
@@ -414,10 +433,6 @@
if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
// TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.
- String16 output = mStatsPullerManager.pull(StatsPullerManager::KERNEL_WAKELOCKS);
- // TODO: do something useful with the output instead of writing a string to screen.
- ALOGD("%s", String8(output).string());
- ALOGD("%d", int(output.size()));
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 294aec8..449a2b8 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -121,6 +121,11 @@
status_t cmd_print_uid_map(FILE* out);
/**
+ * Print contents of a pulled metrics source.
+ */
+ status_t cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args);
+
+ /**
* Update a configuration.
*/
void set_config(int uid, const string& name, const StatsdConfig& config);
@@ -132,9 +137,8 @@
/**
* Fetches external metrics.
- * TODO: This should be an sp<>
*/
- StatsPullerManager mStatsPullerManager;
+ sp<StatsPullerManager> mStatsPullerManager;
/**
* Tracks the configurations that have been passed to statsd.
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/KernelWakelockPuller.cpp
index b9abee0..ee072f8 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.cpp
+++ b/cmds/statsd/src/external/KernelWakelockPuller.cpp
@@ -37,9 +37,9 @@
// The reading and parsing are implemented in Java. It is not difficult to port over. But for now
// let StatsCompanionService handle that and send the data back.
-String16 KernelWakelockPuller::pull() {
+vector<StatsLogEventWrapper> KernelWakelockPuller::pull() {
sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
- String16 returned_value("");
+ vector<StatsLogEventWrapper> returned_value;
if (statsCompanion != NULL) {
Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
&returned_value);
@@ -47,12 +47,10 @@
ALOGW("error pulling kernel wakelock");
}
ALOGD("KernelWakelockPuller::pull succeeded!");
- // TODO: remove this when we integrate into aggregation chain.
- ALOGD("%s", String8(returned_value).string());
return returned_value;
} else {
ALOGW("statsCompanion not found!");
- return String16();
+ return returned_value;
}
}
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/KernelWakelockPuller.h
index 1ec3376..c12806c 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/KernelWakelockPuller.h
@@ -29,7 +29,7 @@
// a number of stats need to be pulled from StatsCompanionService
//
const static int PULL_CODE_KERNEL_WAKELOCKS;
- String16 pull() override;
+ vector<StatsLogEventWrapper> pull() override;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 5e556b8..6655629 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -17,7 +17,12 @@
#ifndef STATSD_STATSPULLER_H
#define STATSD_STATSPULLER_H
+#include <android/os/StatsLogEventWrapper.h>
#include <utils/String16.h>
+#include <vector>
+
+using android::os::StatsLogEventWrapper;
+using std::vector;
namespace android {
namespace os {
@@ -26,8 +31,8 @@
class StatsPuller {
public:
virtual ~StatsPuller(){};
- // use string for now, until we figure out how to integrate into the aggregation path
- virtual String16 pull() = 0;
+
+ virtual vector<StatsLogEventWrapper> pull() = 0;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 6e8d58bc..7f554d3 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -21,6 +21,11 @@
#include "KernelWakelockPuller.h"
#include "StatsService.h"
#include "external/StatsPullerManager.h"
+#include "logd/LogEvent.h"
+#include <cutils/log.h>
+#include <algorithm>
+
+#include <iostream>
using namespace android;
@@ -35,13 +40,27 @@
{static_cast<int>(KERNEL_WAKELOCKS), std::make_unique<KernelWakelockPuller>()});
}
-String16 StatsPullerManager::pull(int pullCode) {
+vector<std::shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode) {
if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
+
+ vector<std::shared_ptr<LogEvent>> ret;
if (mStatsPullers.find(pullCode) != mStatsPullers.end()) {
- return (mStatsPullers.find(pullCode)->second)->pull();
+ vector<StatsLogEventWrapper> outputs = (mStatsPullers.find(pullCode)->second)->pull();
+ for (const StatsLogEventWrapper& it : outputs) {
+ log_msg tmp;
+ tmp.entry_v1.len = it.bytes.size();
+ // Manually set the header size to 28 bytes to match the pushed log events.
+ tmp.entry.hdr_size = 28;
+ // And set the received bytes starting after the 28 bytes reserved for header.
+ std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + 28);
+ std::shared_ptr<LogEvent> evt = std::make_shared<LogEvent>(tmp);
+ ret.push_back(evt);
+ // ret.emplace_back(tmp);
+ }
+ return ret;
} else {
ALOGD("Unknown pull code %d", pullCode);
- return String16();
+ return ret; // Return early since we don't know what to pull.
}
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index f143424..e46aec1 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -20,6 +20,8 @@
#include <utils/String16.h>
#include <unordered_map>
#include "external/StatsPuller.h"
+#include "logd/LogEvent.h"
+#include "matchers/matcher_util.h"
namespace android {
namespace os {
@@ -27,7 +29,7 @@
const static int KERNEL_WAKELOCKS = 1;
-class StatsPullerManager {
+class StatsPullerManager : public virtual RefBase {
public:
// Enums of pulled data types (pullCodes)
// These values must be kept in sync with com/android/server/stats/StatsCompanionService.java.
@@ -35,7 +37,8 @@
const static int KERNEL_WAKELOCKS;
StatsPullerManager();
- String16 pull(const int pullCode);
+ // We return a vector of shared_ptr since LogEvent's copy constructor is not available.
+ vector<std::shared_ptr<LogEvent>> Pull(const int pullCode);
private:
std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 032b4b8..fb992c1 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -23,29 +23,30 @@
namespace statsd {
using std::ostringstream;
+using std::string;
-LogEvent::LogEvent(const log_msg& msg) {
- init(msg);
+// We need to keep a copy of the android_log_event_list owned by this instance so that the char*
+// for strings is not cleared before we can read them.
+LogEvent::LogEvent(log_msg msg) : mList(msg) {
+ init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
}
-LogEvent::LogEvent(int64_t timestampNs, android_log_event_list* reader) {
- init(timestampNs, reader);
+LogEvent::LogEvent(int tag) : mList(tag) {
}
LogEvent::~LogEvent() {
}
+void LogEvent::init() {
+ mList.convert_to_reader();
+ init(mTimestampNs, &mList);
+}
+
/**
* The elements of each log event are stored as a vector of android_log_list_elements.
* The goal is to do as little preprocessing as possible, because we read a tiny fraction
* of the elements that are written to the log.
*/
-void LogEvent::init(const log_msg& msg) {
-
- android_log_event_list list(const_cast<log_msg&>(msg));
- init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &list);
-}
-
void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
mTimestampNs = timestampNs;
mTagId = reader->tag();
@@ -79,6 +80,10 @@
} while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
}
+android_log_event_list* LogEvent::GetAndroidLogEventList() {
+ return &mList;
+}
+
int64_t LogEvent::GetLong(size_t key, status_t* err) const {
if (key < 1 || (key - 1) >= mElements.size()) {
*err = BAD_INDEX;
@@ -109,7 +114,8 @@
*err = BAD_TYPE;
return NULL;
}
- return elem.data.string;
+ // Need to add the '/0' at the end by specifying the length of the string.
+ return string(elem.data.string, elem.len).c_str();
}
bool LogEvent::GetBool(size_t key, status_t* err) const {
@@ -189,7 +195,8 @@
} else if (elem.type == EVENT_TYPE_FLOAT) {
result << elem.data.float32;
} else if (elem.type == EVENT_TYPE_STRING) {
- result << elem.data.string;
+ // Need to add the '/0' at the end by specifying the length of the string.
+ result << string(elem.data.string, elem.len).c_str();
}
}
result << " }";
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 464afca..4102675 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -22,6 +22,7 @@
#include <log/log_event_list.h>
#include <log/log_read.h>
+#include <memory>
#include <string>
#include <vector>
@@ -40,12 +41,16 @@
/**
* Read a LogEvent from a log_msg.
*/
- explicit LogEvent(const log_msg& msg);
+ explicit LogEvent(log_msg msg);
/**
- * Read a LogEvent from an android_log_context.
+ * Constructs a LogEvent with the specified tag and creates an android_log_event_list in write
+ * mode. Obtain this list with the getter. Make sure to call init() before attempting to read
+ * any of the values. This constructor is useful for unit-testing since we can't pass in an
+ * android_log_event_list since there is no copy constructor or assignment operator available.
*/
- explicit LogEvent(int64_t timestampNs, android_log_event_list* reader);
+ explicit LogEvent(int tag);
+
~LogEvent();
/**
@@ -85,6 +90,19 @@
*/
KeyValuePair GetKeyValueProto(size_t key) const;
+ /**
+ * A pointer to the contained log_event_list.
+ *
+ * @return The android_log_event_list contained within.
+ */
+ android_log_event_list* GetAndroidLogEventList();
+
+ /**
+ * Used with the constructor where tag is passed in. Converts the log_event_list to read mode
+ * and prepares the list for reading.
+ */
+ void init();
+
private:
/**
* Don't copy, it's slower. If we really need this we can add it but let's try to
@@ -103,6 +121,8 @@
void init(int64_t timestampNs, android_log_event_list* reader);
vector<android_log_list_element> mElements;
+ // Need a copy of the android_log_event_list so the strings are not cleared.
+ android_log_event_list mList;
long mTimestampNs;
int mTagId;
};
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 19403c0..fdfe8ef 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -42,12 +42,10 @@
auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
simpleMatcher->set_tag(TAG_ID);
- // Set up the event
- android_log_event_list list(TAG_ID);
+ LogEvent event(TAG_ID);
// Convert to a LogEvent
- list.convert_to_reader();
- LogEvent event(999, &list);
+ event.init();
// Test
EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
@@ -64,13 +62,13 @@
keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
// Set up the event
- android_log_event_list list(TAG_ID);
- list << true;
- list << false;
+ LogEvent event(TAG_ID);
+ auto list = event.GetAndroidLogEventList();
+ *list << true;
+ *list << false;
// Convert to a LogEvent
- list.convert_to_reader();
- LogEvent event(999, &list);
+ event.init();
// Test
keyValue1->set_eq_bool(true);
@@ -100,12 +98,12 @@
keyValue->set_eq_string("some value");
// Set up the event
- android_log_event_list list(TAG_ID);
- list << "some value";
+ LogEvent event(TAG_ID);
+ auto list = event.GetAndroidLogEventList();
+ *list << "some value";
// Convert to a LogEvent
- list.convert_to_reader();
- LogEvent event(999, &list);
+ event.init();
// Test
EXPECT_TRUE(matchesSimple(*simpleMatcher, event));
@@ -121,12 +119,11 @@
keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
// Set up the event
- android_log_event_list list(TAG_ID);
- list << 11;
+ LogEvent event(TAG_ID);
+ auto list = event.GetAndroidLogEventList();
+ *list << 11;
- // Convert to a LogEvent
- list.convert_to_reader();
- LogEvent event(999, &list);
+ event.init();
// Test