OSDN Git Service

Adds aidl definitions and their implementations for binder transfer of
authoryro <yro@google.com>
Tue, 24 Oct 2017 20:33:21 +0000 (13:33 -0700)
committeryro <yro@google.com>
Tue, 24 Oct 2017 22:25:27 +0000 (15:25 -0700)
statsd entries to clients. This change only includes changes on statds
side and does not include java library for clients to import. Java
library will be a separate change as it requires system api review.

Test: statsd, statsd_test
Change-Id: I306c6e9687801668cc0145b12d38406bfe634775

Android.mk
cmds/statsd/Android.mk
cmds/statsd/src/StatsLogProcessor.cpp
cmds/statsd/src/StatsLogProcessor.h
cmds/statsd/src/StatsService.cpp
cmds/statsd/src/StatsService.h
core/java/android/os/IStatsCallbacks.aidl [new file with mode: 0644]
core/java/android/os/IStatsManager.aidl

index 648544a..9890bb4 100644 (file)
@@ -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 \
index 8946aed..50f6311 100644 (file)
@@ -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 \
index e7825cf..68f48a4 100644 (file)
@@ -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
index 3cefd29..08090c1 100644 (file)
@@ -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
index 1faeee0..604753e 100644 (file)
@@ -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
index 449a2b8..7f04658 100644 (file)
@@ -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 (file)
index 0000000..02e7cd3
--- /dev/null
@@ -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);
+}
index daacc4e..480296c 100644 (file)
@@ -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);
 }