Loading cmds/statsd/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ cc_defaults { "src/external/StatsPuller.cpp", "src/external/StatsPullerManager.cpp", "src/external/SubsystemSleepStatePuller.cpp", "src/external/SurfaceflingerStatsPuller.cpp", "src/external/TrainInfoPuller.cpp", "src/FieldValue.cpp", "src/guardrail/StatsdStats.cpp", Loading Loading @@ -138,6 +139,7 @@ cc_defaults { "libservices", "libstatslog", "libsysutils", "libtimestats_proto", "libutils", ], } Loading Loading @@ -239,6 +241,7 @@ cc_test { "tests/external/IncidentReportArgs_test.cpp", "tests/external/puller_util_test.cpp", "tests/external/StatsPuller_test.cpp", "tests/external/SurfaceflingerStatsPuller_test.cpp", "tests/FieldValue_test.cpp", "tests/guardrail/StatsdStats_test.cpp", "tests/indexed_priority_queue_test.cpp", Loading cmds/statsd/src/external/StatsPullerManager.cpp +10 −3 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -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; Loading Loading @@ -269,6 +272,10 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // 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) { Loading cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp 0 → 100644 +99 −0 Original line number Diff line number Diff line /* * 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 cmds/statsd/src/external/SurfaceflingerStatsPuller.h 0 → 100644 +48 −0 Original line number Diff line number Diff line /* * 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 cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * 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. */ #undef LOG_TAG #define LOG_TAG "SurfaceflingerStatsPuller_test" #include "src/external/SurfaceflingerStatsPuller.h" #include <gtest/gtest.h> #include <log/log.h> #ifdef __ANDROID__ namespace android { namespace os { namespace statsd { class TestableSurfaceflingerStatsPuller : public SurfaceflingerStatsPuller { public: TestableSurfaceflingerStatsPuller(const int tagId) : SurfaceflingerStatsPuller(tagId){}; void injectStats(const StatsProvider& statsProvider) { mStatsProvider = statsProvider; } }; class SurfaceflingerStatsPullerTest : public ::testing::Test { public: SurfaceflingerStatsPullerTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); } ~SurfaceflingerStatsPullerTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } }; TEST_F(SurfaceflingerStatsPullerTest, pullGlobalStats) { surfaceflinger::SFTimeStatsGlobalProto proto; proto.set_total_frames(1); proto.set_missed_frames(2); proto.set_client_composition_frames(2); proto.set_display_on_time(4); auto bucketOne = proto.add_present_to_present(); bucketOne->set_time_millis(2); bucketOne->set_frame_count(4); auto bucketTwo = proto.add_present_to_present(); bucketTwo->set_time_millis(4); bucketTwo->set_frame_count(1); auto bucketThree = proto.add_present_to_present(); bucketThree->set_time_millis(1000); bucketThree->set_frame_count(1); static constexpr int64_t expectedAnimationMillis = 12; TestableSurfaceflingerStatsPuller puller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); puller.injectStats([&] { return proto.SerializeAsString(); }); puller.ForceClearCache(); vector<std::shared_ptr<LogEvent>> outData; puller.Pull(&outData); ASSERT_EQ(1, outData.size()); EXPECT_EQ(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, outData[0]->GetTagId()); EXPECT_EQ(proto.total_frames(), outData[0]->getValues()[0].mValue.long_value); EXPECT_EQ(proto.missed_frames(), outData[0]->getValues()[1].mValue.long_value); EXPECT_EQ(proto.client_composition_frames(), outData[0]->getValues()[2].mValue.long_value); EXPECT_EQ(proto.display_on_time(), outData[0]->getValues()[3].mValue.long_value); EXPECT_EQ(expectedAnimationMillis, outData[0]->getValues()[4].mValue.long_value); } } // namespace statsd } // namespace os } // namespace android #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif Loading
cmds/statsd/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ cc_defaults { "src/external/StatsPuller.cpp", "src/external/StatsPullerManager.cpp", "src/external/SubsystemSleepStatePuller.cpp", "src/external/SurfaceflingerStatsPuller.cpp", "src/external/TrainInfoPuller.cpp", "src/FieldValue.cpp", "src/guardrail/StatsdStats.cpp", Loading Loading @@ -138,6 +139,7 @@ cc_defaults { "libservices", "libstatslog", "libsysutils", "libtimestats_proto", "libutils", ], } Loading Loading @@ -239,6 +241,7 @@ cc_test { "tests/external/IncidentReportArgs_test.cpp", "tests/external/puller_util_test.cpp", "tests/external/StatsPuller_test.cpp", "tests/external/SurfaceflingerStatsPuller_test.cpp", "tests/FieldValue_test.cpp", "tests/guardrail/StatsdStats_test.cpp", "tests/indexed_priority_queue_test.cpp", Loading
cmds/statsd/src/external/StatsPullerManager.cpp +10 −3 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -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; Loading Loading @@ -269,6 +272,10 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // 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) { Loading
cmds/statsd/src/external/SurfaceflingerStatsPuller.cpp 0 → 100644 +99 −0 Original line number Diff line number Diff line /* * 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
cmds/statsd/src/external/SurfaceflingerStatsPuller.h 0 → 100644 +48 −0 Original line number Diff line number Diff line /* * 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
cmds/statsd/tests/external/SurfaceflingerStatsPuller_test.cpp 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * 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. */ #undef LOG_TAG #define LOG_TAG "SurfaceflingerStatsPuller_test" #include "src/external/SurfaceflingerStatsPuller.h" #include <gtest/gtest.h> #include <log/log.h> #ifdef __ANDROID__ namespace android { namespace os { namespace statsd { class TestableSurfaceflingerStatsPuller : public SurfaceflingerStatsPuller { public: TestableSurfaceflingerStatsPuller(const int tagId) : SurfaceflingerStatsPuller(tagId){}; void injectStats(const StatsProvider& statsProvider) { mStatsProvider = statsProvider; } }; class SurfaceflingerStatsPullerTest : public ::testing::Test { public: SurfaceflingerStatsPullerTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); } ~SurfaceflingerStatsPullerTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } }; TEST_F(SurfaceflingerStatsPullerTest, pullGlobalStats) { surfaceflinger::SFTimeStatsGlobalProto proto; proto.set_total_frames(1); proto.set_missed_frames(2); proto.set_client_composition_frames(2); proto.set_display_on_time(4); auto bucketOne = proto.add_present_to_present(); bucketOne->set_time_millis(2); bucketOne->set_frame_count(4); auto bucketTwo = proto.add_present_to_present(); bucketTwo->set_time_millis(4); bucketTwo->set_frame_count(1); auto bucketThree = proto.add_present_to_present(); bucketThree->set_time_millis(1000); bucketThree->set_frame_count(1); static constexpr int64_t expectedAnimationMillis = 12; TestableSurfaceflingerStatsPuller puller(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO); puller.injectStats([&] { return proto.SerializeAsString(); }); puller.ForceClearCache(); vector<std::shared_ptr<LogEvent>> outData; puller.Pull(&outData); ASSERT_EQ(1, outData.size()); EXPECT_EQ(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO, outData[0]->GetTagId()); EXPECT_EQ(proto.total_frames(), outData[0]->getValues()[0].mValue.long_value); EXPECT_EQ(proto.missed_frames(), outData[0]->getValues()[1].mValue.long_value); EXPECT_EQ(proto.client_composition_frames(), outData[0]->getValues()[2].mValue.long_value); EXPECT_EQ(proto.display_on_time(), outData[0]->getValues()[3].mValue.long_value); EXPECT_EQ(expectedAnimationMillis, outData[0]->getValues()[4].mValue.long_value); } } // namespace statsd } // namespace os } // namespace android #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif