diff options
| author | 2017-09-14 03:41:38 +0000 | |
|---|---|---|
| committer | 2017-09-14 03:41:38 +0000 | |
| commit | 8e7418509d6db2e1eb585c52bab563f28dfe93dd (patch) | |
| tree | b27e0666080dcd3ecdafea4fc330415194e83106 | |
| parent | a41d85286104e9d4266fac8803c31e4aef505852 (diff) | |
| parent | 482d272d7c94201206518d6b37d32647838b15d7 (diff) | |
Merge changes from topic "dropbox"
* changes:
Add a cmd line tool to StatsService to parse log files from Dropbox
Add a DropboxWriter in statsd.
| -rw-r--r-- | cmds/statsd/Android.mk | 40 | ||||
| -rw-r--r-- | cmds/statsd/src/DropboxReader.cpp | 120 | ||||
| -rw-r--r-- | cmds/statsd/src/DropboxReader.h | 45 | ||||
| -rw-r--r-- | cmds/statsd/src/DropboxWriter.cpp | 61 | ||||
| -rw-r--r-- | cmds/statsd/src/DropboxWriter.h | 66 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsLogProcessor.cpp | 68 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsLogProcessor.h | 46 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.cpp | 29 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.h | 4 | ||||
| -rw-r--r-- | cmds/statsd/src/main.cpp | 6 | ||||
| -rw-r--r-- | cmds/statsd/src/stats_constants.proto | 31 | ||||
| -rw-r--r-- | cmds/statsd/src/stats_log.proto | 77 | ||||
| -rw-r--r-- | cmds/statsd/src/statsd_config.proto | 449 | ||||
| -rw-r--r-- | libs/services/include/android/os/DropBoxManager.h | 12 | ||||
| -rw-r--r-- | libs/services/src/os/DropBoxManager.cpp | 34 |
15 files changed, 1071 insertions, 17 deletions
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index db8c89dafaba..4c097f012d2d 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -14,6 +14,23 @@ LOCAL_PATH:= $(call my-dir) +# ================ +# proto static lib +# ================ +include $(CLEAR_VARS) + +LOCAL_MODULE := statsd_proto +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-proto-files-under, src) + +LOCAL_PROTOC_FLAGS := +LOCAL_PROTOC_OPTIMIZE_TYPE := lite + +include $(BUILD_STATIC_LIBRARY) + +STATSD_PROTO_INCLUDES := $(local-generated-sources-dir)/src/$(LOCAL_PATH) + # ========= # statsd # ========= @@ -27,7 +44,14 @@ LOCAL_SRC_FILES := \ src/StatsService.cpp \ src/LogEntryPrinter.cpp \ src/LogReader.cpp \ - src/main.cpp + src/main.cpp \ + src/DropboxWriter.cpp \ + src/StatsLogProcessor.cpp \ + src/stats_log.proto \ + src/statsd_config.proto \ + src/stats_constants.proto \ + src/DropboxReader.cpp \ + LOCAL_CFLAGS += \ -Wall \ @@ -47,7 +71,10 @@ else endif LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/../../core/java -LOCAL_C_INCLUDES += $(LOCAL_PATH)/src +LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \ + STATSD_PROTO_INCLUDES + +LOCAL_STATIC_LIBRARIES := statsd_proto LOCAL_SHARED_LIBRARIES := \ libbase \ @@ -56,7 +83,9 @@ LOCAL_SHARED_LIBRARIES := \ libincident \ liblog \ libselinux \ - libutils + libutils \ + libservices \ + libandroidfw \ LOCAL_MODULE_CLASS := EXECUTABLES @@ -82,7 +111,8 @@ LOCAL_CFLAGS += \ -Wno-unused-function \ -Wno-unused-parameter -LOCAL_C_INCLUDES += $(LOCAL_PATH)/src +LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \ + STATSD_PROTO_INCLUDES LOCAL_SRC_FILES := \ ../../core/java/android/os/IStatsManager.aidl \ @@ -93,6 +123,7 @@ LOCAL_SRC_FILES := \ LOCAL_STATIC_LIBRARIES := \ libgmock \ + statsd_proto LOCAL_SHARED_LIBRARIES := \ libbase \ @@ -103,4 +134,3 @@ LOCAL_SHARED_LIBRARIES := \ libutils include $(BUILD_NATIVE_TEST) - diff --git a/cmds/statsd/src/DropboxReader.cpp b/cmds/statsd/src/DropboxReader.cpp new file mode 100644 index 000000000000..187f4ada61ca --- /dev/null +++ b/cmds/statsd/src/DropboxReader.cpp @@ -0,0 +1,120 @@ +/* + * 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 <android/os/DropBoxManager.h> +#include <android-base/file.h> +#include <cutils/log.h> +#include <androidfw/ZipUtils.h> +#include <stdio.h> + +#include "DropboxReader.h" + +using android::sp; +using android::String16; +using android::binder::Status; +using android::base::unique_fd; +using android::os::DropBoxManager; +using android::os::statsd::StatsLogEntry; +using android::ZipUtils; +using std::vector; + +status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) { + sp<DropBoxManager> dropbox = new DropBoxManager(); + StatsLogList logList; + + long timestamp = msec; + // instead of while(true), put a hard limit 1000. Dropbox won't have more than 1000 files. + for(int i = 0; i < 1000; i++ ) { + DropBoxManager::Entry entry; + Status status = dropbox->getNextEntry(String16(tag.c_str()), + timestamp, &entry); + if (!status.isOk()) { + ALOGD("No more entries, or failed to read. We can't tell unfortunately."); + return android::OK; + } + + const unique_fd& fd = entry.getFd(); + + // use this timestamp for next query. + timestamp = entry.getTimestamp(); + + if (entry.getFlags() & DropBoxManager::IS_GZIPPED) { + if (!parseFromGzipFile(fd, logList)) { + // Failed to parse from the file. Continue to fetch the next entry. + continue; + } + } else { + if (!parseFromFile(fd, logList)) { + // Failed to parse from the file. Continue to fetch the next entry. + continue; + } + } + + printLog(out, logList); + } + return android::OK; +} + +bool DropboxReader::parseFromGzipFile(const unique_fd& fd, StatsLogList& list) { + FILE *file = fdopen(fd, "r"); + bool result = false; + bool scanResult; + int method; + long compressedLen; + long uncompressedLen; + unsigned long crc32; + scanResult = ZipUtils::examineGzip(file, &method, &uncompressedLen, + &compressedLen, &crc32); + if (scanResult && method == kCompressDeflated) { + vector<uint8_t> buf(uncompressedLen); + if (ZipUtils::inflateToBuffer(file, &buf[0], uncompressedLen, compressedLen)) { + if (list.ParseFromArray(&buf[0], uncompressedLen)) { + result = true; + } + } + } else { + ALOGE("This isn't a valid deflated gzip file"); + } + fclose(file); + return result; +} + +// parse a non zipped file. +bool DropboxReader::parseFromFile(const unique_fd& fd, StatsLogList& list) { + string content; + if (!android::base::ReadFdToString(fd, &content)) { + ALOGE("Failed to read file"); + return false; + } + if (!list.ParseFromString(content)) { + ALOGE("failed to parse log entry from data"); + return false; + } + return true; +} + +void DropboxReader::printLog(FILE* out, const StatsLogList& list) { + for (int i = 0; i < list.stats_log_entry_size(); i++) { + const StatsLogEntry entry = list.stats_log_entry(i); + // TODO: print pretty + fprintf(out, "time_msec=%lld, type=%d, aggregate_type=%d, uid=%d, pid=%d ", + entry.start_report_millis(), entry.type(), entry.aggregate_type(), + entry.uid(), entry.pid()); + for (int j = 0; j < entry.pairs_size(); j++) { + fprintf(out, "msg=%s ", entry.pairs(j).value_str().c_str()); + } + fprintf(out, "\n"); + } +} diff --git a/cmds/statsd/src/DropboxReader.h b/cmds/statsd/src/DropboxReader.h new file mode 100644 index 000000000000..a62ffde6b255 --- /dev/null +++ b/cmds/statsd/src/DropboxReader.h @@ -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. + */ + +#ifndef DROPBOX_READER_H +#define DROPBOX_READER_H + +#include <frameworks/base/cmds/statsd/src/stats_log.pb.h> + +#include <stdint.h> +#include <stdio.h> + +using android::base::unique_fd; +using android::os::statsd::StatsLogList; +using android::status_t; +using std::string; + +class DropboxReader { +public: + // msec is the start timestamp. + static status_t readStatsLogs(FILE* out, const string& tag, long msec); + +private: + static bool parseFromFile(const unique_fd& fd, StatsLogList& list); + static bool parseFromGzipFile(const unique_fd& fd, StatsLogList& list); + static void printLog(FILE* out, const StatsLogList& list); + enum { + kCompressStored = 0, // no compression + kCompressDeflated = 8, // standard deflate + }; +}; + +#endif //DROPBOX_READER_H
\ No newline at end of file diff --git a/cmds/statsd/src/DropboxWriter.cpp b/cmds/statsd/src/DropboxWriter.cpp new file mode 100644 index 000000000000..a251056d9e81 --- /dev/null +++ b/cmds/statsd/src/DropboxWriter.cpp @@ -0,0 +1,61 @@ +/* + * 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 <android/os/DropBoxManager.h> +#include <cutils/log.h> + +#include "DropboxWriter.h" + +using android::os::DropBoxManager; +using android::binder::Status; +using android::sp; +using android::String16; +using std::vector; + +DropboxWriter::DropboxWriter(const string& tag) + : mTag(tag), mLogList(), mBufferSize(0) { +} + +void DropboxWriter::addEntry(const StatsLogEntry& entry) { + flushIfNecessary(entry); + StatsLogEntry* newEntry = mLogList.add_stats_log_entry(); + newEntry->CopyFrom(entry); + mBufferSize += entry.ByteSize(); +} + +void DropboxWriter::flushIfNecessary(const StatsLogEntry& entry) { + // The serialized size of the StatsLogList is approximately the sum of the serialized size of + // every StatsLogEntry inside it. + if (entry.ByteSize() + mBufferSize > kMaxSerializedBytes) { + flush(); + } +} + +void DropboxWriter::flush() { + // now we get an exact byte size of the output + const int numBytes = mLogList.ByteSize(); + vector<uint8_t> buffer(numBytes); + sp<DropBoxManager> dropbox = new DropBoxManager(); + mLogList.SerializeToArray(&buffer[0], numBytes); + Status status = dropbox->addData(String16(mTag.c_str()), &buffer[0], + numBytes, 0 /* no flag */); + if (!status.isOk()) { + ALOGE("failed to write to dropbox"); + //TODO: What to do if flush fails?? + } + mLogList.Clear(); + mBufferSize = 0; +} diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/DropboxWriter.h new file mode 100644 index 000000000000..176ac8b944a7 --- /dev/null +++ b/cmds/statsd/src/DropboxWriter.h @@ -0,0 +1,66 @@ +/* + * 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 DROPBOX_WRITER_H +#define DROPBOX_WRITER_H + +#include <frameworks/base/cmds/statsd/src/stats_log.pb.h> + +using std::string; +using android::os::statsd::StatsLogEntry; +using android::os::statsd::StatsLogList; + +class DropboxWriter { +public: + /* tag will be part of the file name, and used as the key to build the file index inside + DropBoxManagerService. + */ + DropboxWriter(const string& tag); + + void addEntry(const StatsLogEntry& entry); + + /* Request a flush to dropbox. */ + void flush(); + +private: + /* Max *serialized* size of the logs kept in memory before flushing to dropbox. + Proto lite does not implement the SpaceUsed() function which gives the in memory byte size. + So we cap memory usage by limiting the serialized size. Note that protobuf's in memory size + is higher than its serialized size. DropboxManager will compress the file when the data is + larger than 4KB. So the final file size is less than this number. + */ + static const size_t kMaxSerializedBytes = 16 * 1024; + + const string mTag; + + /* StatsLogList is a wrapper for storing a list of StatsLogEntry */ + StatsLogList mLogList; + + /* Current *serialized* size of the logs kept in memory. + To save computation, we will not calculate the size of the StatsLogList every time when a new + entry is added, which would recursively call ByteSize() on every log entry. Instead, we keep + the sum of all individual stats log entry sizes. The size of a proto is approximately the sum + of the size of all member protos. + */ + size_t mBufferSize = 0; + + /* Check if the buffer size exceeds the max buffer size when the new entry is added, and flush + the logs to dropbox if true. */ + void flushIfNecessary(const StatsLogEntry& entry); + +}; + +#endif //DROPBOX_WRITER_H diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp new file mode 100644 index 000000000000..f49dfde804f4 --- /dev/null +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -0,0 +1,68 @@ +/* + * 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 <StatsLogProcessor.h> + +#include <log/event_tag_map.h> +#include <log/logprint.h> +#include <utils/Errors.h> + +#include <frameworks/base/cmds/statsd/src/stats_log.pb.h> + +using namespace android; +using android::os::statsd::StatsLogEntry; + +StatsLogProcessor::StatsLogProcessor() : m_dropbox_writer("all-logs") +{ + // Initialize the EventTagMap, which is how we know the names of the numeric event tags. + // If this fails, we can't print well, but something will print. + m_tags = android_openEventTagMap(NULL); + + // Printing format + m_format = android_log_format_new(); + android_log_setPrintFormat(m_format, FORMAT_THREADTIME); +} + +StatsLogProcessor::~StatsLogProcessor() +{ + if (m_tags != NULL) { + android_closeEventTagMap(m_tags); + } + android_log_format_free(m_format); +} + +void +StatsLogProcessor::OnLogEvent(const log_msg& msg) +{ + status_t err; + AndroidLogEntry entry; + char buf[1024]; + + err = android_log_processBinaryLogBuffer(&(const_cast<log_msg*>(&msg)->entry_v1), + &entry, m_tags, buf, sizeof(buf)); + + // dump all statsd logs to dropbox for now. + // TODO: Add filtering, aggregation, etc. + if (err == NO_ERROR) { + StatsLogEntry logEntry; + logEntry.set_uid(entry.uid); + logEntry.set_pid(entry.pid); + logEntry.set_start_report_millis(entry.tv_sec / 1000 + entry.tv_nsec / 1000 / 1000); + logEntry.add_pairs()->set_value_str(entry.message, entry.messageLen); + m_dropbox_writer.addEntry(logEntry); + } +} + diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h new file mode 100644 index 000000000000..23066ab974d8 --- /dev/null +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -0,0 +1,46 @@ +/* + * 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_PROCESSOR_H +#define STATS_LOG_PROCESSOR_H + +#include "LogReader.h" +#include "DropboxWriter.h" + +#include <log/logprint.h> +#include <stdio.h> + +class StatsLogProcessor : public LogListener +{ +public: + StatsLogProcessor(); + virtual ~StatsLogProcessor(); + + virtual void OnLogEvent(const log_msg& msg); + +private: + /** + * Numeric to string tag name mapping. + */ + EventTagMap* m_tags; + + /** + * Pretty printing format. + */ + AndroidLogFormat* m_format; + + DropboxWriter m_dropbox_writer; +}; +#endif //STATS_LOG_PROCESSOR_H diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 5ee07b44d2a3..030c760c8643 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "statsd" #include "StatsService.h" +#include "DropboxReader.h" #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -27,6 +28,7 @@ #include <unistd.h> #include <stdio.h> +#include <stdlib.h> using namespace android; @@ -118,15 +120,13 @@ StatsService::dump(int fd, const Vector<String16>& args) status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) { - fprintf(out, "StatsService::command:"); - ALOGD("StatsService::command:"); - const int N = args.size(); - for (int i=0; i<N; i++) { - fprintf(out, " %s", String8(args[i]).string()); - ALOGD(" %s", String8(args[i]).string()); + if (args.size() > 0) { + if (!args[0].compare(String8("print-stats-log")) && args.size() > 1) { + return doPrintStatsLog(out, args); + } } - fprintf(out, "\n"); + printCmdHelp(out); return NO_ERROR; } @@ -144,3 +144,18 @@ StatsService::systemRunning() return Status::ok(); } +status_t +StatsService::doPrintStatsLog(FILE* out, const Vector<String8>& args) { + long msec = 0; + + if (args.size() > 2) { + msec = strtol(args[2].string(), NULL, 10); + } + return DropboxReader::readStatsLogs(out, args[1].string(), msec); +} + +void +StatsService::printCmdHelp(FILE* out) { + fprintf(out, "Usage:\n"); + fprintf(out, "\t print-stats-log [tag_required] [timestamp_nsec_optional]\n"); +} diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 5dd92990547c..556b07b6b594 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -45,6 +45,10 @@ public: virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args); virtual Status systemRunning(); + +private: + status_t doPrintStatsLog(FILE* out, const Vector<String8>& args); + void printCmdHelp(FILE* out); }; #endif // STATS_SERVICE_H diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp index 93405cb6bf95..2c721c74f117 100644 --- a/cmds/statsd/src/main.cpp +++ b/cmds/statsd/src/main.cpp @@ -19,6 +19,7 @@ #include "LogEntryPrinter.h" #include "LogReader.h" #include "StatsService.h" +#include "StatsLogProcessor.h" #include <binder/IInterface.h> #include <binder/IPCThreadState.h> @@ -55,9 +56,8 @@ log_reader_thread_func(void* cookie) sp<LogReader> reader = new LogReader(); // Put the printer one first, so it will print before the real ones. - if (true) { - reader->AddListener(new LogEntryPrinter(STDOUT_FILENO)); - } + reader->AddListener(new LogEntryPrinter(STDOUT_FILENO)); + reader->AddListener(new StatsLogProcessor()); // TODO: Construct and add real LogListners here. diff --git a/cmds/statsd/src/stats_constants.proto b/cmds/statsd/src/stats_constants.proto new file mode 100644 index 000000000000..1787ae3cba2e --- /dev/null +++ b/cmds/statsd/src/stats_constants.proto @@ -0,0 +1,31 @@ +/* + * 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 android.os.statsd; + +option optimize_for = LITE_RUNTIME; + +option java_package = "com.android.internal.logging"; +option java_outer_classname = "StatsConstantsProto"; + +message StatsConstants { + // Event type. + enum Type { + WAKELOCK = 1; + SCREEN= 2; + } +} diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto new file mode 100644 index 000000000000..ec92023c873a --- /dev/null +++ b/cmds/statsd/src/stats_log.proto @@ -0,0 +1,77 @@ +/* + * 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 android.os.statsd; + +option optimize_for = LITE_RUNTIME; + +option java_package = "com.android.os"; +option java_outer_classname = "StatsLog"; + +import "frameworks/base/cmds/statsd/src/statsd_config.proto"; +import "frameworks/base/cmds/statsd/src/stats_constants.proto"; + +// StatsLogEntry is a generic proto holding a single metrics data. +message StatsLogEntry { + // Type of stats. + optional android.os.statsd.StatsConstants.Type type = 1; + + // Aggregation type of the data. + optional android.os.statsd.TrackedAggregateType aggregate_type = 2; + + // Start timestamp of the interval. Timestamp for event-type data will have + // equal value for start_report_millis and end_report_millis. + optional int64 start_report_millis = 3; + + // End timestamp of the interval. + optional int64 end_report_millis = 4; + + // Package information for application-level data. + optional string package_name = 5; + optional int32 package_version = 6; + optional string package_version_string = 7; + + // UID associated with the data. + optional int32 uid = 8; + + // PID associated with the data. + optional int32 pid = 9; + + // Payload contains key value pairs of the data from statsd. + message KeyValuePair { + // Integer representation of data type. + optional int32 key = 1; + + oneof value { + string value_str = 2; + int64 value_int = 3; + bool value_bool = 4; + } + } + repeated KeyValuePair pairs = 10; + + // Next tag: 11 +} + +// Data captured for a given metric during a given period of time. +message StatsLogList { + // Unique ID for this metric. + optional int32 metric_id = 1; + + // List of stats log entry. + repeated StatsLogEntry stats_log_entry = 2; +} diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto new file mode 100644 index 000000000000..2d034e50f4b5 --- /dev/null +++ b/cmds/statsd/src/statsd_config.proto @@ -0,0 +1,449 @@ +/* + * 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. + */ + + +// Version 1. +// Important: Update the version line above before copy-pasting this file +// from/to Google3 and Android repository. +// This proto needs to be manually synced between Google3 and Android versions. + +/* + * Note about semantics of the buckets: + * In this current proto scheme, the buckets are updated only when an event + * occurs. In the case of durations, this means that we update at the end of a + * duration. + * + * For example, suppose we have buckets at every 10 min: + * 0, 10, 20, 30, 40, etc. + * And then suppose a wakelock is first held starting at min 5 and lasts for 21 + * mins. Then the buckets for 0-10 and 10-20 don't contain anything and inside + * the bucket for 20-30, we add the value of 21 minutes. + * + * Also note that buckets are only aligned to wall-clock (no custom time-bases). + */ + +syntax = "proto2"; +package android.os.statsd; + +option optimize_for = LITE_RUNTIME; + +option java_package = "com.android.internal.os"; +option java_outer_classname = "StatsdConfigProto"; + +// KeyMatcher specifies how to match the key. +message KeyMatcher { + oneof contents { + int32 key = 1; // ID of the key to match. + + // Special matcher for package name. This will match either the package name + // or the UID (statsD will map the UID of the source event to a package + // name). Specify the package name to match in eq_string. + bool use_package = 2; + } +} + +// FieldMatcher allows us to match specific fields/keys in an event. +message FieldMatcher { + optional KeyMatcher key_matcher = 1; + + oneof value_matcher { + // Equality matchers + bool eq_bool = 2; + string eq_string = 3; + int32 eq_int32 = 4; + int64 eq_int64 = 5; + + // Numeric comparisons; + int32 lt_int32 = 6; + int32 gt_int32 = 7; + int64 lt_int64 = 8; + int64 gt_int64 = 9; + float lt_float = 10; + float gt_float = 11; + } +} + +enum OperationType { + AND = 1; + OR = 2; + NOT = 3; // Must have only a single operand when using NOT operator. + NAND = 4; // NAND and NOR as conveniences to avoid NOT+(AND/OR)-layers. + NOR = 5; +} + +enum TrackedAggregateType { + // IS_RUNNING; // whether it is currently running + VALUE_COUNT = 1; // count number of events + VALUE_SUM = 2; + VALUE_MAX = 3; + VALUE_MIN = 4; + DURATION_SUM = 5; // cumulative total time + DURATION_MAX = 6; // longest continuously-on time + DURATION_MIN = 7; // shortest continuously-on time + //DURATION_CURRENT = 6; // current continuously-on time (not bucketed) +} + +// Assume the events come in with a tag and an array of (key, value) tuples +// where the key must be an int32 and value can be any type. +message LineMatcher { + // For now, we assume that we don't flatten the tags (ie, one tag corresponds + // to screen-on and screen-off events and key 1 represents ON or OFF). + repeated int32 tag = 1; // Must match at least one of the tags. + + message Nested { + optional OperationType operation = 1; + repeated LineMatcher matcher = 2; + } + oneof contents { + FieldMatcher requirement = 2; + Nested nested = 3; + } +} + +// Defines when an AggregateCounter or EventMatcher applies. +message Condition { + message Nested { + optional OperationType operation = 1; + repeated Condition nested_conditions = 2; // operands that are themselves + // conditions (recursively) + } + + // Leaf node of condition. + message RangeMatcher { + optional LineMatcher start = 1; + optional LineMatcher stop = 2; + optional bool count_nesting = 3 + [default = true]; // true if "start start stop" is still + // considered running + + // Configure which fields define the slices. These fields must be present in + // both the start and stop lines. Note that this can be a subset of all the + // slices defined in the AggregateCounter. + // For example, if the counter slices on both app name and wake lock name, + // we can define that this range only slices on app name. + repeated KeyMatcher slice = 4; + } + + oneof contents { + RangeMatcher range = 1; // Represents a leaf node. + Nested nested = 2; // Represents a non-leaf node. + } +} + +// Emits matching events to statsd event buffer. +message EventMatcher { + // Tracks what configuration led to uploading of this event. + optional int32 metric_id = 1; + + // LineMatcher for the event to emit. + optional LineMatcher what = 2; + + optional Condition condition = 3; + + // TODO: Have a clear use-case for this in P or-else drop this for P. + message Filter { + } + optional Filter filter = 4; +} + +// Hard-code the possible metrics that we can pull. +// For example, NETSTATS_BY_UID would provide network usage per uid. +// We should treat the results like a batch of individual log events, and we +// should process them one-by-one to re-use our LineMatcher logic. +enum PulledMetricSource { + NETSTATS = 1; +} + +message AggregateCounter { // previously called Timer + // Specifies which fields in the message act as dimensions. + // For both pushed and pulled metrics, we assume every record has all the + // dimensions set. + message Slicer { + repeated KeyMatcher keys = 1; + } + optional Slicer slicer = 1; + + message ValueSource { + message PushedMetric { + // LineMatcher for the event to apply. + // Slicing (which keys act as dimensions) should not be specified here. + optional LineMatcher what = 1; + + // Only needed if one key should be treated as the value. + optional int32 value_key = 2; + } + + // The values for pulled metrics are computed and aggregated at the end of + // the condition. + message PulledMetric { + optional bool compute_diff = + 1; // If we want the diff (if this + // metric is pulled when condition opens/closes). + optional PulledMetricSource metric = 2; + + // We treat the pulled metrics as a batch of log-records that look like + // they came from LogD. + optional LineMatcher what = 3; + optional int32 value_field = 4; + } + + oneof value { + PushedMetric pushed_metric = 1; + + // Pulled metrics are computed when the duration closes (and are also + // fetched at the open if we need to compute a diff). + // Pulled metrics require a condition being defined. + // These metrics are not pulled at the end of every bucket. + PulledMetric pulled_metric = 2; + + // Polled Metrics are pulled at the end of every bucket. + // Since the buckets are only planned to be on wall-clock for Android P, + // condition is NOT supported for polled metrics. + PulledMetric polled_metric = 3; + } + } + optional ValueSource value = 2; + + message TrackedAggregate { + // Must be an integer that is uniquely chosen so we can identify the metric + // on server. We will provide a tool on server to help generate this. + optional int32 metric_id = 1; + + optional TrackedAggregateType type = 2; + + // Alert if the value, when summed over the Counter's number_of_buckets + // most-recent bins, exceeds min_threshold or is below max_threshold. For + // Anomaly Detection. + message Alert { + message IncidentdDetails { + optional string + alert_name = 1; // for humans and incidentd to identify this issue + repeated int32 incidentd_sections = 2; // tells incidentd what to do if + // alert triggers + } + optional IncidentdDetails incidentd_details = 1; + optional int32 number_of_buckets = 2; + // NOTE: that we assume the aggregate is only int. + optional int64 trigger_if_gt = 3; // min threshold + optional int64 trigger_if_lt = 4; // max_threshold; + optional int32 refractory_period_secs = 5; // alarm cannot fire a second + // time until elapsed + } + repeated Alert alerts = 3; // Support diff alert params for same aggregate. + } // end TrackedAggregate + repeated TrackedAggregate tracked_aggregates = 3; + + optional Condition condition = 4; + + message Bucket { + // TODO: Consider switching to second granularity. + // In practice, this must be chosen from a pre-defined list. So that we have + // flexiblity, we don't hard-code this as an enum today. + optional int64 bucket_size_msec = 1; + optional int32 max_number_of_bits = 2; // Max bits per bucket. + } + optional Bucket bucket = 5; + + message MiscellaneousEffect { + optional LineMatcher matcher = 1; // When to trigger the effect + + enum Effect { + STOP_ALL = 1; // Needed for stop-all events, where nested start value is + // forced to 0. + } + repeated Effect effects = 2; + } // end MiscellaneousEffect + repeated MiscellaneousEffect misc_effects = 6; +} // end Counter + +// Alarm configs not tied to a particular Counter. +message GlobalAlertParameters { + // No alarm can fire after any other alarm fired until this many seconds has + // elapsed. + optional int32 global_refractory_period_seconds = 1; +} + +// The config defining all metrics to be captured. +message StatsdConfig { + // Event matchers. + repeated EventMatcher event_matchers = 1; + + // Aggregate counters. + repeated AggregateCounter aggregate_counters = 2; +} + +/* Sample configurations start here: +----Screen on time---- +AggregateCounter < + condition < + range < + start < + tag: SCREEN_ON + requirement < + key_matcher< + key: SCREEN_ON_VALUE + eq_bool: true + stop < + tag: SCREEN_ON + requirement < + key_matcher< + key: SCREEN_ON_VALUE + eq_bool: false + metric_id: # set on server + tracked_aggregates < + DURATION_SUM + (For brevity, omit the bucket options but they can also be set) + +----Screen off time---- +Should be like aboe but reversing start and stop + +----Log the screen change events---- +EventMatcher < + metric_id: # set on server + what < + tag: SCREEN_ON + +----Number of crashes (across system)---- +AggregateCounter < + metric_id: # set on server + tracked_aggregates < + VALUE_COUNT + value < + pushed_metric < + what < + tag: CRASH_TAG + +----Network Usage in bytes Per App While in Background---- +AggregateCounter < + metric_id: # set on server + slicer < + keys < + use_package_name: true + tracked_aggregates < + VALUE_SUM + value < + pulled_metric < + compute_diff: true + metric: Enum corresponding to network usage in bytes + condition < + range < + sliced: true + start < + tag: APP_FOREGROUND_TRANSITION (assume false means move to background) + requirement < + key_matcher< + key: APP_FOREGROUND_STATE + eq_bool: false + stop < + tag: APP_FOREGROUND_TRANSITION (assume false means move to background) + requirement < + key_matcher< + key: APP_FOREGROUND_STATE + eq_bool: true + +----Wakelock Acquire time per app and wakelock + while unplugged and screen off and in background process state---- +AggregateCounter < + metric_id: # set on server + slicer < + keys < + use_package_name: true + keys < + key: Key corresponding to wake_lock ID + tracked_aggregates < + DURATION_SUM + condition < + nested < + operation: AND + nested_conditions < + range < + start < + tag: PLUGGED_IN (assume false means uncharged) + requirement < + key_matcher< + key: PLUGGED_IN_STATE + eq_bool: false + stop < + tag: PLUGGED_IN (assume false means uncharged) + requirement < + key_matcher< + key: PLUGGED_IN_STATE + eq_bool: true + nested_conditions < + range < + start < + tag: SCREEN_ON + requirement < + key_matcher< + key: SCREEN_ON_STATE + eq_bool: false + stop < + tag: SCREEN_ON + requirement < + key_matcher< + key: SCREEN_ON_STATE + eq_bool: true + nested_conditions < + range < + start < + tag: PROCESS_CHANGE + requirement < + key_matcher< + key: PROCESS_STATE_VALUE + eq_int32: BACKGROUND_PROCESS + stop < + tag: PROCESS_CHANGE + nested < + operation: NOT + matcher< (This is an example of using the NOT to define stop) + requirement < (Note this requirement should match the start.) + key_matcher< + key: PROCESS_STATE_VALUE + eq_int32: BACKGROUND_PROCESS + slice< + use_package_name: true + + +----Number of crashes (per app) ---- +AggregateCounter < + metric_id: # set on server + slicer < + keys< + use_package_name: true + tracked_aggregates < + VALUE_COUNT + value < + pushed_metric < + what < + tag: CRASH_TAG + +---- Number of transitions to background (per app) ---- +AggregateCounter < + metric_id: # set on server + slicer < + keys< + use_package_name: true + tracked_aggregates < + VALUE_COUNT + value < + pushed_metric < + what < + tag: APP_FOREGROUND_TRANSITION + requirement< + key: APP_FOREGROUND_TRANSITION_STATE + eq_bool: false + +*/ diff --git a/libs/services/include/android/os/DropBoxManager.h b/libs/services/include/android/os/DropBoxManager.h index 8717178bb7d6..2ed203d9f865 100644 --- a/libs/services/include/android/os/DropBoxManager.h +++ b/libs/services/include/android/os/DropBoxManager.h @@ -57,7 +57,7 @@ public: // and a handle will be passed to the system process, so no additional permissions // are required from the system process. Returns NULL if the file can't be opened. Status addFile(const String16& tag, const string& filename, int flags); - + class Entry : public virtual RefBase, public Parcelable { public: Entry(); @@ -65,7 +65,12 @@ public: virtual status_t writeToParcel(Parcel* out) const; virtual status_t readFromParcel(const Parcel* in); - + + const vector<uint8_t>& getData() const; + const unique_fd& getFd() const; + int32_t getFlags() const; + int64_t getTimestamp() const; + private: Entry(const String16& tag, int32_t flags); Entry(const String16& tag, int32_t flags, int fd); @@ -80,6 +85,9 @@ public: friend class DropBoxManager; }; + // Get the next entry from the drop box after the specified time. + Status getNextEntry(const String16& tag, long msec, Entry* entry); + private: enum { HAS_BYTE_ARRAY = 8 diff --git a/libs/services/src/os/DropBoxManager.cpp b/libs/services/src/os/DropBoxManager.cpp index bbb45f022a87..1c760e850e4f 100644 --- a/libs/services/src/os/DropBoxManager.cpp +++ b/libs/services/src/os/DropBoxManager.cpp @@ -143,6 +143,29 @@ DropBoxManager::Entry::readFromParcel(const Parcel* in) return NO_ERROR; } +const vector<uint8_t>& +DropBoxManager::Entry::getData() const +{ + return mData; +} + +const unique_fd& +DropBoxManager::Entry::getFd() const +{ + return mFd; +} + +int32_t +DropBoxManager::Entry::getFlags() const +{ + return mFlags; +} + +int64_t +DropBoxManager::Entry::getTimestamp() const +{ + return mTimeMillis; +} DropBoxManager::DropBoxManager() { @@ -195,5 +218,16 @@ DropBoxManager::add(const Entry& entry) return service->add(entry); } +Status +DropBoxManager::getNextEntry(const String16& tag, long msec, Entry* entry) +{ + sp<IDropBoxManagerService> service = interface_cast<IDropBoxManagerService>( + defaultServiceManager()->getService(android::String16("dropbox"))); + if (service == NULL) { + return Status::fromExceptionCode(Status::EX_NULL_POINTER, "can't find dropbox service"); + } + return service->getNextEntry(tag, msec, entry); +} + }} // namespace android::os |