| /* | 
 |  * Copyright (C) 2018 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 "src/traced/service/builtin_producer.h" | 
 |  | 
 | #include "perfetto/tracing/core/data_source_config.h" | 
 | #include "src/base/test/test_task_runner.h" | 
 | #include "test/gtest_and_gmock.h" | 
 |  | 
 | #include "protos/perfetto/config/android/android_sdk_sysprop_guard_config.gen.h" | 
 |  | 
 | namespace perfetto { | 
 | namespace { | 
 |  | 
 | constexpr char kHeapprofdDataSourceName[] = "android.heapprofd"; | 
 | constexpr char kTracedPerfDataSourceName[] = "linux.perf"; | 
 | constexpr char kLazyHeapprofdPropertyName[] = "traced.lazy.heapprofd"; | 
 | constexpr char kLazyTracedPerfPropertyName[] = "traced.lazy.traced_perf"; | 
 |  | 
 | constexpr char kAndroidSdkSyspropGuardDataSourceName[] = | 
 |     "android.sdk_sysprop_guard"; | 
 | constexpr char kPerfettoSdkSyspropGuardGenerationPropertyName[] = | 
 |     "debug.tracing.ctl.perfetto.sdk_sysprop_guard_generation"; | 
 | constexpr char kHwuiSkiaBroadTracingPropertyName[] = | 
 |     "debug.tracing.ctl.hwui.skia_tracing_enabled"; | 
 | constexpr char kHwuiSkiaUsePerfettoPropertyName[] = | 
 |     "debug.tracing.ctl.hwui.skia_use_perfetto_track_events"; | 
 | constexpr char kHwuiSkiaPropertyPackageSeparator[] = "."; | 
 | constexpr char kSurfaceFlingerSkiaBroadTracingPropertyName[] = | 
 |     "debug.tracing.ctl.renderengine.skia_tracing_enabled"; | 
 | constexpr char kSurfaceFlingerSkiaUsePerfettoPropertyName[] = | 
 |     "debug.tracing.ctl.renderengine.skia_use_perfetto_track_events"; | 
 |  | 
 | using ::testing::_; | 
 | using ::testing::InvokeWithoutArgs; | 
 | using ::testing::Mock; | 
 | using ::testing::Return; | 
 | using ::testing::StrictMock; | 
 |  | 
 | class MockBuiltinProducer : public BuiltinProducer { | 
 |  public: | 
 |   MockBuiltinProducer(base::TaskRunner* task_runner) | 
 |       : BuiltinProducer(task_runner, /*lazy_stop_delay_ms=*/0) {} | 
 |  | 
 |   MOCK_METHOD(bool, | 
 |               SetAndroidProperty, | 
 |               (const std::string&, const std::string&), | 
 |               (override)); | 
 | }; | 
 |  | 
 | TEST(BuiltinProducerTest, LazyHeapprofdSimple) { | 
 |   DataSourceConfig cfg; | 
 |   cfg.set_name(kHeapprofdDataSourceName); | 
 |   base::TestTaskRunner task_runner; | 
 |   auto done = task_runner.CreateCheckpoint("done"); | 
 |   StrictMock<MockBuiltinProducer> p(&task_runner); | 
 |   testing::InSequence s; | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyHeapprofdPropertyName, "1")) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyHeapprofdPropertyName, "")) | 
 |       .WillOnce(InvokeWithoutArgs([&done]() { | 
 |         done(); | 
 |         return true; | 
 |       })); | 
 |   p.SetupDataSource(1, cfg); | 
 |   p.StopDataSource(1); | 
 |   task_runner.RunUntilCheckpoint("done"); | 
 | } | 
 |  | 
 | TEST(BuiltinProducerTest, LazyTracedPerfSimple) { | 
 |   DataSourceConfig cfg; | 
 |   cfg.set_name(kTracedPerfDataSourceName); | 
 |   base::TestTaskRunner task_runner; | 
 |   auto done = task_runner.CreateCheckpoint("done"); | 
 |   StrictMock<MockBuiltinProducer> p(&task_runner); | 
 |   testing::InSequence s; | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyTracedPerfPropertyName, "1")) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyTracedPerfPropertyName, "")) | 
 |       .WillOnce(InvokeWithoutArgs([&done]() { | 
 |         done(); | 
 |         return true; | 
 |       })); | 
 |   p.SetupDataSource(1, cfg); | 
 |   p.StopDataSource(1); | 
 |   task_runner.RunUntilCheckpoint("done"); | 
 | } | 
 |  | 
 | TEST(BuiltinProducerTest, LazyHeapprofdRefCount) { | 
 |   DataSourceConfig cfg; | 
 |   cfg.set_name(kHeapprofdDataSourceName); | 
 |   base::TestTaskRunner task_runner; | 
 |   auto done = task_runner.CreateCheckpoint("done"); | 
 |   StrictMock<MockBuiltinProducer> p(&task_runner); | 
 |   testing::InSequence s; | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyHeapprofdPropertyName, "1")) | 
 |       .WillRepeatedly(Return(true)); | 
 |   p.SetupDataSource(1, cfg); | 
 |   p.SetupDataSource(2, cfg); | 
 |   p.StopDataSource(2); | 
 |   task_runner.RunUntilIdle(); | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyHeapprofdPropertyName, "")) | 
 |       .WillOnce(InvokeWithoutArgs([&done]() { | 
 |         done(); | 
 |         return true; | 
 |       })); | 
 |   p.StopDataSource(1); | 
 |   task_runner.RunUntilCheckpoint("done"); | 
 | } | 
 |  | 
 | TEST(BuiltinProducerTest, LazyHeapprofdNoFlap) { | 
 |   DataSourceConfig cfg; | 
 |   cfg.set_name(kHeapprofdDataSourceName); | 
 |   base::TestTaskRunner task_runner; | 
 |   auto done = task_runner.CreateCheckpoint("done"); | 
 |   StrictMock<MockBuiltinProducer> p(&task_runner); | 
 |   testing::InSequence s; | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyHeapprofdPropertyName, "1")) | 
 |       .WillRepeatedly(Return(true)); | 
 |   p.SetupDataSource(1, cfg); | 
 |   p.StopDataSource(1); | 
 |   p.SetupDataSource(2, cfg); | 
 |   task_runner.RunUntilIdle(); | 
 |   p.StopDataSource(2); | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyHeapprofdPropertyName, "")) | 
 |       .WillOnce(InvokeWithoutArgs([&done]() { | 
 |         done(); | 
 |         return true; | 
 |       })); | 
 |   task_runner.RunUntilCheckpoint("done"); | 
 | } | 
 |  | 
 | TEST(BuiltinProducerTest, LazyRefCountsIndependent) { | 
 |   DataSourceConfig cfg_perf; | 
 |   cfg_perf.set_name(kTracedPerfDataSourceName); | 
 |   DataSourceConfig cfg_heap; | 
 |   cfg_heap.set_name(kHeapprofdDataSourceName); | 
 |  | 
 |   base::TestTaskRunner task_runner; | 
 |   StrictMock<MockBuiltinProducer> p(&task_runner); | 
 |   testing::InSequence s; | 
 |  | 
 |   // start one instance of both types of sources | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyHeapprofdPropertyName, "1")) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyTracedPerfPropertyName, "1")) | 
 |       .WillOnce(Return(true)); | 
 |   p.SetupDataSource(1, cfg_heap); | 
 |   p.SetupDataSource(2, cfg_perf); | 
 |   task_runner.RunUntilIdle(); | 
 |   Mock::VerifyAndClearExpectations(&p); | 
 |  | 
 |   // stop heapprofd source | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyHeapprofdPropertyName, "")) | 
 |       .WillOnce(Return(true)); | 
 |   p.StopDataSource(1); | 
 |   task_runner.RunUntilIdle(); | 
 |   Mock::VerifyAndClearExpectations(&p); | 
 |  | 
 |   // stop traced_perf source | 
 |   EXPECT_CALL(p, SetAndroidProperty(kLazyTracedPerfPropertyName, "")) | 
 |       .WillOnce(Return(true)); | 
 |   p.StopDataSource(2); | 
 |   task_runner.RunUntilIdle(); | 
 |   Mock::VerifyAndClearExpectations(&p); | 
 | } | 
 |  | 
 | class AndroidSdkSyspropGuardParameterizedTestFixture | 
 |     : public ::testing::TestWithParam<bool> { | 
 |  public: | 
 |   static constexpr int ITERATIONS = 3; | 
 | }; | 
 |  | 
 | TEST_P(AndroidSdkSyspropGuardParameterizedTestFixture, SurfaceFlinger) { | 
 |   bool should_enable = GetParam(); | 
 |  | 
 |   // Set SF flag in config | 
 |   protos::gen::AndroidSdkSyspropGuardConfig sysprop_guard; | 
 |   sysprop_guard.set_surfaceflinger_skia_track_events(should_enable); | 
 |  | 
 |   base::TestTaskRunner task_runner; | 
 |   StrictMock<MockBuiltinProducer> p(&task_runner); | 
 |   DataSourceConfig cfg; | 
 |   cfg.set_name(kAndroidSdkSyspropGuardDataSourceName); | 
 |   cfg.set_android_sdk_sysprop_guard_config_raw( | 
 |       sysprop_guard.SerializeAsString()); | 
 |  | 
 |   // Expect SF props set | 
 |   EXPECT_CALL(p, SetAndroidProperty(kSurfaceFlingerSkiaBroadTracingPropertyName, | 
 |                                     "true")) | 
 |       .Times(should_enable ? 1 : 0) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL( | 
 |       p, SetAndroidProperty(kSurfaceFlingerSkiaUsePerfettoPropertyName, "true")) | 
 |       .Times(should_enable ? 1 : 0) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL(p, SetAndroidProperty( | 
 |                      kPerfettoSdkSyspropGuardGenerationPropertyName, "1")) | 
 |       .Times(should_enable ? 1 : 0) | 
 |       .WillOnce(Return(true)); | 
 |  | 
 |   // Sysprops should only be set once given the same config | 
 |   for (int i = 0; i < ITERATIONS; i++) { | 
 |     p.SetupDataSource(1, cfg); | 
 |     p.StopDataSource(1); | 
 |     task_runner.RunUntilIdle(); | 
 |   } | 
 |   Mock::VerifyAndClearExpectations(&p); | 
 | } | 
 |  | 
 | TEST_P(AndroidSdkSyspropGuardParameterizedTestFixture, HwuiGlobal) { | 
 |   bool should_enable = GetParam(); | 
 |  | 
 |   // Set HWUI flag in config. | 
 |   // The package filter is left BLANK so this applies GLOBALLY. | 
 |   protos::gen::AndroidSdkSyspropGuardConfig sysprop_guard; | 
 |   sysprop_guard.set_hwui_skia_track_events(should_enable); | 
 |  | 
 |   base::TestTaskRunner task_runner; | 
 |   StrictMock<MockBuiltinProducer> p(&task_runner); | 
 |   DataSourceConfig cfg; | 
 |   cfg.set_name(kAndroidSdkSyspropGuardDataSourceName); | 
 |   cfg.set_android_sdk_sysprop_guard_config_raw( | 
 |       sysprop_guard.SerializeAsString()); | 
 |  | 
 |   // Expect GLOBAL props set for HWUI. | 
 |   EXPECT_CALL(p, SetAndroidProperty(kHwuiSkiaBroadTracingPropertyName, "true")) | 
 |       .Times(should_enable ? 1 : 0) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL(p, SetAndroidProperty(kHwuiSkiaUsePerfettoPropertyName, "true")) | 
 |       .Times(should_enable ? 1 : 0) | 
 |       .WillOnce(Return(true)); | 
 |   EXPECT_CALL(p, SetAndroidProperty( | 
 |                      kPerfettoSdkSyspropGuardGenerationPropertyName, "1")) | 
 |       .Times(should_enable ? 1 : 0) | 
 |       .WillOnce(Return(true)); | 
 |  | 
 |   // Sysprops should only be set once given the same config | 
 |   for (int i = 0; i < ITERATIONS; i++) { | 
 |     p.SetupDataSource(1, cfg); | 
 |     p.StopDataSource(1); | 
 |     task_runner.RunUntilIdle(); | 
 |   } | 
 |   Mock::VerifyAndClearExpectations(&p); | 
 | } | 
 |  | 
 | TEST_P(AndroidSdkSyspropGuardParameterizedTestFixture, HwuiPackageFiltered) { | 
 |   bool should_enable = GetParam(); | 
 |  | 
 |   std::string packages[] = {"test1", "com.android.systemui", "test3"}; | 
 |   // Set HWUI flag in config. Package filter left blank. | 
 |   // The package filter is SET so this applies SELECTIVELY. | 
 |   protos::gen::AndroidSdkSyspropGuardConfig sysprop_guard; | 
 |   sysprop_guard.set_hwui_skia_track_events(should_enable); | 
 |   for (std::string package : packages) { | 
 |     sysprop_guard.add_hwui_package_name_filter(package); | 
 |   } | 
 |  | 
 |   base::TestTaskRunner task_runner; | 
 |   StrictMock<MockBuiltinProducer> p(&task_runner); | 
 |   DataSourceConfig cfg; | 
 |   cfg.set_name(kAndroidSdkSyspropGuardDataSourceName); | 
 |   cfg.set_android_sdk_sysprop_guard_config_raw( | 
 |       sysprop_guard.SerializeAsString()); | 
 |  | 
 |   // Expect APP-SPECIFIC props set for HWUI. | 
 |   for (std::string package : packages) { | 
 |     EXPECT_CALL( | 
 |         p, SetAndroidProperty(kHwuiSkiaBroadTracingPropertyName + | 
 |                                   (kHwuiSkiaPropertyPackageSeparator + package), | 
 |                               "true")) | 
 |         .Times(should_enable ? 1 : 0) | 
 |         .WillOnce(Return(true)); | 
 |     EXPECT_CALL( | 
 |         p, SetAndroidProperty(kHwuiSkiaUsePerfettoPropertyName + | 
 |                                   (kHwuiSkiaPropertyPackageSeparator + package), | 
 |                               "true")) | 
 |         .Times(should_enable ? 1 : 0) | 
 |         .WillOnce(Return(true)); | 
 |   } | 
 |   EXPECT_CALL(p, SetAndroidProperty( | 
 |                      kPerfettoSdkSyspropGuardGenerationPropertyName, "1")) | 
 |       .Times(should_enable ? 1 : 0) | 
 |       .WillOnce(Return(true)); | 
 |  | 
 |   // Sysprops should only be set once given the same config | 
 |   for (int i = 0; i < ITERATIONS; i++) { | 
 |     p.SetupDataSource(1, cfg); | 
 |     p.StopDataSource(1); | 
 |     task_runner.RunUntilIdle(); | 
 |   } | 
 |   Mock::VerifyAndClearExpectations(&p); | 
 | } | 
 |  | 
 | INSTANTIATE_TEST_SUITE_P(BuiltinProducerTest, | 
 |                          AndroidSdkSyspropGuardParameterizedTestFixture, | 
 |                          testing::Values(true, false)); | 
 |  | 
 | }  // namespace | 
 | }  // namespace perfetto |