diff options
| -rw-r--r-- | Android.mk | 1 | ||||
| -rw-r--r-- | cmds/statsd/Android.mk | 1 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsLogProcessor.cpp | 40 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsLogProcessor.h | 33 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.cpp | 38 | ||||
| -rw-r--r-- | cmds/statsd/src/StatsService.h | 32 | ||||
| -rw-r--r-- | core/java/android/os/IStatsCallbacks.aidl | 25 | ||||
| -rw-r--r-- | core/java/android/os/IStatsManager.aidl | 13 |
8 files changed, 178 insertions, 5 deletions
diff --git a/Android.mk b/Android.mk index 648544a956a7..9890bb401404 100644 --- a/Android.mk +++ b/Android.mk @@ -270,6 +270,7 @@ LOCAL_SRC_FILES += \ core/java/android/os/IRecoverySystemProgressListener.aidl \ core/java/android/os/IRemoteCallback.aidl \ core/java/android/os/ISchedulingPolicyService.aidl \ + core/java/android/os/IStatsCallbacks.aidl \ core/java/android/os/IStatsCompanionService.aidl \ core/java/android/os/IStatsManager.aidl \ core/java/android/os/IThermalEventListener.aidl \ diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 8946aed58052..50f631184155 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -15,6 +15,7 @@ LOCAL_PATH:= $(call my-dir) statsd_common_src := \ + ../../core/java/android/os/IStatsCallbacks.aidl \ ../../core/java/android/os/IStatsCompanionService.aidl \ ../../core/java/android/os/IStatsManager.aidl \ src/stats_log.proto \ diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index e7825cf75159..68f48a4f4c37 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -33,8 +33,9 @@ namespace android { namespace os { namespace statsd { -StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap) - : m_dropbox_writer("all-logs"), mUidMap(uidMap) { +StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap, + const std::function<void(const vector<uint8_t>&)>& pushLog) + : m_dropbox_writer("all-logs"), mUidMap(uidMap), mPushLog(pushLog) { } StatsLogProcessor::~StatsLogProcessor() { @@ -91,6 +92,41 @@ void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) { } } +void StatsLogProcessor::addEventMetricData(const EventMetricData& eventMetricData) { + // TODO: Replace this code when MetricsManager.onDumpReport() is ready to + // get a list of byte arrays. + flushIfNecessary(eventMetricData); + const int numBytes = eventMetricData.ByteSize(); + char buffer[numBytes]; + eventMetricData.SerializeToArray(&buffer[0], numBytes); + string bufferString(buffer, numBytes); + mEvents.push_back(bufferString); + mBufferSize += eventMetricData.ByteSize(); +} + +void StatsLogProcessor::flushIfNecessary(const EventMetricData& eventMetricData) { + if (eventMetricData.ByteSize() + mBufferSize > kMaxSerializedBytes) { + flush(); + } +} + +void StatsLogProcessor::flush() { + StatsLogReport logReport; + for (string eventBuffer : mEvents) { + EventMetricData eventFromBuffer; + eventFromBuffer.ParseFromString(eventBuffer); + EventMetricData* newEntry = logReport.mutable_event_metrics()->add_data(); + newEntry->CopyFrom(eventFromBuffer); + } + + const int numBytes = logReport.ByteSize(); + vector<uint8_t> logReportBuffer(numBytes); + logReport.SerializeToArray(&logReportBuffer[0], numBytes); + mPushLog(logReportBuffer); + mEvents.clear(); + mBufferSize = 0; +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 3cefd29fa026..08090c11f724 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -33,7 +33,8 @@ namespace statsd { class StatsLogProcessor : public ConfigListener { public: - StatsLogProcessor(const sp<UidMap>& uidMap); + StatsLogProcessor(const sp<UidMap>& uidMap, + const std::function<void(const vector<uint8_t>&)>& pushLog); virtual ~StatsLogProcessor(); virtual void OnLogEvent(const LogEvent& event); @@ -44,6 +45,9 @@ public: // TODO: Once we have the ProtoOutputStream in c++, we can just return byte array. std::vector<StatsLogReport> onDumpReport(const ConfigKey& key); + /* Request a flush through a binder call. */ + void flush(); + private: // TODO: use EventMetrics to log the events. DropboxWriter m_dropbox_writer; @@ -51,6 +55,33 @@ private: std::unordered_map<ConfigKey, std::unique_ptr<MetricsManager>> mMetricsManagers; sp<UidMap> mUidMap; // Reference to the UidMap to lookup app name and version for each uid. + + /* Max *serialized* size of the logs kept in memory before flushing through binder call. + 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. + */ + static const size_t kMaxSerializedBytes = 16 * 1024; + + /* List of data that was captured for a single metric over a given interval of time. */ + vector<string> mEvents; + + /* Current *serialized* size of the logs kept in memory. + To save computation, we will not calculate the size of the StatsLogReport 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 EventMetricData& eventMetricData); + + /* Append event metric data to StatsLogReport. */ + void addEventMetricData(const EventMetricData& eventMetricData); + + std::function<void(const vector<uint8_t>&)> mPushLog; }; } // namespace statsd diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 1faeee0a6554..604753ef54a0 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -68,7 +68,9 @@ StatsService::StatsService(const sp<Looper>& handlerLooper) mStatsPullerManager = new StatsPullerManager(); mUidMap = new UidMap(); mConfigManager = new ConfigManager(); - mProcessor = new StatsLogProcessor(mUidMap); + mProcessor = new StatsLogProcessor(mUidMap, [this](const vector<uint8_t>& log) { + pushLog(log); + }); mConfigManager->AddListener(mProcessor); @@ -507,6 +509,40 @@ void StatsService::OnLogEvent(const LogEvent& event) { mProcessor->OnLogEvent(event); } +Status StatsService::requestPush() { + mProcessor->flush(); + return Status::ok(); +} + +Status StatsService::pushLog(const vector<uint8_t>& log) { + std::lock_guard<std::mutex> lock(mLock); + for (size_t i = 0; i < mCallbacks.size(); i++) { + mCallbacks[i]->onReceiveLogs((vector<uint8_t>*)&log); + } + return Status::ok(); +} + +Status StatsService::subscribeStatsLog(const sp<IStatsCallbacks>& callback) { + std::lock_guard<std::mutex> lock(mLock); + for (size_t i = 0; i < mCallbacks.size(); i++) { + if (mCallbacks[i] == callback) { + return Status::fromStatusT(-errno); + } + } + mCallbacks.add(callback); + IInterface::asBinder(callback)->linkToDeath(this); + return Status::ok(); +} + +void StatsService::binderDied(const wp<IBinder>& who) { + for (size_t i = 0; i < mCallbacks.size(); i++) { + if (IInterface::asBinder(mCallbacks[i]) == who) { + mCallbacks.removeAt(i); + break; + } + } +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 449a2b84bfd7..7f046584b2d0 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -24,6 +24,7 @@ #include "packages/UidMap.h" #include <android/os/BnStatsManager.h> +#include <android/os/IStatsCallbacks.h> #include <android/os/IStatsCompanionService.h> #include <binder/IResultReceiver.h> #include <binder/IShellCallback.h> @@ -42,7 +43,7 @@ namespace android { namespace os { namespace statsd { -class StatsService : public BnStatsManager, public LogListener { +class StatsService : public BnStatsManager, public LogListener, public IBinder::DeathRecipient { public: StatsService(const sp<Looper>& handlerLooper); virtual ~StatsService(); @@ -70,6 +71,22 @@ public: */ virtual void OnLogEvent(const LogEvent& event); + /** + * Binder call to force trigger pushLog. This would be called by callback + * clients. + */ + virtual Status requestPush() override; + + /** + * Pushes stats log entries from statsd to callback clients. + */ + Status pushLog(const vector<uint8_t>& log); + + /** + * Binder call to listen to statsd to send stats log entries. + */ + virtual Status subscribeStatsLog(const sp<IStatsCallbacks>& callbacks) override; + // TODO: public for testing since statsd doesn't run when system starts. Change to private // later. /** Inform statsCompanion that statsd is ready. */ @@ -78,6 +95,9 @@ public: /** Fetches and returns the StatsCompanionService. */ static sp<IStatsCompanionService> getStatsCompanionService(); + /** IBinder::DeathRecipient */ + virtual void binderDied(const wp<IBinder>& who) override; + private: /** * Load system properties at init. @@ -159,6 +179,16 @@ private: * Whether this is an eng build. */ bool mEngBuild; + + /** + * Lock for callback handling. + */ + std::mutex mLock; + + /** + * Vector maintaining the list of callbacks for clients. + */ + Vector< sp<IStatsCallbacks> > mCallbacks; }; } // namespace statsd diff --git a/core/java/android/os/IStatsCallbacks.aidl b/core/java/android/os/IStatsCallbacks.aidl new file mode 100644 index 000000000000..02e7cd3978c8 --- /dev/null +++ b/core/java/android/os/IStatsCallbacks.aidl @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2016, 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; + +/** + * Callback for Statsd to allow binder calls to clients. + * {@hide} + */ +interface IStatsCallbacks { + void onReceiveLogs(out byte[] log); +} diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index daacc4e832f9..480296c12e50 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -16,6 +16,8 @@ package android.os; +import android.os.IStatsCallbacks; + /** * Binder interface to communicate with the statistics management service. * {@hide} @@ -61,4 +63,15 @@ interface IStatsManager { * Inform stats that an app was removed. */ oneway void informOnePackageRemoved(in String app, in int uid); + + /** + * Trigger pushLog to force push stats log entries from statsd on client side. + */ + void requestPush(); + + /** + * Listen to statsd to send stats log entries. + * TODO: Limit callbacks with specific configurations. + */ + void subscribeStatsLog(IStatsCallbacks callbacks); } |