diff --git a/Android.mk b/Android.mk index 6470e342f9d9f..3bc6a86ed8427 100644 --- a/Android.mk +++ b/Android.mk @@ -579,6 +579,8 @@ LOCAL_SRC_FILES += \ LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings +LOCAL_AIDL_INCLUDES += core/java/android/os/StatsLogEventWrapper.aidl + LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java LOCAL_SRC_FILES += \ lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl \ diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 3c2f2d5d48ad0..8505d4c47aba2 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -49,7 +49,8 @@ statsd_common_src := \ 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 @@ else 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_MODULE := statsd_test 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 87616d3287d6c..1faeee0a65541 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -63,9 +63,9 @@ void CompanionDeathRecipient::binderDied(const wp& who) { // ====================================================================== StatsService::StatsService(const sp& 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 @@ status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector& 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 @@ void StatsService::print_cmd_help(FILE* out) { 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 @@ status_t StatsService::cmd_print_uid_map(FILE* out) { return NO_ERROR; } +status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector& 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& uid, const vector& version, const vector& app) { if (DEBUG) ALOGD("StatsService::informAllUidData was called"); @@ -414,10 +433,6 @@ Status StatsService::informPollAlarmFired() { 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 294aec868880a..449a2b84bfd72 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -120,6 +120,11 @@ private: */ 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& args); + /** * Update a configuration. */ @@ -132,9 +137,8 @@ private: /** * Fetches external metrics. - * TODO: This should be an sp<> */ - StatsPullerManager mStatsPullerManager; + sp 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 b9abee0d5df1d..ee072f80aa4ad 100644 --- a/cmds/statsd/src/external/KernelWakelockPuller.cpp +++ b/cmds/statsd/src/external/KernelWakelockPuller.cpp @@ -37,9 +37,9 @@ const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 20; // 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 KernelWakelockPuller::pull() { sp statsCompanion = StatsService::getStatsCompanionService(); - String16 returned_value(""); + vector returned_value; if (statsCompanion != NULL) { Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS, &returned_value); @@ -47,12 +47,10 @@ String16 KernelWakelockPuller::pull() { 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 1ec33762bd490..c12806c1fc474 100644 --- a/cmds/statsd/src/external/KernelWakelockPuller.h +++ b/cmds/statsd/src/external/KernelWakelockPuller.h @@ -29,7 +29,7 @@ public: // a number of stats need to be pulled from StatsCompanionService // const static int PULL_CODE_KERNEL_WAKELOCKS; - String16 pull() override; + vector pull() override; }; } // namespace statsd diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h index 5e556b89b5219..66556291e976d 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 #include +#include + +using android::os::StatsLogEventWrapper; +using std::vector; namespace android { namespace os { @@ -26,8 +31,8 @@ namespace statsd { 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 pull() = 0; }; } // namespace statsd diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 6e8d58bc33adb..7f554d3e398ed 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 +#include + +#include using namespace android; @@ -35,13 +40,27 @@ StatsPullerManager::StatsPullerManager() { {static_cast(KERNEL_WAKELOCKS), std::make_unique()}); } -String16 StatsPullerManager::pull(int pullCode) { +vector> StatsPullerManager::Pull(int pullCode) { if (DEBUG) ALOGD("Initiating pulling %d", pullCode); + + vector> ret; if (mStatsPullers.find(pullCode) != mStatsPullers.end()) { - return (mStatsPullers.find(pullCode)->second)->pull(); + vector 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 evt = std::make_shared(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 f143424e7b76c..e46aec1c060b4 100644 --- a/cmds/statsd/src/external/StatsPullerManager.h +++ b/cmds/statsd/src/external/StatsPullerManager.h @@ -20,6 +20,8 @@ #include #include #include "external/StatsPuller.h" +#include "logd/LogEvent.h" +#include "matchers/matcher_util.h" namespace android { namespace os { @@ -27,7 +29,7 @@ namespace statsd { 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 @@ public: 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> Pull(const int pullCode); private: std::unordered_map> mStatsPullers; diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp index 032b4b86fe76f..fb992c11aad76 100644 --- a/cmds/statsd/src/logd/LogEvent.cpp +++ b/cmds/statsd/src/logd/LogEvent.cpp @@ -23,29 +23,30 @@ namespace os { 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(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 @@ void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) { } 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 @@ const char* LogEvent::GetString(size_t key, status_t* err) const { *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 @@ string LogEvent::ToString() const { } 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 464afca1361f4..4102675074304 100644 --- a/cmds/statsd/src/logd/LogEvent.h +++ b/cmds/statsd/src/logd/LogEvent.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -40,12 +41,16 @@ public: /** * 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 @@ public: */ 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 @@ private: void init(int64_t timestampNs, android_log_event_list* reader); vector 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 19403c0d0e870..fdfe8ef46853e 100644 --- a/cmds/statsd/tests/LogEntryMatcher_test.cpp +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -42,12 +42,10 @@ TEST(LogEntryMatcherTest, TestSimpleMatcher) { 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 @@ TEST(LogEntryMatcherTest, TestBoolMatcher) { 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 @@ TEST(LogEntryMatcherTest, TestStringMatcher) { 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 @@ TEST(LogEntryMatcherTest, TestIntComparisonMatcher) { 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 diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl index d8f9567fddcbf..20f6c8ecd4953 100644 --- a/core/java/android/os/IStatsCompanionService.aidl +++ b/core/java/android/os/IStatsCompanionService.aidl @@ -16,6 +16,8 @@ package android.os; +import android.os.StatsLogEventWrapper; + /** * Binder interface to communicate with the Java-based statistics service helper. * {@hide} @@ -50,5 +52,5 @@ interface IStatsCompanionService { oneway void cancelPollingAlarms(); /** Pull the specified data. Results will be sent to statsd when complete. */ - String pullData(int pullCode); + StatsLogEventWrapper[] pullData(int pullCode); } diff --git a/core/java/android/os/StatsLogEventWrapper.aidl b/core/java/android/os/StatsLogEventWrapper.aidl new file mode 100644 index 0000000000000..766343e38f3fd --- /dev/null +++ b/core/java/android/os/StatsLogEventWrapper.aidl @@ -0,0 +1,20 @@ +/* + * 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. + */ + +package android.os; + +/** @hide */ +parcelable StatsLogEventWrapper cpp_header "android/os/StatsLogEventWrapper.h"; \ No newline at end of file diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java new file mode 100644 index 0000000000000..9491bec6532ca --- /dev/null +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -0,0 +1,141 @@ +/* + * 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. + */ +package android.os; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; + +/** + * Wrapper class for sending data from Android OS to StatsD. + * + * @hide + */ +public final class StatsLogEventWrapper implements Parcelable { + private ByteArrayOutputStream mStorage = new ByteArrayOutputStream(); + + // Below are constants copied from log/log.h + private static final int EVENT_TYPE_INT = 0; /* int32_t */ + private static final int EVENT_TYPE_LONG = 1; /* int64_t */ + private static final int EVENT_TYPE_STRING = 2; + private static final int EVENT_TYPE_LIST = 3; + private static final int EVENT_TYPE_FLOAT = 4; + + /** + * Creates a log_event that is binary-encoded as implemented in + * system/core/liblog/log_event_list.c; this allows us to use the same parsing logic in statsd + * for pushed and pulled data. The write* methods must be called in the same order as their + * field number. There is no checking that the correct number of write* methods is called. + * We also write an END_LIST character before beginning to write to parcel, but this END_LIST + * may be unnecessary. + * + * @param tag The integer representing the tag for this event. + * @param fields The number of fields specified in this event. + */ + public StatsLogEventWrapper(int tag, int fields) { + // Write four bytes from tag, starting with least-significant bit. + write4Bytes(tag); + mStorage.write(EVENT_TYPE_LIST); // This is required to start the log entry. + mStorage.write(fields); // Indicate number of elements in this list. + } + + /** + * Boilerplate for Parcel. + */ + public static final Parcelable.Creator CREATOR = new + Parcelable.Creator() { + public StatsLogEventWrapper createFromParcel(Parcel in) { + return new StatsLogEventWrapper(in); + } + + public StatsLogEventWrapper[] newArray(int size) { + return new StatsLogEventWrapper[size]; + } + }; + + private void write4Bytes(int val) { + mStorage.write(val); + mStorage.write(val >>> 8); + mStorage.write(val >>> 16); + mStorage.write(val >>> 24); + } + + private void write8Bytes(long val) { + write4Bytes((int) (val & 0xFFFFFFFF)); // keep the lowe 32-bits + write4Bytes((int) (val >>> 32)); // Write the high 32-bits. + } + + /** + * Adds 32-bit integer to output. + */ + public void writeInt(int val) { + mStorage.write(EVENT_TYPE_INT); + write4Bytes(val); + } + + /** + * Adds 64-bit long to output. + */ + public void writeLong(long val) { + mStorage.write(EVENT_TYPE_LONG); + write8Bytes(val); + } + + /** + * Adds a 4-byte floating point value to output. + */ + public void writeFloat(float val) { + int v = Float.floatToIntBits(val); + mStorage.write(EVENT_TYPE_FLOAT); + write4Bytes(v); + } + + /** + * Adds a string to the output. + */ + public void writeString(String val) { + mStorage.write(EVENT_TYPE_STRING); + write4Bytes(val.length()); + byte[] bytes = val.getBytes(StandardCharsets.UTF_8); + mStorage.write(bytes, 0, bytes.length); + } + + private StatsLogEventWrapper(Parcel in) { + readFromParcel(in); + } + + /** + * Writes the stored fields to a byte array. Will first write a new-line character to denote + * END_LIST before writing contents to byte array. + */ + public void writeToParcel(Parcel out, int flags) { + mStorage.write(10); // new-line character is same as END_LIST + out.writeByteArray(mStorage.toByteArray()); + } + + /** + * Not implemented. + */ + public void readFromParcel(Parcel in) { + // Not needed since this java class is for sending to statsd only. + } + + /** + * Boilerplate for Parcel. + */ + public int describeContents() { + return 0; + } +} diff --git a/libs/services/Android.mk b/libs/services/Android.mk index cbfd4b3f9f104..d72059aad93f5 100644 --- a/libs/services/Android.mk +++ b/libs/services/Android.mk @@ -21,7 +21,8 @@ include $(CLEAR_VARS) LOCAL_MODULE := libservices LOCAL_SRC_FILES := \ ../../core/java/com/android/internal/os/IDropBoxManagerService.aidl \ - src/os/DropBoxManager.cpp + src/os/DropBoxManager.cpp \ + src/os/StatsLogEventWrapper.cpp LOCAL_AIDL_INCLUDES := \ $(LOCAL_PATH)/../../core/java diff --git a/libs/services/include/android/os/StatsLogEventWrapper.h b/libs/services/include/android/os/StatsLogEventWrapper.h new file mode 100644 index 0000000000000..255619c6226c5 --- /dev/null +++ b/libs/services/include/android/os/StatsLogEventWrapper.h @@ -0,0 +1,47 @@ +/* + * 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 STATS_LOG_EVENT_WRAPPER_H +#define STATS_LOG_EVENT_WRAPPER_H + +#include +#include +#include +#include +#include + +namespace android { +namespace os { + +// Represents a parcelable object. Only used to send data from Android OS to statsd. +class StatsLogEventWrapper : public android::Parcelable { + public: + StatsLogEventWrapper(); + + StatsLogEventWrapper(StatsLogEventWrapper&& in) = default; + + android::status_t writeToParcel(android::Parcel* out) const; + + android::status_t readFromParcel(const android::Parcel* in); + + // These are public for ease of conversion. + std::vector bytes; +}; +} // Namespace os +} // Namespace android + + +#endif // STATS_LOG_EVENT_WRAPPER_H + diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp new file mode 100644 index 0000000000000..8b3aa9ab42571 --- /dev/null +++ b/libs/services/src/os/StatsLogEventWrapper.cpp @@ -0,0 +1,45 @@ +/* + * 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. + */ +#include + +#include +#include +#include +#include +#include + +using android::Parcel; +using android::Parcelable; +using android::status_t; +using std::vector; + +namespace android { +namespace os { + +StatsLogEventWrapper::StatsLogEventWrapper(){}; + +status_t StatsLogEventWrapper::writeToParcel(Parcel* out) const { + out->writeByteVector(bytes); + return ::android::NO_ERROR; +}; + +status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) { + in->readByteVector(&bytes); + return ::android::NO_ERROR; +}; + +} // Namespace os +} // Namespace android diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index ca3dd058660ce..22d2bcfc3e7e7 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -33,12 +33,14 @@ import android.os.IStatsManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.StatsLogEventWrapper; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; import java.util.ArrayList; import java.util.List; + import com.android.internal.annotations.GuardedBy; import com.android.internal.os.KernelWakelockReader; import com.android.internal.os.KernelWakelockStats; @@ -49,6 +51,7 @@ 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. + * * @hide */ public class StatsCompanionService extends IStatsCompanionService.Stub { @@ -90,7 +93,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // Needed since the new user basically has a version of every app. informAllUidsLocked(context); } catch (RemoteException e) { - Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e); + Slog.e(TAG, "Failed to inform statsd latest update of all apps", e); forgetEverything(); } } @@ -99,9 +102,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { Slog.w(TAG, "Registered receiver for ACTION_PACKAGE_REPLACE AND ADDED."); } - private final static int[] toIntArray(List list){ + private final static int[] toIntArray(List list) { int[] ret = new int[list.size()]; - for(int i = 0;i < ret.length;i++) { + for (int i = 0; i < ret.length; i++) { ret[i] = list.get(i); } return ret; @@ -113,7 +116,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { PackageManager pm = context.getPackageManager(); final List users = um.getUsers(true); if (DEBUG) { - Slog.w(TAG, "Iterating over "+users.size() + " profiles."); + Slog.w(TAG, "Iterating over " + users.size() + " profiles."); } List uids = new ArrayList(); @@ -122,23 +125,23 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // Add in all the apps for every user/profile. for (UserInfo profile : users) { - List pi = pm.getInstalledPackagesAsUser(0, profile.id); - for (int j = 0; j < pi.size(); j++) { - if (pi.get(j).applicationInfo != null) { - uids.add(pi.get(j).applicationInfo.uid); - versions.add(pi.get(j).versionCode); - apps.add(pi.get(j).packageName); - } - } + List pi = pm.getInstalledPackagesAsUser(0, profile.id); + for (int j = 0; j < pi.size(); j++) { + if (pi.get(j).applicationInfo != null) { + uids.add(pi.get(j).applicationInfo.uid); + versions.add(pi.get(j).versionCode); + apps.add(pi.get(j).packageName); + } + } } sStatsd.informAllUidData(toIntArray(uids), toIntArray(versions), apps.toArray(new - String[apps.size()])); + String[apps.size()])); if (DEBUG) { - Slog.w(TAG, "Sent data for "+uids.size() +" apps"); + Slog.w(TAG, "Sent data for " + uids.size() + " apps"); } } - public final static class AppUpdateReceiver extends BroadcastReceiver { + public final static class AppUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Slog.i(TAG, "StatsCompanionService noticed an app was updated."); @@ -147,7 +150,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { * waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag. */ if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) && - intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { return; // Keep only replacing or normal add and remove. } synchronized (sStatsdLock) { @@ -180,9 +183,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } } - }; + } - public final static class AnomalyAlarmReceiver extends BroadcastReceiver { + public final static class AnomalyAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred."); @@ -200,7 +203,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } // AlarmManager releases its own wakelock here. } - }; + } public final static class PollingAlarmReceiver extends BroadcastReceiver { @Override @@ -220,7 +223,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } // AlarmManager releases its own wakelock here. } - }; + } @Override // Binder call public void setAnomalyAlarm(long timestampMs) { @@ -286,33 +289,34 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats(); @Override // Binder call - public String pullData(int pullCode) { + public StatsLogEventWrapper[] pullData(int pullCode) { enforceCallingPermission(); - if (DEBUG) Slog.d(TAG, "Fetching " + pullCode); + if (DEBUG) { + Slog.d(TAG, "Pulling " + pullCode); + } - StringBuilder s = new StringBuilder(); // TODO: use and return a Parcel instead of a string + List ret = new ArrayList<>(); switch (pullCode) { - case PULL_CODE_KERNEL_WAKELOCKS: + case PULL_CODE_KERNEL_WAKELOCKS: { final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats); - for (Map.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'); + StatsLogEventWrapper e = new StatsLogEventWrapper(101, 4); + e.writeInt(kws.mCount); + e.writeInt(kws.mVersion); + e.writeLong(kws.mTotalTime); + e.writeString(name); + ret.add(e); } break; + } default: Slog.w(TAG, "No such pollable data as " + pullCode); return null; } - return s.toString(); + return ret.toArray(new StatsLogEventWrapper[ret.size()]); } @Override // Binder call @@ -331,7 +335,9 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // Lifecycle and related code - /** Fetches the statsd IBinder service */ + /** + * Fetches the statsd IBinder service + */ private static IStatsManager fetchStatsdService() { return IStatsManager.Stub.asInterface(ServiceManager.getService("stats")); } @@ -363,13 +369,17 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - /** Now that the android system is ready, StatsCompanion is ready too, so inform statsd. */ + /** + * Now that the android system is ready, StatsCompanion is ready too, so inform statsd. + */ private void systemReady() { if (DEBUG) Slog.d(TAG, "Learned that systemReady"); sayHiToStatsd(); } - /** Tells statsd that statscompanion is ready. If the binder call returns, link to statsd. */ + /** + * Tells statsd that statscompanion is ready. If the binder call returns, link to statsd. + */ private void sayHiToStatsd() { synchronized (sStatsdLock) { if (sStatsd != null) { @@ -398,14 +408,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter, null, - null); + null); // Setup receiver for user initialize (which happens once for a new user) and // if a user is removed. filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE); filter.addAction(Intent.ACTION_USER_REMOVED); mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL, - filter, null, null); + filter, null, null); // Pull the latest state of UID->app name, version mapping when statsd starts. informAllUidsLocked(mContext);