1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "dumpstate_test"
18
19 #include "dumpstate.h"
20
21 #include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
22 #include <android-base/file.h>
23 #include <android-base/properties.h>
24 #include <android-base/stringprintf.h>
25 #include <android-base/strings.h>
26 #include <android-base/unique_fd.h>
27 #include <android/hardware/dumpstate/1.1/types.h>
28 #include <android_tracing.h>
29 #include <cutils/log.h>
30 #include <cutils/properties.h>
31 #include <fcntl.h>
32 #include <gmock/gmock-matchers.h>
33 #include <gmock/gmock.h>
34 #include <gtest/gtest.h>
35 #include <libgen.h>
36 #include <signal.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <ziparchive/zip_archive.h>
40
41 #include <filesystem>
42 #include <thread>
43
44 #include "DumpPool.h"
45 #include "DumpstateInternal.h"
46 #include "DumpstateService.h"
47 #include "android/os/BnDumpstate.h"
48
49 namespace android {
50 namespace os {
51 namespace dumpstate {
52
53 using DumpstateDeviceAidl = ::aidl::android::hardware::dumpstate::IDumpstateDevice;
54 using ::android::hardware::dumpstate::V1_1::DumpstateMode;
55 using ::testing::EndsWith;
56 using ::testing::Eq;
57 using ::testing::HasSubstr;
58 using ::testing::IsEmpty;
59 using ::testing::IsNull;
60 using ::testing::NotNull;
61 using ::testing::StartsWith;
62 using ::testing::StrEq;
63 using ::testing::Test;
64 using ::testing::internal::CaptureStderr;
65 using ::testing::internal::CaptureStdout;
66 using ::testing::internal::GetCapturedStderr;
67 using ::testing::internal::GetCapturedStdout;
68
69 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
70
71 class DumpstateListenerMock : public IDumpstateListener {
72 public:
73 MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
74 MOCK_METHOD1(onError, binder::Status(int32_t error_code));
75 MOCK_METHOD1(onFinished, binder::Status(const std::string& bugreport_file));
76 MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success));
77 MOCK_METHOD0(onUiIntensiveBugreportDumpsFinished, binder::Status());
78
79 protected:
80 MOCK_METHOD0(onAsBinder, IBinder*());
81 };
82
83 static int calls_;
84
85 // Base class for all tests in this file
86 class DumpstateBaseTest : public Test {
87 public:
SetUp()88 virtual void SetUp() override {
89 calls_++;
90 SetDryRun(false);
91 }
92
SetDryRun(bool dry_run) const93 void SetDryRun(bool dry_run) const {
94 PropertiesHelper::dry_run_ = dry_run;
95 }
96
SetBuildType(const std::string & build_type) const97 void SetBuildType(const std::string& build_type) const {
98 PropertiesHelper::build_type_ = build_type;
99 }
100
SetUnroot(bool unroot) const101 void SetUnroot(bool unroot) const {
102 PropertiesHelper::unroot_ = unroot;
103 }
104
SetParallelRun(bool parallel_run) const105 void SetParallelRun(bool parallel_run) const {
106 PropertiesHelper::parallel_run_ = parallel_run;
107 }
108
IsStandalone() const109 bool IsStandalone() const {
110 return calls_ == 1;
111 }
112
DropRoot() const113 void DropRoot() const {
114 DropRootUser();
115 uid_t uid = getuid();
116 ASSERT_EQ(2000, (int)uid);
117 }
118
119 protected:
120 const std::string kTestPath = dirname(android::base::GetExecutablePath().c_str());
121 const std::string kTestDataPath = kTestPath + "/tests/testdata/";
122 const std::string kSimpleCommand = kTestPath + "/dumpstate_test_fixture";
123 const std::string kEchoCommand = "/system/bin/echo";
124
125 /*
126 * Copies a text file fixture to a temporary file, returning it's path.
127 *
128 * Useful in cases where the test case changes the content of the tile.
129 */
CopyTextFileFixture(const std::string & relative_name)130 std::string CopyTextFileFixture(const std::string& relative_name) {
131 std::string from = kTestDataPath + relative_name;
132 // Not using TemporaryFile because it's deleted at the end, and it's useful to keep it
133 // around for poking when the test fails.
134 std::string to = kTestDataPath + relative_name + ".tmp";
135 ALOGD("CopyTextFileFixture: from %s to %s\n", from.c_str(), to.c_str());
136 android::base::RemoveFileIfExists(to);
137 CopyTextFile(from, to);
138 return to.c_str();
139 }
140
141 // Need functions that returns void to use assertions -
142 // https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#assertion-placement
ReadFileToString(const std::string & path,std::string * content)143 void ReadFileToString(const std::string& path, std::string* content) {
144 ASSERT_TRUE(android::base::ReadFileToString(path, content))
145 << "could not read contents from " << path;
146 }
WriteStringToFile(const std::string & content,const std::string & path)147 void WriteStringToFile(const std::string& content, const std::string& path) {
148 ASSERT_TRUE(android::base::WriteStringToFile(content, path))
149 << "could not write contents to " << path;
150 }
151
152 private:
CopyTextFile(const std::string & from,const std::string & to)153 void CopyTextFile(const std::string& from, const std::string& to) {
154 std::string content;
155 ReadFileToString(from, &content);
156 WriteStringToFile(content, to);
157 }
158 };
159
160 class DumpOptionsTest : public Test {
161 public:
~DumpOptionsTest()162 virtual ~DumpOptionsTest() {
163 }
SetUp()164 virtual void SetUp() {
165 options_ = Dumpstate::DumpOptions();
166 }
TearDown()167 void TearDown() {
168 }
169 Dumpstate::DumpOptions options_;
170 android::base::unique_fd fd;
171 };
172
TEST_F(DumpOptionsTest,InitializeNone)173 TEST_F(DumpOptionsTest, InitializeNone) {
174 // clang-format off
175 char* argv[] = {
176 const_cast<char*>("dumpstate")
177 };
178 // clang-format on
179
180 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
181
182 EXPECT_EQ(status, Dumpstate::RunStatus::OK);
183
184 EXPECT_EQ("", options_.out_dir);
185 EXPECT_FALSE(options_.stream_to_socket);
186 EXPECT_FALSE(options_.progress_updates_to_socket);
187 EXPECT_FALSE(options_.show_header_only);
188 EXPECT_TRUE(options_.do_vibrate);
189 EXPECT_FALSE(options_.do_screenshot);
190 EXPECT_FALSE(options_.do_progress_updates);
191 EXPECT_FALSE(options_.is_remote_mode);
192 EXPECT_FALSE(options_.limited_only);
193 }
194
TEST_F(DumpOptionsTest,InitializeAdbBugreport)195 TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
196 // clang-format off
197 char* argv[] = {
198 const_cast<char*>("dumpstatez"),
199 const_cast<char*>("-S"),
200 };
201 // clang-format on
202
203 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
204
205 EXPECT_EQ(status, Dumpstate::RunStatus::OK);
206 EXPECT_TRUE(options_.progress_updates_to_socket);
207
208 // Other options retain default values
209 EXPECT_TRUE(options_.do_vibrate);
210 EXPECT_FALSE(options_.show_header_only);
211 EXPECT_FALSE(options_.do_screenshot);
212 EXPECT_FALSE(options_.do_progress_updates);
213 EXPECT_FALSE(options_.is_remote_mode);
214 EXPECT_FALSE(options_.stream_to_socket);
215 EXPECT_FALSE(options_.limited_only);
216 }
217
TEST_F(DumpOptionsTest,InitializeAdbShellBugreport)218 TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
219 // clang-format off
220 char* argv[] = {
221 const_cast<char*>("dumpstate"),
222 const_cast<char*>("-s"),
223 };
224 // clang-format on
225
226 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
227
228 EXPECT_EQ(status, Dumpstate::RunStatus::OK);
229 EXPECT_TRUE(options_.stream_to_socket);
230
231 // Other options retain default values
232 EXPECT_TRUE(options_.do_vibrate);
233 EXPECT_FALSE(options_.progress_updates_to_socket);
234 EXPECT_FALSE(options_.show_header_only);
235 EXPECT_FALSE(options_.do_screenshot);
236 EXPECT_FALSE(options_.do_progress_updates);
237 EXPECT_FALSE(options_.is_remote_mode);
238 EXPECT_FALSE(options_.limited_only);
239 }
240
TEST_F(DumpOptionsTest,InitializeFullBugReport)241 TEST_F(DumpOptionsTest, InitializeFullBugReport) {
242 options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, 0, fd, fd, true, false);
243 EXPECT_TRUE(options_.do_screenshot);
244
245 // Other options retain default values
246 EXPECT_TRUE(options_.do_vibrate);
247 EXPECT_FALSE(options_.progress_updates_to_socket);
248 EXPECT_FALSE(options_.show_header_only);
249 EXPECT_FALSE(options_.do_progress_updates);
250 EXPECT_FALSE(options_.is_remote_mode);
251 EXPECT_FALSE(options_.stream_to_socket);
252 EXPECT_FALSE(options_.limited_only);
253 }
254
TEST_F(DumpOptionsTest,InitializeInteractiveBugReport)255 TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
256 options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, 0, fd, fd, true, false);
257 EXPECT_TRUE(options_.do_progress_updates);
258 EXPECT_TRUE(options_.do_screenshot);
259
260 // Other options retain default values
261 EXPECT_TRUE(options_.do_vibrate);
262 EXPECT_FALSE(options_.progress_updates_to_socket);
263 EXPECT_FALSE(options_.show_header_only);
264 EXPECT_FALSE(options_.is_remote_mode);
265 EXPECT_FALSE(options_.stream_to_socket);
266 EXPECT_FALSE(options_.limited_only);
267 }
268
TEST_F(DumpOptionsTest,InitializeRemoteBugReport)269 TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
270 options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, 0, fd, fd, false, false);
271 EXPECT_TRUE(options_.is_remote_mode);
272 EXPECT_FALSE(options_.do_vibrate);
273 EXPECT_FALSE(options_.do_screenshot);
274
275 // Other options retain default values
276 EXPECT_FALSE(options_.progress_updates_to_socket);
277 EXPECT_FALSE(options_.show_header_only);
278 EXPECT_FALSE(options_.do_progress_updates);
279 EXPECT_FALSE(options_.stream_to_socket);
280 EXPECT_FALSE(options_.limited_only);
281 }
282
TEST_F(DumpOptionsTest,InitializeWearBugReport)283 TEST_F(DumpOptionsTest, InitializeWearBugReport) {
284 options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, 0, fd, fd, true, false);
285 EXPECT_TRUE(options_.do_screenshot);
286 EXPECT_TRUE(options_.do_progress_updates);
287
288
289 // Other options retain default values
290 EXPECT_FALSE(options_.progress_updates_to_socket);
291 EXPECT_FALSE(options_.do_vibrate);
292 EXPECT_FALSE(options_.show_header_only);
293 EXPECT_FALSE(options_.is_remote_mode);
294 EXPECT_FALSE(options_.stream_to_socket);
295 EXPECT_FALSE(options_.limited_only);
296 }
297
TEST_F(DumpOptionsTest,InitializeTelephonyBugReport)298 TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
299 options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, 0, fd, fd, false, false);
300 EXPECT_FALSE(options_.do_screenshot);
301 EXPECT_TRUE(options_.telephony_only);
302 EXPECT_TRUE(options_.do_progress_updates);
303
304 // Other options retain default values
305 EXPECT_TRUE(options_.do_vibrate);
306 EXPECT_FALSE(options_.progress_updates_to_socket);
307 EXPECT_FALSE(options_.show_header_only);
308 EXPECT_FALSE(options_.is_remote_mode);
309 EXPECT_FALSE(options_.stream_to_socket);
310 EXPECT_FALSE(options_.limited_only);
311 }
312
TEST_F(DumpOptionsTest,InitializeWifiBugReport)313 TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
314 options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, 0, fd, fd, false, false);
315 EXPECT_FALSE(options_.do_screenshot);
316 EXPECT_TRUE(options_.wifi_only);
317
318 // Other options retain default values
319 EXPECT_TRUE(options_.do_vibrate);
320 EXPECT_FALSE(options_.progress_updates_to_socket);
321 EXPECT_FALSE(options_.show_header_only);
322 EXPECT_FALSE(options_.do_progress_updates);
323 EXPECT_FALSE(options_.is_remote_mode);
324 EXPECT_FALSE(options_.stream_to_socket);
325 EXPECT_FALSE(options_.limited_only);
326 }
327
TEST_F(DumpOptionsTest,InitializeLimitedOnlyBugreport)328 TEST_F(DumpOptionsTest, InitializeLimitedOnlyBugreport) {
329 // clang-format off
330 char* argv[] = {
331 const_cast<char*>("dumpstatez"),
332 const_cast<char*>("-S"),
333 const_cast<char*>("-q"),
334 const_cast<char*>("-L"),
335 const_cast<char*>("-o abc")
336 };
337 // clang-format on
338
339 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
340
341 EXPECT_EQ(status, Dumpstate::RunStatus::OK);
342 EXPECT_TRUE(options_.progress_updates_to_socket);
343 EXPECT_FALSE(options_.do_vibrate);
344 EXPECT_TRUE(options_.limited_only);
345 EXPECT_EQ(" abc", std::string(options_.out_dir));
346
347 // Other options retain default values
348 EXPECT_FALSE(options_.show_header_only);
349 EXPECT_FALSE(options_.do_screenshot);
350 EXPECT_FALSE(options_.do_progress_updates);
351 EXPECT_FALSE(options_.is_remote_mode);
352 EXPECT_FALSE(options_.stream_to_socket);
353 }
354
TEST_F(DumpOptionsTest,InitializeDefaultBugReport)355 TEST_F(DumpOptionsTest, InitializeDefaultBugReport) {
356 // default: commandline options are not overridden
357 // clang-format off
358 char* argv[] = {
359 const_cast<char*>("bugreport"),
360 const_cast<char*>("-d"),
361 const_cast<char*>("-p"),
362 const_cast<char*>("-z"),
363 };
364 // clang-format on
365 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
366
367 EXPECT_EQ(status, Dumpstate::RunStatus::OK);
368 EXPECT_TRUE(options_.do_screenshot);
369
370 // Other options retain default values
371 EXPECT_TRUE(options_.do_vibrate);
372 EXPECT_FALSE(options_.progress_updates_to_socket);
373 EXPECT_FALSE(options_.show_header_only);
374 EXPECT_FALSE(options_.do_progress_updates);
375 EXPECT_FALSE(options_.is_remote_mode);
376 EXPECT_FALSE(options_.stream_to_socket);
377 EXPECT_FALSE(options_.wifi_only);
378 EXPECT_FALSE(options_.limited_only);
379 }
380
TEST_F(DumpOptionsTest,InitializePartial1)381 TEST_F(DumpOptionsTest, InitializePartial1) {
382 // clang-format off
383 char* argv[] = {
384 const_cast<char*>("dumpstate"),
385 const_cast<char*>("-s"),
386 const_cast<char*>("-S"),
387
388 };
389 // clang-format on
390
391 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
392
393 EXPECT_EQ(status, Dumpstate::RunStatus::OK);
394 // TODO: Maybe we should trim the filename
395 EXPECT_TRUE(options_.stream_to_socket);
396 EXPECT_TRUE(options_.progress_updates_to_socket);
397
398 // Other options retain default values
399 EXPECT_FALSE(options_.show_header_only);
400 EXPECT_TRUE(options_.do_vibrate);
401 EXPECT_FALSE(options_.do_screenshot);
402 EXPECT_FALSE(options_.do_progress_updates);
403 EXPECT_FALSE(options_.is_remote_mode);
404 EXPECT_FALSE(options_.limited_only);
405 }
406
TEST_F(DumpOptionsTest,InitializePartial2)407 TEST_F(DumpOptionsTest, InitializePartial2) {
408 // clang-format off
409 char* argv[] = {
410 const_cast<char*>("dumpstate"),
411 const_cast<char*>("-v"),
412 const_cast<char*>("-q"),
413 const_cast<char*>("-p"),
414 const_cast<char*>("-P"),
415 const_cast<char*>("-R"),
416 };
417 // clang-format on
418
419 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
420
421 EXPECT_EQ(status, Dumpstate::RunStatus::OK);
422 EXPECT_TRUE(options_.show_header_only);
423 EXPECT_FALSE(options_.do_vibrate);
424 EXPECT_TRUE(options_.do_screenshot);
425 EXPECT_TRUE(options_.do_progress_updates);
426 EXPECT_TRUE(options_.is_remote_mode);
427
428 // Other options retain default values
429 EXPECT_FALSE(options_.stream_to_socket);
430 EXPECT_FALSE(options_.progress_updates_to_socket);
431 EXPECT_FALSE(options_.limited_only);
432 }
433
TEST_F(DumpOptionsTest,InitializeHelp)434 TEST_F(DumpOptionsTest, InitializeHelp) {
435 // clang-format off
436 char* argv[] = {
437 const_cast<char*>("dumpstate"),
438 const_cast<char*>("-h")
439 };
440 // clang-format on
441
442 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
443
444 // -h is for help.
445 EXPECT_EQ(status, Dumpstate::RunStatus::HELP);
446 }
447
TEST_F(DumpOptionsTest,InitializeUnknown)448 TEST_F(DumpOptionsTest, InitializeUnknown) {
449 // clang-format off
450 char* argv[] = {
451 const_cast<char*>("dumpstate"),
452 const_cast<char*>("-u") // unknown flag
453 };
454 // clang-format on
455
456 Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
457
458 // -u is unknown.
459 EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
460 }
461
TEST_F(DumpOptionsTest,ValidateOptionsSocketUsage1)462 TEST_F(DumpOptionsTest, ValidateOptionsSocketUsage1) {
463 options_.progress_updates_to_socket = true;
464 options_.stream_to_socket = true;
465 EXPECT_FALSE(options_.ValidateOptions());
466
467 options_.stream_to_socket = false;
468 EXPECT_TRUE(options_.ValidateOptions());
469 }
470
TEST_F(DumpOptionsTest,ValidateOptionsSocketUsage2)471 TEST_F(DumpOptionsTest, ValidateOptionsSocketUsage2) {
472 options_.do_progress_updates = true;
473 // Writing to socket = !writing to file.
474 options_.stream_to_socket = true;
475 EXPECT_FALSE(options_.ValidateOptions());
476
477 options_.stream_to_socket = false;
478 EXPECT_TRUE(options_.ValidateOptions());
479 }
480
TEST_F(DumpOptionsTest,ValidateOptionsRemoteMode)481 TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
482 options_.do_progress_updates = true;
483 options_.is_remote_mode = true;
484 EXPECT_FALSE(options_.ValidateOptions());
485
486 options_.do_progress_updates = false;
487 EXPECT_TRUE(options_.ValidateOptions());
488 }
489
TEST_F(DumpOptionsTest,InitializeBugreportFlags)490 TEST_F(DumpOptionsTest, InitializeBugreportFlags) {
491 int flags = Dumpstate::BugreportFlag::BUGREPORT_USE_PREDUMPED_UI_DATA |
492 Dumpstate::BugreportFlag::BUGREPORT_FLAG_DEFER_CONSENT;
493 options_.Initialize(
494 Dumpstate::BugreportMode::BUGREPORT_FULL, flags, fd, fd, true, false);
495 EXPECT_TRUE(options_.is_consent_deferred);
496 EXPECT_TRUE(options_.use_predumped_ui_data);
497
498 options_.Initialize(
499 Dumpstate::BugreportMode::BUGREPORT_FULL, 0, fd, fd, true, false);
500 EXPECT_FALSE(options_.is_consent_deferred);
501 EXPECT_FALSE(options_.use_predumped_ui_data);
502 }
503
504 class DumpstateTest : public DumpstateBaseTest {
505 public:
SetUp()506 void SetUp() {
507 DumpstateBaseTest::SetUp();
508 SetDryRun(false);
509 SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
510 ds.progress_.reset(new Progress());
511 ds.options_.reset(new Dumpstate::DumpOptions());
512 }
513
TearDown()514 void TearDown() {
515 ds.ShutdownDumpPool();
516 }
517
518 // Runs a command and capture `stdout` and `stderr`.
RunCommand(const std::string & title,const std::vector<std::string> & full_command,const CommandOptions & options=CommandOptions::DEFAULT)519 int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
520 const CommandOptions& options = CommandOptions::DEFAULT) {
521 CaptureStdout();
522 CaptureStderr();
523 int status = ds.RunCommand(title, full_command, options);
524 out = GetCapturedStdout();
525 err = GetCapturedStderr();
526 return status;
527 }
528
529 // Dumps a file and capture `stdout` and `stderr`.
DumpFile(const std::string & title,const std::string & path)530 int DumpFile(const std::string& title, const std::string& path) {
531 CaptureStdout();
532 CaptureStderr();
533 int status = ds.DumpFile(title, path);
534 out = GetCapturedStdout();
535 err = GetCapturedStderr();
536 return status;
537 }
538
SetProgress(long progress,long initial_max)539 void SetProgress(long progress, long initial_max) {
540 ds.last_reported_percent_progress_ = 0;
541 ds.options_->do_progress_updates = true;
542 ds.progress_.reset(new Progress(initial_max, progress, 1.2));
543 }
544
EnableParallelRunIfNeeded()545 void EnableParallelRunIfNeeded() {
546 ds.EnableParallelRunIfNeeded();
547 }
548
GetProgressMessage(int progress,int max,int old_max=0,bool update_progress=true)549 std::string GetProgressMessage(int progress, int max,
550 int old_max = 0, bool update_progress = true) {
551 EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
552 EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max";
553
554 bool max_increased = old_max > 0;
555
556 std::string message = "";
557 if (max_increased) {
558 message =
559 android::base::StringPrintf("Adjusting max progress from %d to %d\n", old_max, max);
560 }
561
562 if (update_progress) {
563 message += android::base::StringPrintf("Setting progress: %d/%d (%d%%)\n",
564 progress, max, (100 * progress / max));
565 }
566
567 return message;
568 }
569
570 // `stdout` and `stderr` from the last command ran.
571 std::string out, err;
572
573 Dumpstate& ds = Dumpstate::GetInstance();
574 };
575
TEST_F(DumpstateTest,RunCommandNoArgs)576 TEST_F(DumpstateTest, RunCommandNoArgs) {
577 EXPECT_EQ(-1, RunCommand("", {}));
578 }
579
TEST_F(DumpstateTest,RunCommandNoTitle)580 TEST_F(DumpstateTest, RunCommandNoTitle) {
581 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
582 EXPECT_THAT(out, StrEq("stdout\n"));
583 EXPECT_THAT(err, StrEq("stderr\n"));
584 }
585
TEST_F(DumpstateTest,RunCommandWithTitle)586 TEST_F(DumpstateTest, RunCommandWithTitle) {
587 EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
588 EXPECT_THAT(err, StrEq("stderr\n"));
589 // The duration may not get output, depending on how long it takes,
590 // so we just check the prefix.
591 EXPECT_THAT(out,
592 StartsWith("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n"));
593 }
594
TEST_F(DumpstateTest,RunCommandWithLoggingMessage)595 TEST_F(DumpstateTest, RunCommandWithLoggingMessage) {
596 EXPECT_EQ(
597 0, RunCommand("", {kSimpleCommand},
598 CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
599 EXPECT_THAT(out, StrEq("stdout\n"));
600 EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
601 }
602
TEST_F(DumpstateTest,RunCommandRedirectStderr)603 TEST_F(DumpstateTest, RunCommandRedirectStderr) {
604 EXPECT_EQ(0, RunCommand("", {kSimpleCommand},
605 CommandOptions::WithTimeout(10).RedirectStderr().Build()));
606 EXPECT_THAT(out, IsEmpty());
607 EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
608 }
609
TEST_F(DumpstateTest,RunCommandWithOneArg)610 TEST_F(DumpstateTest, RunCommandWithOneArg) {
611 EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one"}));
612 EXPECT_THAT(err, IsEmpty());
613 EXPECT_THAT(out, StrEq("one\n"));
614 }
615
TEST_F(DumpstateTest,RunCommandWithMultipleArgs)616 TEST_F(DumpstateTest, RunCommandWithMultipleArgs) {
617 EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one", "is", "the", "loniest", "number"}));
618 EXPECT_THAT(err, IsEmpty());
619 EXPECT_THAT(out, StrEq("one is the loniest number\n"));
620 }
621
TEST_F(DumpstateTest,RunCommandDryRun)622 TEST_F(DumpstateTest, RunCommandDryRun) {
623 SetDryRun(true);
624 EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
625 // The duration may not get output, depending on how long it takes,
626 // so we just check the prefix.
627 EXPECT_THAT(out, StartsWith("------ I AM GROOT (" + kSimpleCommand +
628 ") ------\n\t(skipped on dry run)\n"));
629 EXPECT_THAT(err, IsEmpty());
630 }
631
TEST_F(DumpstateTest,RunCommandDryRunNoTitle)632 TEST_F(DumpstateTest, RunCommandDryRunNoTitle) {
633 SetDryRun(true);
634 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
635 EXPECT_THAT(out, IsEmpty());
636 EXPECT_THAT(err, IsEmpty());
637 }
638
TEST_F(DumpstateTest,RunCommandDryRunAlways)639 TEST_F(DumpstateTest, RunCommandDryRunAlways) {
640 SetDryRun(true);
641 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
642 EXPECT_THAT(out, StrEq("stdout\n"));
643 EXPECT_THAT(err, StrEq("stderr\n"));
644 }
645
TEST_F(DumpstateTest,RunCommandNotFound)646 TEST_F(DumpstateTest, RunCommandNotFound) {
647 EXPECT_NE(0, RunCommand("", {"/there/cannot/be/such/command"}));
648 EXPECT_THAT(out, StartsWith("*** command '/there/cannot/be/such/command' failed: exit code"));
649 EXPECT_THAT(err, StartsWith("execvp on command '/there/cannot/be/such/command' failed"));
650 }
651
TEST_F(DumpstateTest,RunCommandFails)652 TEST_F(DumpstateTest, RunCommandFails) {
653 EXPECT_EQ(42, RunCommand("", {kSimpleCommand, "--exit", "42"}));
654 EXPECT_THAT(out, StrEq("stdout\n*** command '" + kSimpleCommand +
655 " --exit 42' failed: exit code 42\n"));
656 EXPECT_THAT(err, StrEq("stderr\n*** command '" + kSimpleCommand +
657 " --exit 42' failed: exit code 42\n"));
658 }
659
TEST_F(DumpstateTest,RunCommandCrashes)660 TEST_F(DumpstateTest, RunCommandCrashes) {
661 EXPECT_NE(0, RunCommand("", {kSimpleCommand, "--crash"}));
662 // We don't know the exit code, so check just the prefix.
663 EXPECT_THAT(
664 out, StartsWith("stdout\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
665 EXPECT_THAT(
666 err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
667 }
668
TEST_F(DumpstateTest,RunCommandTimesout)669 TEST_F(DumpstateTest, RunCommandTimesout) {
670 EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
671 CommandOptions::WithTimeout(1).Build()));
672 EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
673 " --sleep 2' timed out after 1"));
674 EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
675 " --sleep 2' timed out after 1"));
676 }
677
TEST_F(DumpstateTest,RunCommandIsKilled)678 TEST_F(DumpstateTest, RunCommandIsKilled) {
679 CaptureStdout();
680 CaptureStderr();
681
682 std::thread t([=]() {
683 EXPECT_EQ(SIGTERM, ds.RunCommand("", {kSimpleCommand, "--pid", "--sleep", "20"},
684 CommandOptions::WithTimeout(100).Always().Build()));
685 });
686
687 // Capture pid and pre-sleep output.
688 sleep(1); // Wait a little bit to make sure pid and 1st line were printed.
689 std::string err = GetCapturedStderr();
690 EXPECT_THAT(err, StrEq("sleeping for 20s\n"));
691
692 std::string out = GetCapturedStdout();
693 std::vector<std::string> lines = android::base::Split(out, "\n");
694 ASSERT_EQ(3, (int)lines.size()) << "Invalid lines before sleep: " << out;
695
696 int pid = atoi(lines[0].c_str());
697 EXPECT_THAT(lines[1], StrEq("stdout line1"));
698 EXPECT_THAT(lines[2], IsEmpty()); // \n
699
700 // Then kill the process.
701 CaptureStdout();
702 CaptureStderr();
703 ASSERT_EQ(0, kill(pid, SIGTERM)) << "failed to kill pid " << pid;
704 t.join();
705
706 // Finally, check output after murder.
707 out = GetCapturedStdout();
708 err = GetCapturedStderr();
709
710 EXPECT_THAT(out, StrEq("*** command '" + kSimpleCommand +
711 " --pid --sleep 20' failed: killed by signal 15\n"));
712 EXPECT_THAT(err, StrEq("*** command '" + kSimpleCommand +
713 " --pid --sleep 20' failed: killed by signal 15\n"));
714 }
715
TEST_F(DumpstateTest,RunCommandProgress)716 TEST_F(DumpstateTest, RunCommandProgress) {
717 sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
718 ds.listener_ = listener;
719 SetProgress(0, 30);
720
721 EXPECT_CALL(*listener, onProgress(66)); // 20/30 %
722 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
723 std::string progress_message = GetProgressMessage(20, 30);
724 EXPECT_THAT(out, StrEq("stdout\n"));
725 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
726
727 EXPECT_CALL(*listener, onProgress(80)); // 24/30 %
728 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
729 progress_message = GetProgressMessage(24, 30);
730 EXPECT_THAT(out, StrEq("stdout\n"));
731 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
732
733 // Make sure command ran while in dry_run is counted.
734 SetDryRun(true);
735 EXPECT_CALL(*listener, onProgress(90)); // 27/30 %
736 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
737 progress_message = GetProgressMessage(27, 30);
738 EXPECT_THAT(out, IsEmpty());
739 EXPECT_THAT(err, StrEq(progress_message));
740
741 SetDryRun(false);
742 EXPECT_CALL(*listener, onProgress(96)); // 29/30 %
743 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build()));
744 progress_message = GetProgressMessage(29, 30);
745 EXPECT_THAT(out, StrEq("stdout\n"));
746 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
747
748 EXPECT_CALL(*listener, onProgress(100)); // 30/30 %
749 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
750 progress_message = GetProgressMessage(30, 30);
751 EXPECT_THAT(out, StrEq("stdout\n"));
752 EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
753
754 ds.listener_.clear();
755 }
756
TEST_F(DumpstateTest,RunCommandDropRoot)757 TEST_F(DumpstateTest, RunCommandDropRoot) {
758 if (!IsStandalone()) {
759 // TODO: temporarily disabled because it might cause other tests to fail after dropping
760 // to Shell - need to refactor tests to avoid this problem)
761 MYLOGE("Skipping DumpstateTest.RunCommandDropRoot() on test suite\n")
762 return;
763 }
764 // First check root case - only available when running with 'adb root'.
765 uid_t uid = getuid();
766 if (uid == 0) {
767 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}));
768 EXPECT_THAT(out, StrEq("0\nstdout\n"));
769 EXPECT_THAT(err, StrEq("stderr\n"));
770 return;
771 }
772 // Then run dropping root.
773 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
774 CommandOptions::WithTimeout(1).DropRoot().Build()));
775 EXPECT_THAT(out, StrEq("2000\nstdout\n"));
776 EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
777 }
778
TEST_F(DumpstateTest,RunCommandAsRootUserBuild)779 TEST_F(DumpstateTest, RunCommandAsRootUserBuild) {
780 if (!IsStandalone()) {
781 // TODO: temporarily disabled because it might cause other tests to fail after dropping
782 // to Shell - need to refactor tests to avoid this problem)
783 MYLOGE("Skipping DumpstateTest.RunCommandAsRootUserBuild() on test suite\n")
784 return;
785 }
786 if (!PropertiesHelper::IsUserBuild()) {
787 // Emulates user build if necessarily.
788 SetBuildType("user");
789 }
790
791 DropRoot();
792
793 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).AsRoot().Build()));
794
795 // We don't know the exact path of su, so we just check for the 'root ...' commands
796 EXPECT_THAT(out, StartsWith("Skipping"));
797 EXPECT_THAT(out, EndsWith("root " + kSimpleCommand + "' on user build.\n"));
798 EXPECT_THAT(err, IsEmpty());
799 }
800
TEST_F(DumpstateTest,RunCommandAsRootNonUserBuild)801 TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild) {
802 if (!IsStandalone()) {
803 // TODO: temporarily disabled because it might cause other tests to fail after dropping
804 // to Shell - need to refactor tests to avoid this problem)
805 MYLOGE("Skipping DumpstateTest.RunCommandAsRootNonUserBuild() on test suite\n")
806 return;
807 }
808 if (PropertiesHelper::IsUserBuild()) {
809 ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
810 return;
811 }
812
813 DropRoot();
814
815 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
816 CommandOptions::WithTimeout(1).AsRoot().Build()));
817
818 EXPECT_THAT(out, StrEq("0\nstdout\n"));
819 EXPECT_THAT(err, StrEq("stderr\n"));
820 }
821
TEST_F(DumpstateTest,RunCommandAsRootNonUserBuild_withUnroot)822 TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild_withUnroot) {
823 if (!IsStandalone()) {
824 // TODO: temporarily disabled because it might cause other tests to fail after dropping
825 // to Shell - need to refactor tests to avoid this problem)
826 MYLOGE(
827 "Skipping DumpstateTest.RunCommandAsRootNonUserBuild_withUnroot() "
828 "on test suite\n")
829 return;
830 }
831 if (PropertiesHelper::IsUserBuild()) {
832 ALOGI("Skipping RunCommandAsRootNonUserBuild_withUnroot on user builds\n");
833 return;
834 }
835
836 // Same test as above, but with unroot property set, which will override su availability.
837 SetUnroot(true);
838 DropRoot();
839
840 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
841 CommandOptions::WithTimeout(1).AsRoot().Build()));
842
843 // AsRoot is ineffective.
844 EXPECT_THAT(out, StrEq("2000\nstdout\n"));
845 EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
846 }
847
TEST_F(DumpstateTest,RunCommandAsRootIfAvailableOnUserBuild)848 TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
849 if (!IsStandalone()) {
850 // TODO: temporarily disabled because it might cause other tests to fail after dropping
851 // to Shell - need to refactor tests to avoid this problem)
852 MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
853 return;
854 }
855 if (!PropertiesHelper::IsUserBuild()) {
856 // Emulates user build if necessarily.
857 SetBuildType("user");
858 }
859
860 DropRoot();
861
862 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
863 CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
864
865 EXPECT_THAT(out, StrEq("2000\nstdout\n"));
866 EXPECT_THAT(err, StrEq("stderr\n"));
867 }
868
TEST_F(DumpstateTest,RunCommandAsRootIfAvailableOnDebugBuild)869 TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild) {
870 if (!IsStandalone()) {
871 // TODO: temporarily disabled because it might cause other tests to fail after dropping
872 // to Shell - need to refactor tests to avoid this problem)
873 MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
874 return;
875 }
876 if (PropertiesHelper::IsUserBuild()) {
877 ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
878 return;
879 }
880
881 DropRoot();
882
883 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
884 CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
885
886 EXPECT_THAT(out, StrEq("0\nstdout\n"));
887 EXPECT_THAT(err, StrEq("stderr\n"));
888 }
889
TEST_F(DumpstateTest,RunCommandAsRootIfAvailableOnDebugBuild_withUnroot)890 TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild_withUnroot) {
891 if (!IsStandalone()) {
892 // TODO: temporarily disabled because it might cause other tests to fail after dropping
893 // to Shell - need to refactor tests to avoid this problem)
894 MYLOGE(
895 "Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild_withUnroot() "
896 "on test suite\n")
897 return;
898 }
899 if (PropertiesHelper::IsUserBuild()) {
900 ALOGI("Skipping RunCommandAsRootIfAvailableOnDebugBuild_withUnroot on user builds\n");
901 return;
902 }
903 // Same test as above, but with unroot property set, which will override su availability.
904 SetUnroot(true);
905
906 DropRoot();
907
908 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
909 CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
910
911 // It's a userdebug build, so "su root" should be available, but unroot=true overrides it.
912 EXPECT_THAT(out, StrEq("2000\nstdout\n"));
913 EXPECT_THAT(err, StrEq("stderr\n"));
914 }
915
TEST_F(DumpstateTest,DumpFileNotFoundNoTitle)916 TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
917 EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
918 EXPECT_THAT(out,
919 StrEq("*** Error dumping /I/cant/believe/I/exist: No such file or directory\n"));
920 EXPECT_THAT(err, IsEmpty());
921 }
922
TEST_F(DumpstateTest,DumpFileNotFoundWithTitle)923 TEST_F(DumpstateTest, DumpFileNotFoundWithTitle) {
924 EXPECT_EQ(-1, DumpFile("Y U NO EXIST?", "/I/cant/believe/I/exist"));
925 EXPECT_THAT(err, IsEmpty());
926 // The duration may not get output, depending on how long it takes,
927 // so we just check the prefix.
928 EXPECT_THAT(out, StartsWith("*** Error dumping /I/cant/believe/I/exist (Y U NO EXIST?): No "
929 "such file or directory\n"));
930 }
931
TEST_F(DumpstateTest,DumpFileSingleLine)932 TEST_F(DumpstateTest, DumpFileSingleLine) {
933 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
934 EXPECT_THAT(err, IsEmpty());
935 EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline
936 }
937
TEST_F(DumpstateTest,DumpFileSingleLineWithNewLine)938 TEST_F(DumpstateTest, DumpFileSingleLineWithNewLine) {
939 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line-with-newline.txt"));
940 EXPECT_THAT(err, IsEmpty());
941 EXPECT_THAT(out, StrEq("I AM LINE1\n"));
942 }
943
TEST_F(DumpstateTest,DumpFileMultipleLines)944 TEST_F(DumpstateTest, DumpFileMultipleLines) {
945 EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines.txt"));
946 EXPECT_THAT(err, IsEmpty());
947 EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
948 }
949
TEST_F(DumpstateTest,DumpFileMultipleLinesWithNewLine)950 TEST_F(DumpstateTest, DumpFileMultipleLinesWithNewLine) {
951 EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines-with-newline.txt"));
952 EXPECT_THAT(err, IsEmpty());
953 EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
954 }
955
TEST_F(DumpstateTest,DumpFileOnDryRunNoTitle)956 TEST_F(DumpstateTest, DumpFileOnDryRunNoTitle) {
957 SetDryRun(true);
958 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
959 EXPECT_THAT(err, IsEmpty());
960 EXPECT_THAT(out, IsEmpty());
961 }
962
TEST_F(DumpstateTest,DumpFileOnDryRun)963 TEST_F(DumpstateTest, DumpFileOnDryRun) {
964 SetDryRun(true);
965 EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", kTestDataPath + "single-line.txt"));
966 EXPECT_THAT(err, IsEmpty());
967 EXPECT_THAT(
968 out, StartsWith("------ Might as well dump. Dump! (" + kTestDataPath + "single-line.txt:"));
969 EXPECT_THAT(out, HasSubstr("\n\t(skipped on dry run)\n"));
970 }
971
TEST_F(DumpstateTest,DumpFileUpdateProgress)972 TEST_F(DumpstateTest, DumpFileUpdateProgress) {
973 sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
974 ds.listener_ = listener;
975 SetProgress(0, 30);
976
977 EXPECT_CALL(*listener, onProgress(16)); // 5/30 %
978 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
979
980 std::string progress_message = GetProgressMessage(5, 30); // TODO: unhardcode WEIGHT_FILE (5)?
981 EXPECT_THAT(err, StrEq(progress_message));
982 EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline
983
984 ds.listener_.clear();
985 }
986
TEST_F(DumpstateTest,DumpPool_withParallelRunEnabled_notNull)987 TEST_F(DumpstateTest, DumpPool_withParallelRunEnabled_notNull) {
988 SetParallelRun(true);
989 EnableParallelRunIfNeeded();
990 EXPECT_TRUE(ds.zip_entry_tasks_);
991 EXPECT_TRUE(ds.dump_pool_);
992 }
993
TEST_F(DumpstateTest,DumpPool_withParallelRunDisabled_isNull)994 TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) {
995 SetParallelRun(false);
996 EnableParallelRunIfNeeded();
997 EXPECT_FALSE(ds.zip_entry_tasks_);
998 EXPECT_FALSE(ds.dump_pool_);
999 }
1000
TEST_F(DumpstateTest,PreDumpUiData)1001 TEST_F(DumpstateTest, PreDumpUiData) {
1002 // These traces are always enabled, i.e. they are always pre-dumped
1003 std::vector<std::filesystem::path> uiTraces;
1004 if (!android_tracing_perfetto_transition_tracing()) {
1005 uiTraces.push_back(
1006 std::filesystem::path{"/data/misc/wmtrace/wm_transition_trace.winscope"});
1007 uiTraces.push_back(
1008 std::filesystem::path{"/data/misc/wmtrace/shell_transition_trace.winscope"});
1009 }
1010
1011 for (const auto traceFile : uiTraces) {
1012 std::system(("rm -f " + traceFile.string()).c_str());
1013 EXPECT_FALSE(std::filesystem::exists(traceFile)) << traceFile << " was not deleted.";
1014
1015 Dumpstate& ds_ = Dumpstate::GetInstance();
1016 ds_.PreDumpUiData();
1017 EXPECT_TRUE(std::filesystem::exists(traceFile)) << traceFile << " was not created.";
1018 }
1019 }
1020
1021 class ZippedBugReportStreamTest : public DumpstateBaseTest {
1022 public:
SetUp()1023 void SetUp() {
1024 DumpstateBaseTest::SetUp();
1025 ds_.options_.reset(new Dumpstate::DumpOptions());
1026 }
TearDown()1027 void TearDown() {
1028 CloseArchive(handle_);
1029 }
1030
1031 // Set bugreport mode and options before here.
GenerateBugreport()1032 void GenerateBugreport() {
1033 ds_.Initialize();
1034 EXPECT_EQ(Dumpstate::RunStatus::OK, ds_.Run(/*calling_uid=*/-1, /*calling_package=*/""));
1035 }
1036
1037 // Most bugreports droproot, ensure the file can be opened by shell to verify file content.
CreateFd(const std::string & path,android::base::unique_fd * out_fd)1038 void CreateFd(const std::string& path, android::base::unique_fd* out_fd) {
1039 out_fd->reset(TEMP_FAILURE_RETRY(open(path.c_str(),
1040 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1041 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1042 ASSERT_GE(out_fd->get(), 0) << "could not create FD for path " << path;
1043 }
1044
VerifyEntry(const ZipArchiveHandle archive,const std::string_view entry_name,ZipEntry * data)1045 void VerifyEntry(const ZipArchiveHandle archive, const std::string_view entry_name,
1046 ZipEntry* data) {
1047 int32_t e = FindEntry(archive, entry_name, data);
1048 EXPECT_EQ(0, e) << ErrorCodeString(e) << " entry name: " << entry_name;
1049 }
1050
1051 // While testing dumpstate in process, using STDOUT may get confused about
1052 // the internal fd redirection. Redirect to a dedicate fd to save content.
RedirectOutputToFd(android::base::unique_fd & ufd)1053 void RedirectOutputToFd(android::base::unique_fd& ufd) {
1054 ds_.open_socket_fn_ = [&](const char*) -> int { return ufd.release(); };
1055 };
1056
1057 Dumpstate& ds_ = Dumpstate::GetInstance();
1058 ZipArchiveHandle handle_;
1059 };
1060
1061 // Generate a quick LimitedOnly report redirected to a file, open it and verify entry exist.
1062 // TODO: broken test tracked in b/249983726
TEST_F(ZippedBugReportStreamTest,DISABLED_StreamLimitedOnlyReport)1063 TEST_F(ZippedBugReportStreamTest, DISABLED_StreamLimitedOnlyReport) {
1064 std::string out_path = kTestDataPath + "StreamLimitedOnlyReportOut.zip";
1065 android::base::unique_fd out_fd;
1066 CreateFd(out_path, &out_fd);
1067 ds_.options_->limited_only = true;
1068 ds_.options_->stream_to_socket = true;
1069 RedirectOutputToFd(out_fd);
1070
1071 GenerateBugreport();
1072 OpenArchive(out_path.c_str(), &handle_);
1073
1074 ZipEntry entry;
1075 VerifyEntry(handle_, "main_entry.txt", &entry);
1076 std::string bugreport_txt_name;
1077 bugreport_txt_name.resize(entry.uncompressed_length);
1078 ExtractToMemory(handle_, &entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
1079 entry.uncompressed_length);
1080 EXPECT_THAT(bugreport_txt_name,
1081 testing::ContainsRegex("(bugreport-.+(-[[:digit:]]+){6}\\.txt)"));
1082 VerifyEntry(handle_, bugreport_txt_name, &entry);
1083 }
1084
1085 class ProgressTest : public DumpstateBaseTest {
1086 public:
GetInstance(int32_t max,double growth_factor,const std::string & path="")1087 Progress GetInstance(int32_t max, double growth_factor, const std::string& path = "") {
1088 return Progress(max, growth_factor, path);
1089 }
1090
AssertStats(const std::string & path,int32_t expected_runs,int32_t expected_average)1091 void AssertStats(const std::string& path, int32_t expected_runs, int32_t expected_average) {
1092 std::string expected_content =
1093 android::base::StringPrintf("%d %d\n", expected_runs, expected_average);
1094 std::string actual_content;
1095 ReadFileToString(path, &actual_content);
1096 ASSERT_THAT(actual_content, StrEq(expected_content)) << "invalid stats on " << path;
1097 }
1098 };
1099
TEST_F(ProgressTest,SimpleTest)1100 TEST_F(ProgressTest, SimpleTest) {
1101 Progress progress;
1102 EXPECT_EQ(0, progress.Get());
1103 EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
1104 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1105
1106 bool max_increased = progress.Inc(1);
1107 EXPECT_EQ(1, progress.Get());
1108 EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
1109 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1110 EXPECT_FALSE(max_increased);
1111
1112 // Ignore negative increase.
1113 max_increased = progress.Inc(-1);
1114 EXPECT_EQ(1, progress.Get());
1115 EXPECT_EQ(Progress::kDefaultMax, progress.GetInitialMax());
1116 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1117 EXPECT_FALSE(max_increased);
1118 }
1119
TEST_F(ProgressTest,MaxGrowsInsideNewRange)1120 TEST_F(ProgressTest, MaxGrowsInsideNewRange) {
1121 Progress progress = GetInstance(10, 1.2); // 20% growth factor
1122 EXPECT_EQ(0, progress.Get());
1123 EXPECT_EQ(10, progress.GetInitialMax());
1124 EXPECT_EQ(10, progress.GetMax());
1125
1126 // No increase
1127 bool max_increased = progress.Inc(10);
1128 EXPECT_EQ(10, progress.Get());
1129 EXPECT_EQ(10, progress.GetMax());
1130 EXPECT_FALSE(max_increased);
1131
1132 // Increase, with new value < max*20%
1133 max_increased = progress.Inc(1);
1134 EXPECT_EQ(11, progress.Get());
1135 EXPECT_EQ(13, progress.GetMax()); // 11 average * 20% growth = 13.2 = 13
1136 EXPECT_TRUE(max_increased);
1137 }
1138
TEST_F(ProgressTest,MaxGrowsOutsideNewRange)1139 TEST_F(ProgressTest, MaxGrowsOutsideNewRange) {
1140 Progress progress = GetInstance(10, 1.2); // 20% growth factor
1141 EXPECT_EQ(0, progress.Get());
1142 EXPECT_EQ(10, progress.GetInitialMax());
1143 EXPECT_EQ(10, progress.GetMax());
1144
1145 // No increase
1146 bool max_increased = progress.Inc(10);
1147 EXPECT_EQ(10, progress.Get());
1148 EXPECT_EQ(10, progress.GetMax());
1149 EXPECT_FALSE(max_increased);
1150
1151 // Increase, with new value > max*20%
1152 max_increased = progress.Inc(5);
1153 EXPECT_EQ(15, progress.Get());
1154 EXPECT_EQ(18, progress.GetMax()); // 15 average * 20% growth = 18
1155 EXPECT_TRUE(max_increased);
1156 }
1157
TEST_F(ProgressTest,InvalidPath)1158 TEST_F(ProgressTest, InvalidPath) {
1159 Progress progress("/devil/null");
1160 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1161 }
1162
TEST_F(ProgressTest,EmptyFile)1163 TEST_F(ProgressTest, EmptyFile) {
1164 Progress progress(CopyTextFileFixture("empty-file.txt"));
1165 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1166 }
1167
TEST_F(ProgressTest,InvalidLine1stEntryNAN)1168 TEST_F(ProgressTest, InvalidLine1stEntryNAN) {
1169 Progress progress(CopyTextFileFixture("stats-invalid-1st-NAN.txt"));
1170 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1171 }
1172
TEST_F(ProgressTest,InvalidLine2ndEntryNAN)1173 TEST_F(ProgressTest, InvalidLine2ndEntryNAN) {
1174 Progress progress(CopyTextFileFixture("stats-invalid-2nd-NAN.txt"));
1175 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1176 }
1177
TEST_F(ProgressTest,InvalidLineBothNAN)1178 TEST_F(ProgressTest, InvalidLineBothNAN) {
1179 Progress progress(CopyTextFileFixture("stats-invalid-both-NAN.txt"));
1180 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1181 }
1182
TEST_F(ProgressTest,InvalidLine1stEntryNegative)1183 TEST_F(ProgressTest, InvalidLine1stEntryNegative) {
1184 Progress progress(CopyTextFileFixture("stats-invalid-1st-negative.txt"));
1185 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1186 }
1187
TEST_F(ProgressTest,InvalidLine2ndEntryNegative)1188 TEST_F(ProgressTest, InvalidLine2ndEntryNegative) {
1189 Progress progress(CopyTextFileFixture("stats-invalid-2nd-negative.txt"));
1190 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1191 }
1192
TEST_F(ProgressTest,InvalidLine1stEntryTooBig)1193 TEST_F(ProgressTest, InvalidLine1stEntryTooBig) {
1194 Progress progress(CopyTextFileFixture("stats-invalid-1st-too-big.txt"));
1195 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1196 }
1197
TEST_F(ProgressTest,InvalidLine2ndEntryTooBig)1198 TEST_F(ProgressTest, InvalidLine2ndEntryTooBig) {
1199 Progress progress(CopyTextFileFixture("stats-invalid-2nd-too-big.txt"));
1200 EXPECT_EQ(Progress::kDefaultMax, progress.GetMax());
1201 }
1202
1203 // Tests stats are properly saved when the file does not exists.
TEST_F(ProgressTest,FirstTime)1204 TEST_F(ProgressTest, FirstTime) {
1205 if (!IsStandalone()) {
1206 // TODO: temporarily disabled because it's failing when running as suite
1207 MYLOGE("Skipping ProgressTest.FirstTime() on test suite\n")
1208 return;
1209 }
1210
1211 std::string path = kTestDataPath + "FirstTime.txt";
1212 android::base::RemoveFileIfExists(path);
1213
1214 Progress run1(path);
1215 EXPECT_EQ(0, run1.Get());
1216 EXPECT_EQ(Progress::kDefaultMax, run1.GetInitialMax());
1217 EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
1218
1219 bool max_increased = run1.Inc(20);
1220 EXPECT_EQ(20, run1.Get());
1221 EXPECT_EQ(Progress::kDefaultMax, run1.GetMax());
1222 EXPECT_FALSE(max_increased);
1223
1224 run1.Save();
1225 AssertStats(path, 1, 20);
1226 }
1227
1228 // Tests what happens when the persistent settings contains the average duration of 1 run.
1229 // Data on file is 1 run and 109 average.
TEST_F(ProgressTest,SecondTime)1230 TEST_F(ProgressTest, SecondTime) {
1231 std::string path = CopyTextFileFixture("stats-one-run-no-newline.txt");
1232
1233 Progress run1 = GetInstance(-42, 1.2, path);
1234 EXPECT_EQ(0, run1.Get());
1235 EXPECT_EQ(10, run1.GetInitialMax());
1236 EXPECT_EQ(10, run1.GetMax());
1237
1238 bool max_increased = run1.Inc(20);
1239 EXPECT_EQ(20, run1.Get());
1240 EXPECT_EQ(24, run1.GetMax());
1241 EXPECT_TRUE(max_increased);
1242
1243 // Average now is 2 runs and (10 + 20)/ 2 = 15
1244 run1.Save();
1245 AssertStats(path, 2, 15);
1246
1247 Progress run2 = GetInstance(-42, 1.2, path);
1248 EXPECT_EQ(0, run2.Get());
1249 EXPECT_EQ(15, run2.GetInitialMax());
1250 EXPECT_EQ(15, run2.GetMax());
1251
1252 max_increased = run2.Inc(25);
1253 EXPECT_EQ(25, run2.Get());
1254 EXPECT_EQ(30, run2.GetMax());
1255 EXPECT_TRUE(max_increased);
1256
1257 // Average now is 3 runs and (15 * 2 + 25)/ 3 = 18.33 = 18
1258 run2.Save();
1259 AssertStats(path, 3, 18);
1260
1261 Progress run3 = GetInstance(-42, 1.2, path);
1262 EXPECT_EQ(0, run3.Get());
1263 EXPECT_EQ(18, run3.GetInitialMax());
1264 EXPECT_EQ(18, run3.GetMax());
1265
1266 // Make sure average decreases as well
1267 max_increased = run3.Inc(5);
1268 EXPECT_EQ(5, run3.Get());
1269 EXPECT_EQ(18, run3.GetMax());
1270 EXPECT_FALSE(max_increased);
1271
1272 // Average now is 4 runs and (18 * 3 + 5)/ 4 = 14.75 = 14
1273 run3.Save();
1274 AssertStats(path, 4, 14);
1275 }
1276
1277 // Tests what happens when the persistent settings contains the average duration of 2 runs.
1278 // Data on file is 2 runs and 15 average.
TEST_F(ProgressTest,ThirdTime)1279 TEST_F(ProgressTest, ThirdTime) {
1280 std::string path = CopyTextFileFixture("stats-two-runs.txt");
1281 AssertStats(path, 2, 15); // Sanity check
1282
1283 Progress run1 = GetInstance(-42, 1.2, path);
1284 EXPECT_EQ(0, run1.Get());
1285 EXPECT_EQ(15, run1.GetInitialMax());
1286 EXPECT_EQ(15, run1.GetMax());
1287
1288 bool max_increased = run1.Inc(20);
1289 EXPECT_EQ(20, run1.Get());
1290 EXPECT_EQ(24, run1.GetMax());
1291 EXPECT_TRUE(max_increased);
1292
1293 // Average now is 3 runs and (15 * 2 + 20)/ 3 = 16.66 = 16
1294 run1.Save();
1295 AssertStats(path, 3, 16);
1296 }
1297
1298 class DumpstateUtilTest : public DumpstateBaseTest {
1299 public:
SetUp()1300 void SetUp() {
1301 DumpstateBaseTest::SetUp();
1302 SetDryRun(false);
1303 }
1304
CaptureFdOut()1305 void CaptureFdOut() {
1306 ReadFileToString(path_, &out);
1307 }
1308
CreateFd(const std::string & name)1309 void CreateFd(const std::string& name) {
1310 path_ = kTestDataPath + name;
1311 MYLOGD("Creating fd for file %s\n", path_.c_str());
1312
1313 fd = TEMP_FAILURE_RETRY(open(path_.c_str(),
1314 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1315 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
1316 ASSERT_GE(fd, 0) << "could not create FD for path " << path_;
1317 }
1318
1319 // Runs a command into the `fd` and capture `stderr`.
RunCommand(const std::string & title,const std::vector<std::string> & full_command,const CommandOptions & options=CommandOptions::DEFAULT)1320 int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
1321 const CommandOptions& options = CommandOptions::DEFAULT) {
1322 CaptureStderr();
1323 int status = RunCommandToFd(fd, title, full_command, options);
1324 close(fd);
1325
1326 CaptureFdOut();
1327 err = GetCapturedStderr();
1328 return status;
1329 }
1330
1331 // Dumps a file and into the `fd` and `stderr`.
DumpFile(const std::string & title,const std::string & path)1332 int DumpFile(const std::string& title, const std::string& path) {
1333 CaptureStderr();
1334 int status = DumpFileToFd(fd, title, path);
1335 close(fd);
1336
1337 CaptureFdOut();
1338 err = GetCapturedStderr();
1339 return status;
1340 }
1341
1342 int fd;
1343
1344 // 'fd` output and `stderr` from the last command ran.
1345 std::string out, err;
1346
1347 private:
1348 std::string path_;
1349 };
1350
TEST_F(DumpstateUtilTest,RunCommandNoArgs)1351 TEST_F(DumpstateUtilTest, RunCommandNoArgs) {
1352 CreateFd("RunCommandNoArgs.txt");
1353 EXPECT_EQ(-1, RunCommand("", {}));
1354 }
1355
TEST_F(DumpstateUtilTest,RunCommandNoTitle)1356 TEST_F(DumpstateUtilTest, RunCommandNoTitle) {
1357 CreateFd("RunCommandWithNoArgs.txt");
1358 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
1359 EXPECT_THAT(out, StrEq("stdout\n"));
1360 EXPECT_THAT(err, StrEq("stderr\n"));
1361 }
1362
TEST_F(DumpstateUtilTest,RunCommandWithTitle)1363 TEST_F(DumpstateUtilTest, RunCommandWithTitle) {
1364 CreateFd("RunCommandWithNoArgs.txt");
1365 EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
1366 EXPECT_THAT(out, StrEq("------ I AM GROOT (" + kSimpleCommand + ") ------\nstdout\n"));
1367 EXPECT_THAT(err, StrEq("stderr\n"));
1368 }
1369
TEST_F(DumpstateUtilTest,RunCommandWithOneArg)1370 TEST_F(DumpstateUtilTest, RunCommandWithOneArg) {
1371 CreateFd("RunCommandWithOneArg.txt");
1372 EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one"}));
1373 EXPECT_THAT(err, IsEmpty());
1374 EXPECT_THAT(out, StrEq("one\n"));
1375 }
1376
TEST_F(DumpstateUtilTest,RunCommandWithMultipleArgs)1377 TEST_F(DumpstateUtilTest, RunCommandWithMultipleArgs) {
1378 CreateFd("RunCommandWithMultipleArgs.txt");
1379 EXPECT_EQ(0, RunCommand("", {kEchoCommand, "one", "is", "the", "loniest", "number"}));
1380 EXPECT_THAT(err, IsEmpty());
1381 EXPECT_THAT(out, StrEq("one is the loniest number\n"));
1382 }
1383
TEST_F(DumpstateUtilTest,RunCommandWithLoggingMessage)1384 TEST_F(DumpstateUtilTest, RunCommandWithLoggingMessage) {
1385 CreateFd("RunCommandWithLoggingMessage.txt");
1386 EXPECT_EQ(
1387 0, RunCommand("", {kSimpleCommand},
1388 CommandOptions::WithTimeout(10).Log("COMMAND, Y U NO LOG FIRST?").Build()));
1389 EXPECT_THAT(out, StrEq("stdout\n"));
1390 EXPECT_THAT(err, StrEq("COMMAND, Y U NO LOG FIRST?stderr\n"));
1391 }
1392
TEST_F(DumpstateUtilTest,RunCommandRedirectStderr)1393 TEST_F(DumpstateUtilTest, RunCommandRedirectStderr) {
1394 CreateFd("RunCommandRedirectStderr.txt");
1395 EXPECT_EQ(0, RunCommand("", {kSimpleCommand},
1396 CommandOptions::WithTimeout(10).RedirectStderr().Build()));
1397 EXPECT_THAT(out, IsEmpty());
1398 EXPECT_THAT(err, StrEq("stdout\nstderr\n"));
1399 }
1400
TEST_F(DumpstateUtilTest,RunCommandDryRun)1401 TEST_F(DumpstateUtilTest, RunCommandDryRun) {
1402 CreateFd("RunCommandDryRun.txt");
1403 SetDryRun(true);
1404 EXPECT_EQ(0, RunCommand("I AM GROOT", {kSimpleCommand}));
1405 EXPECT_THAT(out, StrEq(android::base::StringPrintf(
1406 "------ I AM GROOT (%s) ------\n\t(skipped on dry run)\n",
1407 kSimpleCommand.c_str())));
1408 EXPECT_THAT(err, IsEmpty());
1409 }
1410
TEST_F(DumpstateUtilTest,RunCommandDryRunNoTitle)1411 TEST_F(DumpstateUtilTest, RunCommandDryRunNoTitle) {
1412 CreateFd("RunCommandDryRun.txt");
1413 SetDryRun(true);
1414 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}));
1415 EXPECT_THAT(
1416 out, StrEq(android::base::StringPrintf("%s: skipped on dry run\n", kSimpleCommand.c_str())));
1417 EXPECT_THAT(err, IsEmpty());
1418 }
1419
TEST_F(DumpstateUtilTest,RunCommandDryRunAlways)1420 TEST_F(DumpstateUtilTest, RunCommandDryRunAlways) {
1421 CreateFd("RunCommandDryRunAlways.txt");
1422 SetDryRun(true);
1423 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Always().Build()));
1424 EXPECT_THAT(out, StrEq("stdout\n"));
1425 EXPECT_THAT(err, StrEq("stderr\n"));
1426 }
1427
TEST_F(DumpstateUtilTest,RunCommandNotFound)1428 TEST_F(DumpstateUtilTest, RunCommandNotFound) {
1429 CreateFd("RunCommandNotFound.txt");
1430 EXPECT_NE(0, RunCommand("", {"/there/cannot/be/such/command"}));
1431 EXPECT_THAT(out, StartsWith("*** command '/there/cannot/be/such/command' failed: exit code"));
1432 EXPECT_THAT(err, StartsWith("execvp on command '/there/cannot/be/such/command' failed"));
1433 }
1434
TEST_F(DumpstateUtilTest,RunCommandFails)1435 TEST_F(DumpstateUtilTest, RunCommandFails) {
1436 CreateFd("RunCommandFails.txt");
1437 EXPECT_EQ(42, RunCommand("", {kSimpleCommand, "--exit", "42"}));
1438 EXPECT_THAT(out, StrEq("stdout\n*** command '" + kSimpleCommand +
1439 " --exit 42' failed: exit code 42\n"));
1440 EXPECT_THAT(err, StrEq("stderr\n*** command '" + kSimpleCommand +
1441 " --exit 42' failed: exit code 42\n"));
1442 }
1443
TEST_F(DumpstateUtilTest,RunCommandCrashes)1444 TEST_F(DumpstateUtilTest, RunCommandCrashes) {
1445 CreateFd("RunCommandCrashes.txt");
1446 EXPECT_NE(0, RunCommand("", {kSimpleCommand, "--crash"}));
1447 // We don't know the exit code, so check just the prefix.
1448 EXPECT_THAT(
1449 out, StartsWith("stdout\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
1450 EXPECT_THAT(
1451 err, StartsWith("stderr\n*** command '" + kSimpleCommand + " --crash' failed: exit code"));
1452 }
1453
TEST_F(DumpstateUtilTest,RunCommandTimesoutWithSec)1454 TEST_F(DumpstateUtilTest, RunCommandTimesoutWithSec) {
1455 CreateFd("RunCommandTimesout.txt");
1456 EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
1457 CommandOptions::WithTimeout(1).Build()));
1458 EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
1459 " --sleep 2' timed out after 1"));
1460 EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
1461 " --sleep 2' timed out after 1"));
1462 }
1463
TEST_F(DumpstateUtilTest,RunCommandTimesoutWithMsec)1464 TEST_F(DumpstateUtilTest, RunCommandTimesoutWithMsec) {
1465 CreateFd("RunCommandTimesout.txt");
1466 EXPECT_EQ(-1, RunCommand("", {kSimpleCommand, "--sleep", "2"},
1467 CommandOptions::WithTimeoutInMs(1000).Build()));
1468 EXPECT_THAT(out, StartsWith("stdout line1\n*** command '" + kSimpleCommand +
1469 " --sleep 2' timed out after 1"));
1470 EXPECT_THAT(err, StartsWith("sleeping for 2s\n*** command '" + kSimpleCommand +
1471 " --sleep 2' timed out after 1"));
1472 }
1473
1474
TEST_F(DumpstateUtilTest,RunCommandIsKilled)1475 TEST_F(DumpstateUtilTest, RunCommandIsKilled) {
1476 CreateFd("RunCommandIsKilled.txt");
1477 CaptureStderr();
1478
1479 std::thread t([=]() {
1480 EXPECT_EQ(SIGTERM, RunCommandToFd(fd, "", {kSimpleCommand, "--pid", "--sleep", "20"},
1481 CommandOptions::WithTimeout(100).Always().Build()));
1482 });
1483
1484 // Capture pid and pre-sleep output.
1485 sleep(1); // Wait a little bit to make sure pid and 1st line were printed.
1486 std::string err = GetCapturedStderr();
1487 EXPECT_THAT(err, StrEq("sleeping for 20s\n"));
1488
1489 CaptureFdOut();
1490 std::vector<std::string> lines = android::base::Split(out, "\n");
1491 ASSERT_EQ(3, (int)lines.size()) << "Invalid lines before sleep: " << out;
1492
1493 int pid = atoi(lines[0].c_str());
1494 EXPECT_THAT(lines[1], StrEq("stdout line1"));
1495 EXPECT_THAT(lines[2], IsEmpty()); // \n
1496
1497 // Then kill the process.
1498 CaptureFdOut();
1499 CaptureStderr();
1500 ASSERT_EQ(0, kill(pid, SIGTERM)) << "failed to kill pid " << pid;
1501 t.join();
1502
1503 // Finally, check output after murder.
1504 CaptureFdOut();
1505 err = GetCapturedStderr();
1506
1507 // out starts with the pid, which is an unknown
1508 EXPECT_THAT(out, EndsWith("stdout line1\n*** command '" + kSimpleCommand +
1509 " --pid --sleep 20' failed: killed by signal 15\n"));
1510 EXPECT_THAT(err, StrEq("*** command '" + kSimpleCommand +
1511 " --pid --sleep 20' failed: killed by signal 15\n"));
1512 }
1513
TEST_F(DumpstateUtilTest,RunCommandAsRootUserBuild)1514 TEST_F(DumpstateUtilTest, RunCommandAsRootUserBuild) {
1515 if (!IsStandalone()) {
1516 // TODO: temporarily disabled because it might cause other tests to fail after dropping
1517 // to Shell - need to refactor tests to avoid this problem)
1518 MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootUserBuild() on test suite\n")
1519 return;
1520 }
1521 CreateFd("RunCommandAsRootUserBuild.txt");
1522 if (!PropertiesHelper::IsUserBuild()) {
1523 // Emulates user build if necessarily.
1524 SetBuildType("user");
1525 }
1526
1527 DropRoot();
1528
1529 EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).AsRoot().Build()));
1530
1531 // We don't know the exact path of su, so we just check for the 'root ...' commands
1532 EXPECT_THAT(out, StartsWith("Skipping"));
1533 EXPECT_THAT(out, EndsWith("root " + kSimpleCommand + "' on user build.\n"));
1534 EXPECT_THAT(err, IsEmpty());
1535 }
1536
TEST_F(DumpstateUtilTest,RunCommandAsRootNonUserBuild)1537 TEST_F(DumpstateUtilTest, RunCommandAsRootNonUserBuild) {
1538 if (!IsStandalone()) {
1539 // TODO: temporarily disabled because it might cause other tests to fail after dropping
1540 // to Shell - need to refactor tests to avoid this problem)
1541 MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootNonUserBuild() on test suite\n")
1542 return;
1543 }
1544 CreateFd("RunCommandAsRootNonUserBuild.txt");
1545 if (PropertiesHelper::IsUserBuild()) {
1546 ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
1547 return;
1548 }
1549
1550 DropRoot();
1551
1552 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
1553 CommandOptions::WithTimeout(1).AsRoot().Build()));
1554
1555 EXPECT_THAT(out, StrEq("0\nstdout\n"));
1556 EXPECT_THAT(err, StrEq("stderr\n"));
1557 }
1558
1559
TEST_F(DumpstateUtilTest,RunCommandAsRootIfAvailableOnUserBuild)1560 TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnUserBuild) {
1561 if (!IsStandalone()) {
1562 // TODO: temporarily disabled because it might cause other tests to fail after dropping
1563 // to Shell - need to refactor tests to avoid this problem)
1564 MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
1565 return;
1566 }
1567 CreateFd("RunCommandAsRootIfAvailableOnUserBuild.txt");
1568 if (!PropertiesHelper::IsUserBuild()) {
1569 // Emulates user build if necessarily.
1570 SetBuildType("user");
1571 }
1572
1573 DropRoot();
1574
1575 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
1576 CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
1577
1578 EXPECT_THAT(out, StrEq("2000\nstdout\n"));
1579 EXPECT_THAT(err, StrEq("stderr\n"));
1580 }
1581
TEST_F(DumpstateUtilTest,RunCommandAsRootIfAvailableOnDebugBuild)1582 TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnDebugBuild) {
1583 if (!IsStandalone()) {
1584 // TODO: temporarily disabled because it might cause other tests to fail after dropping
1585 // to Shell - need to refactor tests to avoid this problem)
1586 MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
1587 return;
1588 }
1589 CreateFd("RunCommandAsRootIfAvailableOnDebugBuild.txt");
1590 if (PropertiesHelper::IsUserBuild()) {
1591 ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
1592 return;
1593 }
1594
1595 DropRoot();
1596
1597 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
1598 CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
1599
1600 EXPECT_THAT(out, StrEq("0\nstdout\n"));
1601 EXPECT_THAT(err, StrEq("stderr\n"));
1602 }
1603
TEST_F(DumpstateUtilTest,RunCommandDropRoot)1604 TEST_F(DumpstateUtilTest, RunCommandDropRoot) {
1605 if (!IsStandalone()) {
1606 // TODO: temporarily disabled because it might cause other tests to fail after dropping
1607 // to Shell - need to refactor tests to avoid this problem)
1608 MYLOGE("Skipping DumpstateUtilTest.RunCommandDropRoot() on test suite\n")
1609 return;
1610 }
1611 CreateFd("RunCommandDropRoot.txt");
1612 // First check root case - only available when running with 'adb root'.
1613 uid_t uid = getuid();
1614 if (uid == 0) {
1615 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}));
1616 EXPECT_THAT(out, StrEq("0\nstdout\n"));
1617 EXPECT_THAT(err, StrEq("stderr\n"));
1618 return;
1619 }
1620 // Then run dropping root.
1621 EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
1622 CommandOptions::WithTimeout(1).DropRoot().Build()));
1623 EXPECT_THAT(out, StrEq("2000\nstdout\n"));
1624 EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
1625 }
1626
TEST_F(DumpstateUtilTest,DumpFileNotFoundNoTitle)1627 TEST_F(DumpstateUtilTest, DumpFileNotFoundNoTitle) {
1628 CreateFd("DumpFileNotFound.txt");
1629 EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
1630 EXPECT_THAT(out,
1631 StrEq("*** Error dumping /I/cant/believe/I/exist: No such file or directory\n"));
1632 EXPECT_THAT(err, IsEmpty());
1633 }
1634
TEST_F(DumpstateUtilTest,DumpFileNotFoundWithTitle)1635 TEST_F(DumpstateUtilTest, DumpFileNotFoundWithTitle) {
1636 CreateFd("DumpFileNotFound.txt");
1637 EXPECT_EQ(-1, DumpFile("Y U NO EXIST?", "/I/cant/believe/I/exist"));
1638 EXPECT_THAT(out, StrEq("*** Error dumping /I/cant/believe/I/exist (Y U NO EXIST?): No such "
1639 "file or directory\n"));
1640 EXPECT_THAT(err, IsEmpty());
1641 }
1642
TEST_F(DumpstateUtilTest,DumpFileSingleLine)1643 TEST_F(DumpstateUtilTest, DumpFileSingleLine) {
1644 CreateFd("DumpFileSingleLine.txt");
1645 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
1646 EXPECT_THAT(err, IsEmpty());
1647 EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline
1648 }
1649
TEST_F(DumpstateUtilTest,DumpFileSingleLineWithNewLine)1650 TEST_F(DumpstateUtilTest, DumpFileSingleLineWithNewLine) {
1651 CreateFd("DumpFileSingleLineWithNewLine.txt");
1652 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line-with-newline.txt"));
1653 EXPECT_THAT(err, IsEmpty());
1654 EXPECT_THAT(out, StrEq("I AM LINE1\n"));
1655 }
1656
TEST_F(DumpstateUtilTest,DumpFileMultipleLines)1657 TEST_F(DumpstateUtilTest, DumpFileMultipleLines) {
1658 CreateFd("DumpFileMultipleLines.txt");
1659 EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines.txt"));
1660 EXPECT_THAT(err, IsEmpty());
1661 EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
1662 }
1663
TEST_F(DumpstateUtilTest,DumpFileMultipleLinesWithNewLine)1664 TEST_F(DumpstateUtilTest, DumpFileMultipleLinesWithNewLine) {
1665 CreateFd("DumpFileMultipleLinesWithNewLine.txt");
1666 EXPECT_EQ(0, DumpFile("", kTestDataPath + "multiple-lines-with-newline.txt"));
1667 EXPECT_THAT(err, IsEmpty());
1668 EXPECT_THAT(out, StrEq("I AM LINE1\nI AM LINE2\nI AM LINE3\n"));
1669 }
1670
TEST_F(DumpstateUtilTest,DumpFileOnDryRunNoTitle)1671 TEST_F(DumpstateUtilTest, DumpFileOnDryRunNoTitle) {
1672 CreateFd("DumpFileOnDryRun.txt");
1673 SetDryRun(true);
1674 std::string path = kTestDataPath + "single-line.txt";
1675 EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
1676 EXPECT_THAT(err, IsEmpty());
1677 EXPECT_THAT(out, StrEq(path + ": skipped on dry run\n"));
1678 }
1679
TEST_F(DumpstateUtilTest,DumpFileOnDryRun)1680 TEST_F(DumpstateUtilTest, DumpFileOnDryRun) {
1681 CreateFd("DumpFileOnDryRun.txt");
1682 SetDryRun(true);
1683 std::string path = kTestDataPath + "single-line.txt";
1684 EXPECT_EQ(0, DumpFile("Might as well dump. Dump!", kTestDataPath + "single-line.txt"));
1685 EXPECT_THAT(err, IsEmpty());
1686 EXPECT_THAT(
1687 out, StartsWith("------ Might as well dump. Dump! (" + kTestDataPath + "single-line.txt:"));
1688 EXPECT_THAT(out, EndsWith("skipped on dry run\n"));
1689 }
1690
1691 class DumpPoolTest : public DumpstateBaseTest {
1692 public:
SetUp()1693 void SetUp() {
1694 dump_pool_ = std::make_unique<DumpPool>(kTestDataPath);
1695 DumpstateBaseTest::SetUp();
1696 CreateOutputFile();
1697 }
1698
CreateOutputFile()1699 void CreateOutputFile() {
1700 out_path_ = kTestDataPath + "out.txt";
1701 out_fd_.reset(TEMP_FAILURE_RETRY(open(out_path_.c_str(),
1702 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
1703 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
1704 ASSERT_GE(out_fd_.get(), 0) << "could not create FD for path "
1705 << out_path_;
1706 }
1707
getTempFileCounts(const std::string & folder)1708 int getTempFileCounts(const std::string& folder) {
1709 int count = 0;
1710 std::unique_ptr<DIR, decltype(&closedir)> dir_ptr(opendir(folder.c_str()),
1711 &closedir);
1712 if (!dir_ptr) {
1713 return -1;
1714 }
1715 int dir_fd = dirfd(dir_ptr.get());
1716 if (dir_fd < 0) {
1717 return -1;
1718 }
1719
1720 struct dirent* de;
1721 while ((de = readdir(dir_ptr.get()))) {
1722 if (de->d_type != DT_REG) {
1723 continue;
1724 }
1725 std::string file_name(de->d_name);
1726 if (file_name.find(DumpPool::PREFIX_TMPFILE_NAME) != 0) {
1727 continue;
1728 }
1729 count++;
1730 }
1731 return count;
1732 }
1733
setLogDuration(bool log_duration)1734 void setLogDuration(bool log_duration) {
1735 dump_pool_->setLogDuration(log_duration);
1736 }
1737
1738 std::unique_ptr<DumpPool> dump_pool_;
1739 android::base::unique_fd out_fd_;
1740 std::string out_path_;
1741 };
1742
TEST_F(DumpPoolTest,EnqueueTaskWithFd)1743 TEST_F(DumpPoolTest, EnqueueTaskWithFd) {
1744 auto dump_func_1 = [](int out_fd) {
1745 dprintf(out_fd, "A");
1746 };
1747 auto dump_func_2 = [](int out_fd) {
1748 dprintf(out_fd, "B");
1749 sleep(1);
1750 };
1751 auto dump_func_3 = [](int out_fd) {
1752 dprintf(out_fd, "C");
1753 };
1754 setLogDuration(/* log_duration = */false);
1755 auto t1 = dump_pool_->enqueueTaskWithFd("", dump_func_1, std::placeholders::_1);
1756 auto t2 = dump_pool_->enqueueTaskWithFd("", dump_func_2, std::placeholders::_1);
1757 auto t3 = dump_pool_->enqueueTaskWithFd("", dump_func_3, std::placeholders::_1);
1758
1759 WaitForTask(std::move(t1), "", out_fd_.get());
1760 WaitForTask(std::move(t2), "", out_fd_.get());
1761 WaitForTask(std::move(t3), "", out_fd_.get());
1762
1763 std::string result;
1764 ReadFileToString(out_path_, &result);
1765 EXPECT_THAT(result, StrEq("A\nB\nC\n"));
1766 EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
1767 }
1768
TEST_F(DumpPoolTest,EnqueueTask_withDurationLog)1769 TEST_F(DumpPoolTest, EnqueueTask_withDurationLog) {
1770 bool run_1 = false;
1771 auto dump_func_1 = [&]() {
1772 run_1 = true;
1773 };
1774
1775 auto t1 = dump_pool_->enqueueTask(/* duration_title = */"1", dump_func_1);
1776 WaitForTask(std::move(t1), "", out_fd_.get());
1777
1778 std::string result;
1779 ReadFileToString(out_path_, &result);
1780 EXPECT_TRUE(run_1);
1781 EXPECT_THAT(result, StrEq("------ 0.000s was the duration of '1' ------\n"));
1782 EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
1783 }
1784
1785 class TaskQueueTest : public DumpstateBaseTest {
1786 public:
SetUp()1787 void SetUp() {
1788 DumpstateBaseTest::SetUp();
1789 }
1790
1791 TaskQueue task_queue_;
1792 };
1793
TEST_F(TaskQueueTest,runTask)1794 TEST_F(TaskQueueTest, runTask) {
1795 bool is_task1_run = false;
1796 bool is_task2_run = false;
1797 auto task_1 = [&](bool task_cancelled) {
1798 if (task_cancelled) {
1799 return;
1800 }
1801 is_task1_run = true;
1802 };
1803 auto task_2 = [&](bool task_cancelled) {
1804 if (task_cancelled) {
1805 return;
1806 }
1807 is_task2_run = true;
1808 };
1809 task_queue_.add(task_1, std::placeholders::_1);
1810 task_queue_.add(task_2, std::placeholders::_1);
1811
1812 task_queue_.run(/* do_cancel = */false);
1813
1814 EXPECT_TRUE(is_task1_run);
1815 EXPECT_TRUE(is_task2_run);
1816 }
1817
TEST_F(TaskQueueTest,runTask_withCancelled)1818 TEST_F(TaskQueueTest, runTask_withCancelled) {
1819 bool is_task1_cancelled = false;
1820 bool is_task2_cancelled = false;
1821 auto task_1 = [&](bool task_cancelled) {
1822 is_task1_cancelled = task_cancelled;
1823 };
1824 auto task_2 = [&](bool task_cancelled) {
1825 is_task2_cancelled = task_cancelled;
1826 };
1827 task_queue_.add(task_1, std::placeholders::_1);
1828 task_queue_.add(task_2, std::placeholders::_1);
1829
1830 task_queue_.run(/* do_cancel = */true);
1831
1832 EXPECT_TRUE(is_task1_cancelled);
1833 EXPECT_TRUE(is_task2_cancelled);
1834 }
1835
1836
1837 } // namespace dumpstate
1838 } // namespace os
1839 } // namespace android
1840