blob: 76de7f80d7c94c9c75125e2e46d853033bc7469d [file] [log] [blame]
Ryan Savitski0feb2c82019-02-08 13:03:11 +00001
2/*
3 * Copyright (C) 2019 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Primiano Tucci2c5488f2019-06-01 03:27:28 +010018#include <gtest/gtest.h>
Ryan Savitski0feb2c82019-02-08 13:03:11 +000019#include <stdlib.h>
Primiano Tucci2c5488f2019-06-01 03:27:28 +010020#include <sys/system_properties.h>
Ryan Savitski0feb2c82019-02-08 13:03:11 +000021#include <sys/types.h>
22#include <sys/wait.h>
Ryan Savitski79e32bb2019-02-11 12:33:15 +000023
Ryan Savitski0feb2c82019-02-08 13:03:11 +000024#include "perfetto/base/logging.h"
25#include "src/base/test/test_task_runner.h"
26#include "test/test_helper.h"
27
Primiano Tucci0f2f3b42019-05-21 19:37:01 +010028#include "perfetto/config/profiling/heapprofd_config.pb.h"
29
Ryan Savitski0feb2c82019-02-08 13:03:11 +000030namespace perfetto {
31namespace {
32
33// Size of individual (repeated) allocations done by the test apps (must be kept
34// in sync with their sources).
35constexpr uint64_t kTestSamplingInterval = 4096;
36constexpr uint64_t kExpectedIndividualAllocSz = 4153;
37// Tests rely on the sampling behaviour where allocations larger than the
38// sampling interval are recorded at their actual size.
39static_assert(kExpectedIndividualAllocSz > kTestSamplingInterval,
40 "kTestSamplingInterval invalid");
41
Ryan Savitski79e32bb2019-02-11 12:33:15 +000042bool IsDebuggableBuild() {
43 char buf[PROP_VALUE_MAX + 1] = {};
44 int ret = __system_property_get("ro.debuggable", buf);
45 PERFETTO_CHECK(ret >= 0);
46 std::string debuggable(buf);
47 if (debuggable == "1")
48 return true;
49 return false;
50}
51
Ryan Savitski0feb2c82019-02-08 13:03:11 +000052// note: cannot use gtest macros due to return type
53bool IsAppRunning(const std::string& name) {
54 std::string cmd = "pgrep -f " + name;
55 int retcode = system(cmd.c_str());
56 PERFETTO_CHECK(retcode >= 0);
57 int exit_status = WEXITSTATUS(retcode);
58 if (exit_status == 0)
59 return true;
60 if (exit_status == 1)
61 return false;
62 PERFETTO_FATAL("unexpected exit status from system(pgrep): %d", exit_status);
63}
64
65// invokes |callback| once the target app is in the desired state
66void PollRunState(bool desired_run_state,
67 base::TestTaskRunner* task_runner,
68 const std::string& name,
69 std::function<void()> callback) {
70 bool app_running = IsAppRunning(name);
71 if (app_running == desired_run_state) {
72 callback();
73 return;
74 }
75 task_runner->PostTask([desired_run_state, task_runner, name, callback] {
76 PollRunState(desired_run_state, task_runner, name, std::move(callback));
77 });
78}
79
80void StartAppActivity(const std::string& app_name,
81 const std::string& checkpoint_name,
82 base::TestTaskRunner* task_runner,
83 int delay_ms = 1) {
84 std::string start_cmd = "am start " + app_name + "/.MainActivity";
85 int status = system(start_cmd.c_str());
86 ASSERT_TRUE(status >= 0 && WEXITSTATUS(status) == 0) << "status: " << status;
87
88 bool desired_run_state = true;
89 const auto checkpoint = task_runner->CreateCheckpoint(checkpoint_name);
90 task_runner->PostDelayedTask(
91 [desired_run_state, task_runner, app_name, checkpoint] {
92 PollRunState(desired_run_state, task_runner, app_name,
93 std::move(checkpoint));
94 },
95 delay_ms);
96}
97
98void StopApp(const std::string& app_name,
99 const std::string& checkpoint_name,
100 base::TestTaskRunner* task_runner) {
101 std::string stop_cmd = "am force-stop " + app_name;
102 int status = system(stop_cmd.c_str());
103 ASSERT_TRUE(status >= 0 && WEXITSTATUS(status) == 0) << "status: " << status;
104
105 bool desired_run_state = false;
106 auto checkpoint = task_runner->CreateCheckpoint(checkpoint_name);
107 task_runner->PostTask([desired_run_state, task_runner, app_name, checkpoint] {
108 PollRunState(desired_run_state, task_runner, app_name,
109 std::move(checkpoint));
110 });
111}
112
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000113std::vector<protos::TracePacket> ProfileRuntime(std::string app_name) {
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000114 base::TestTaskRunner task_runner;
115
116 // (re)start the target app's main activity
117 if (IsAppRunning(app_name)) {
118 StopApp(app_name, "old.app.stopped", &task_runner);
119 task_runner.RunUntilCheckpoint("old.app.stopped", 1000 /*ms*/);
120 }
121 StartAppActivity(app_name, "target.app.running", &task_runner,
122 /*delay_ms=*/100);
123 task_runner.RunUntilCheckpoint("target.app.running", 1000 /*ms*/);
124
125 // set up tracing
126 TestHelper helper(&task_runner);
127 helper.ConnectConsumer();
128 helper.WaitForConsumerConnect();
129
130 TraceConfig trace_config;
131 trace_config.add_buffers()->set_size_kb(10 * 1024);
132 trace_config.set_duration_ms(2000);
133
134 auto* ds_config = trace_config.add_data_sources()->mutable_config();
135 ds_config->set_name("android.heapprofd");
136 ds_config->set_target_buffer(0);
137
Primiano Tucci0f2f3b42019-05-21 19:37:01 +0100138 protos::HeapprofdConfig heapprofd_config;
139 heapprofd_config.set_sampling_interval_bytes(kTestSamplingInterval);
140 heapprofd_config.add_process_cmdline(app_name.c_str());
141 heapprofd_config.set_all(false);
142 ds_config->set_heapprofd_config_raw(heapprofd_config.SerializeAsString());
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000143
144 // start tracing
145 helper.StartTracing(trace_config);
146 helper.WaitForTracingDisabled(4000 /*ms*/);
147 helper.ReadData();
148 helper.WaitForReadData();
149
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000150 return helper.trace();
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000151}
152
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000153std::vector<protos::TracePacket> ProfileStartup(std::string app_name) {
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000154 base::TestTaskRunner task_runner;
155
156 if (IsAppRunning(app_name)) {
157 StopApp(app_name, "old.app.stopped", &task_runner);
158 task_runner.RunUntilCheckpoint("old.app.stopped", 1000 /*ms*/);
159 }
160
161 // set up tracing
162 TestHelper helper(&task_runner);
163 helper.ConnectConsumer();
164 helper.WaitForConsumerConnect();
165
166 TraceConfig trace_config;
167 trace_config.add_buffers()->set_size_kb(10 * 1024);
168 trace_config.set_duration_ms(4000);
169
170 auto* ds_config = trace_config.add_data_sources()->mutable_config();
171 ds_config->set_name("android.heapprofd");
172 ds_config->set_target_buffer(0);
173
Primiano Tucci0f2f3b42019-05-21 19:37:01 +0100174 protos::HeapprofdConfig heapprofd_config;
175 heapprofd_config.set_sampling_interval_bytes(kTestSamplingInterval);
176 heapprofd_config.add_process_cmdline(app_name.c_str());
177 heapprofd_config.set_all(false);
178 ds_config->set_heapprofd_config_raw(heapprofd_config.SerializeAsString());
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000179
180 // start tracing
181 helper.StartTracing(trace_config);
182
183 // start app
184 StartAppActivity(app_name, "target.app.running", &task_runner,
185 /*delay_ms=*/100);
186 task_runner.RunUntilCheckpoint("target.app.running", 2000 /*ms*/);
187
188 helper.WaitForTracingDisabled(8000 /*ms*/);
189 helper.ReadData();
190 helper.WaitForReadData();
191
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000192 return helper.trace();
193}
194
195void AssertExpectedAllocationsPresent(
196 std::vector<protos::TracePacket> packets) {
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000197 ASSERT_GT(packets.size(), 0);
198
199 // TODO(rsavitski): assert particular stack frames once we clarify the
200 // expected behaviour of unwinding native libs within an apk.
201 // Until then, look for an allocation that is a multiple of the expected
202 // allocation size.
203 bool found_alloc = false;
204 for (const auto& packet : packets) {
205 for (const auto& proc_dump : packet.profile_packet().process_dumps()) {
206 for (const auto& sample : proc_dump.samples()) {
207 if (sample.self_allocated() > 0 &&
208 sample.self_allocated() % kExpectedIndividualAllocSz == 0) {
209 found_alloc = true;
210
211 EXPECT_TRUE(sample.self_freed() > 0 &&
212 sample.self_freed() % kExpectedIndividualAllocSz == 0)
213 << "self_freed: " << sample.self_freed();
214 }
215 }
216 }
217 }
218 ASSERT_TRUE(found_alloc);
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000219}
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000220
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000221void AssertNoProfileContents(std::vector<protos::TracePacket> packets) {
222 // If profile packets are present, they must be empty.
223 for (const auto& packet : packets) {
224 ASSERT_EQ(packet.profile_packet().process_dumps_size(), 0);
225 }
226}
227
228void StopApp(std::string app_name) {
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000229 std::string stop_cmd = "am force-stop " + app_name;
230 system(stop_cmd.c_str());
231}
232
Ryan Savitski77bc9b92019-04-16 22:42:56 +0100233// TODO(b/118428762): look into unwinding issues on x86.
234#if defined(__i386__) || defined(__x86_64__)
235#define MAYBE_SKIP(x) DISABLED_##x
236#else
237#define MAYBE_SKIP(x) x
238#endif
Ryan Savitski640a2922019-02-21 23:04:48 +0000239
Ryan Savitski77bc9b92019-04-16 22:42:56 +0100240TEST(HeapprofdCtsTest, MAYBE_SKIP(DebuggableAppRuntime)) {
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000241 std::string app_name = "android.perfetto.cts.app.debuggable";
242 const auto& packets = ProfileRuntime(app_name);
243 AssertExpectedAllocationsPresent(packets);
244 StopApp(app_name);
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000245}
246
Ryan Savitski77bc9b92019-04-16 22:42:56 +0100247TEST(HeapprofdCtsTest, MAYBE_SKIP(DebuggableAppStartup)) {
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000248 std::string app_name = "android.perfetto.cts.app.debuggable";
249 const auto& packets = ProfileStartup(app_name);
250 AssertExpectedAllocationsPresent(packets);
251 StopApp(app_name);
252}
253
Ryan Savitski77bc9b92019-04-16 22:42:56 +0100254TEST(HeapprofdCtsTest, MAYBE_SKIP(ReleaseAppRuntime)) {
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000255 std::string app_name = "android.perfetto.cts.app.release";
256 const auto& packets = ProfileRuntime(app_name);
257
258 if (IsDebuggableBuild())
259 AssertExpectedAllocationsPresent(packets);
260 else
261 AssertNoProfileContents(packets);
262
263 StopApp(app_name);
264}
265
Ryan Savitski77bc9b92019-04-16 22:42:56 +0100266TEST(HeapprofdCtsTest, MAYBE_SKIP(ReleaseAppStartup)) {
Ryan Savitski79e32bb2019-02-11 12:33:15 +0000267 std::string app_name = "android.perfetto.cts.app.release";
268 const auto& packets = ProfileStartup(app_name);
269
270 if (IsDebuggableBuild())
271 AssertExpectedAllocationsPresent(packets);
272 else
273 AssertNoProfileContents(packets);
274
275 StopApp(app_name);
Ryan Savitski0feb2c82019-02-08 13:03:11 +0000276}
277
278} // namespace
279} // namespace perfetto