[SfStats] Implement global atom puller for SfStats

Bug: 119885568
Bug: 136597024
Test: adb shell cmd stats pull-source 10062
Test: statsd_testdrive 10062
Test: atest statsd_test
Change-Id: Ib113066faf67f6abba6cd377aaf1fe17cf16d4d0
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 475f18a..4cf7bc4 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -17,12 +17,17 @@
 #define DEBUG false
 #include "Log.h"
 
+#include "StatsPullerManager.h"
+
 #include <android/os/IStatsCompanionService.h>
 #include <android/os/IStatsPullerCallback.h>
 #include <cutils/log.h>
 #include <math.h>
 #include <stdint.h>
+
 #include <algorithm>
+#include <iostream>
+
 #include "../StatsService.h"
 #include "../logd/LogEvent.h"
 #include "../stats_log_util.h"
@@ -32,13 +37,11 @@
 #include "ResourceHealthManagerPuller.h"
 #include "StatsCallbackPuller.h"
 #include "StatsCompanionServicePuller.h"
-#include "StatsPullerManager.h"
 #include "SubsystemSleepStatePuller.h"
+#include "SurfaceflingerStatsPuller.h"
 #include "TrainInfoPuller.h"
 #include "statslog.h"
 
-#include <iostream>
-
 using std::make_shared;
 using std::map;
 using std::shared_ptr;
@@ -266,6 +269,10 @@
         // App ops
         {android::util::APP_OPS,
          {.puller = new StatsCompanionServicePuller(android::util::APP_OPS)}},
+        // SurfaceflingerStatsGlobalInfo
+        {android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+         {.puller =
+                  new SurfaceflingerStatsPuller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp b/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp
new file mode 100644
index 0000000..23b2236
--- /dev/null
+++ b/cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 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 "SurfaceflingerStatsPuller.h"
+
+#include <cutils/compiler.h>
+
+#include <numeric>
+
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+#include "statslog.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+SurfaceflingerStatsPuller::SurfaceflingerStatsPuller(const int tagId) : StatsPuller(tagId) {
+}
+
+bool SurfaceflingerStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) {
+    switch (mTagId) {
+        case android::util::SURFACEFLINGER_STATS_GLOBAL_INFO:
+            return pullGlobalInfo(data);
+        default:
+            break;
+    }
+
+    return false;
+}
+
+static int64_t getTotalTime(
+        const google::protobuf::RepeatedPtrField<surfaceflinger::SFTimeStatsHistogramBucketProto>&
+                buckets) {
+    int64_t total = 0;
+    for (const auto& bucket : buckets) {
+        if (bucket.time_millis() == 1000) {
+            continue;
+        }
+
+        total += bucket.time_millis() * bucket.frame_count();
+    }
+
+    return total;
+}
+
+bool SurfaceflingerStatsPuller::pullGlobalInfo(std::vector<std::shared_ptr<LogEvent>>* data) {
+    std::string protoBytes;
+    if (CC_UNLIKELY(mStatsProvider)) {
+        protoBytes = mStatsProvider();
+    } else {
+        std::unique_ptr<FILE, decltype(&pclose)> pipe(popen("dumpsys SurfaceFlinger --timestats -dump --proto", "r"), pclose);
+        if (!pipe.get()) {
+            return false;
+        }
+        char buf[1024];
+        size_t bytesRead = 0;
+        do {
+            bytesRead = fread(buf, 1, sizeof(buf), pipe.get());
+            protoBytes.append(buf, bytesRead);
+        } while (bytesRead > 0);
+    }
+    surfaceflinger::SFTimeStatsGlobalProto proto;
+    proto.ParseFromString(protoBytes);
+
+    int64_t totalTime = getTotalTime(proto.present_to_present());
+
+    data->clear();
+    data->reserve(1);
+    std::shared_ptr<LogEvent> event =
+            make_shared<LogEvent>(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, getWallClockNs(),
+                                  getElapsedRealtimeNs());
+    if (!event->write(proto.total_frames())) return false;
+    if (!event->write(proto.missed_frames())) return false;
+    if (!event->write(proto.client_composition_frames())) return false;
+    if (!event->write(proto.display_on_time())) return false;
+    if (!event->write(totalTime)) return false;
+    event->init();
+    data->emplace_back(event);
+
+    return true;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/external/SurfaceflingerStatsPuller.h b/cmds/statsd/src/external/SurfaceflingerStatsPuller.h
new file mode 100644
index 0000000..ed7153e
--- /dev/null
+++ b/cmds/statsd/src/external/SurfaceflingerStatsPuller.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <timestatsproto/TimeStatsProtoHeader.h>
+
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Pull metrics from Surfaceflinger
+ */
+class SurfaceflingerStatsPuller : public StatsPuller {
+public:
+    explicit SurfaceflingerStatsPuller(const int tagId);
+
+    // StatsPuller interface
+    bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override;
+
+protected:
+    // Test-only, for injecting fake data
+    using StatsProvider = std::function<std::string()>;
+    StatsProvider mStatsProvider;
+
+private:
+    bool pullGlobalInfo(std::vector<std::shared_ptr<LogEvent>>* data);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android