blob: f26e4db976993be37cf0b9c1de6c0f0658b4f675 [file] [log] [blame]
Vishnu Naire97d6122018-01-18 13:58:56 -08001/*
2 * Copyright (C) 2018 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
Vishnu Naire97d6122018-01-18 13:58:56 -080017#include <android-base/file.h>
Nandana Dutt16d1aee2019-02-15 16:13:53 +000018#include <android/os/BnDumpstate.h>
19#include <android/os/BnDumpstateListener.h>
20#include <binder/IServiceManager.h>
21#include <binder/ProcessState.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080022#include <cutils/properties.h>
Nandana Duttea71b382019-07-05 09:19:42 +010023#include <fcntl.h>
24#include <gmock/gmock.h>
25#include <gtest/gtest.h>
26#include <libgen.h>
Vishnu Naire97d6122018-01-18 13:58:56 -080027#include <ziparchive/zip_archive.h>
28
Nandana Duttea71b382019-07-05 09:19:42 +010029#include <fstream>
30#include <regex>
31
Vishnu Naire97d6122018-01-18 13:58:56 -080032#include "dumpstate.h"
33
34#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
35
36namespace android {
37namespace os {
38namespace dumpstate {
39
40using ::testing::Test;
41using ::std::literals::chrono_literals::operator""s;
Nandana Dutt16d1aee2019-02-15 16:13:53 +000042using android::base::unique_fd;
43
44class DumpstateListener;
45
46namespace {
47
Nandana Duttea71b382019-07-05 09:19:42 +010048struct SectionInfo {
49 std::string name;
50 int32_t size_bytes;
51};
52
Nandana Dutt16d1aee2019-02-15 16:13:53 +000053sp<IDumpstate> GetDumpstateService() {
54 return android::interface_cast<IDumpstate>(
55 android::defaultServiceManager()->getService(String16("dumpstate")));
56}
57
58int OpenForWrite(const std::string& filename) {
59 return TEMP_FAILURE_RETRY(open(filename.c_str(),
60 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
61 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
62}
63
Nandana Duttea71b382019-07-05 09:19:42 +010064void GetEntry(const ZipArchiveHandle archive, const std::string_view entry_name, ZipEntry* data) {
65 int32_t e = FindEntry(archive, entry_name, data);
66 EXPECT_EQ(e, 0) << ErrorCodeString(e) << " entry name: " << entry_name;
67}
Vishnu Naire97d6122018-01-18 13:58:56 -080068
Nandana Duttea71b382019-07-05 09:19:42 +010069// Extracts the main bugreport txt from the given archive and writes into output_fd.
70void ExtractBugreport(const ZipArchiveHandle* handle, int output_fd) {
71 // Read contents of main_entry.txt which is a single line indicating the name of the zip entry
72 // that contains the main bugreport txt.
73 ZipEntry main_entry;
74 GetEntry(*handle, "main_entry.txt", &main_entry);
75 std::string bugreport_txt_name;
76 bugreport_txt_name.resize(main_entry.uncompressed_length);
77 ExtractToMemory(*handle, &main_entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
78 main_entry.uncompressed_length);
79
80 // Read the main bugreport txt and extract to output_fd.
81 ZipEntry entry;
82 GetEntry(*handle, bugreport_txt_name, &entry);
83 ExtractEntryToFile(*handle, &entry, output_fd);
84}
85
86bool IsSectionStart(const std::string& line, std::string* section_name) {
87 static const std::regex kSectionStart = std::regex{"DUMP OF SERVICE (.*):"};
88 std::smatch match;
89 if (std::regex_match(line, match, kSectionStart)) {
90 *section_name = match.str(1);
91 return true;
92 }
93 return false;
94}
95
96bool IsSectionEnd(const std::string& line) {
97 // Not all lines that contain "was the duration of" is a section end, but all section ends do
98 // contain "was the duration of". The disambiguation can be done by the caller.
99 return (line.find("was the duration of") != std::string::npos);
100}
101
102// Extracts the zipped bugreport and identifies the sections.
103void ParseSections(const std::string& zip_path, std::vector<SectionInfo>* sections) {
104 // Open the archive
105 ZipArchiveHandle handle;
106 ASSERT_EQ(OpenArchive(zip_path.c_str(), &handle), 0);
107
108 // Extract the main entry to a temp file
109 TemporaryFile tmp_binary;
110 ASSERT_NE(-1, tmp_binary.fd);
111 ExtractBugreport(&handle, tmp_binary.fd);
112
113 // Read line by line and identify sections
114 std::ifstream ifs(tmp_binary.path, std::ifstream::in);
115 std::string line;
116 int section_bytes = 0;
117 std::string current_section_name;
118 while (std::getline(ifs, line)) {
119 std::string section_name;
120 if (IsSectionStart(line, &section_name)) {
121 section_bytes = 0;
122 current_section_name = section_name;
123 } else if (IsSectionEnd(line)) {
124 if (!current_section_name.empty()) {
125 sections->push_back({current_section_name, section_bytes});
126 }
127 current_section_name = "";
128 } else if (!current_section_name.empty()) {
129 section_bytes += line.length();
130 }
131 }
132
133 CloseArchive(handle);
134}
135
136} // namespace
Vishnu Naire97d6122018-01-18 13:58:56 -0800137
138/**
139 * Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
140 * section details generated by dumpstate are added to a vector to be used by Tests later.
141 */
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000142class DumpstateListener : public BnDumpstateListener {
Vishnu Naire97d6122018-01-18 13:58:56 -0800143 public:
Vishnu Naire97d6122018-01-18 13:58:56 -0800144 DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000145 : out_fd_(fd), sections_(sections) {
Vishnu Naire97d6122018-01-18 13:58:56 -0800146 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000147
148 DumpstateListener(int fd) : out_fd_(fd) {
149 }
150
Nandana Dutta6a28bd2019-01-14 16:54:38 +0000151 binder::Status onProgress(int32_t progress) override {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000152 dprintf(out_fd_, "\rIn progress %d", progress);
Nandana Dutta6a28bd2019-01-14 16:54:38 +0000153 return binder::Status::ok();
154 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000155
Nandana Dutta6a28bd2019-01-14 16:54:38 +0000156 binder::Status onError(int32_t error_code) override {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000157 std::lock_guard<std::mutex> lock(lock_);
158 error_code_ = error_code;
159 dprintf(out_fd_, "\rError code %d", error_code);
Nandana Dutta6a28bd2019-01-14 16:54:38 +0000160 return binder::Status::ok();
161 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000162
Nandana Duttcc4ead82019-01-23 08:29:23 +0000163 binder::Status onFinished() override {
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000164 std::lock_guard<std::mutex> lock(lock_);
165 is_finished_ = true;
166 dprintf(out_fd_, "\rFinished");
Nandana Dutta6a28bd2019-01-14 16:54:38 +0000167 return binder::Status::ok();
168 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000169
Paul Chang0d2aad72020-02-13 20:04:03 +0800170 binder::Status onScreenshotTaken(bool success) override {
171 std::lock_guard<std::mutex> lock(lock_);
172 dprintf(out_fd_, "\rResult of taking screenshot: %s", success ? "success" : "failure");
173 return binder::Status::ok();
174 }
175
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000176 bool getIsFinished() {
177 std::lock_guard<std::mutex> lock(lock_);
178 return is_finished_;
Vishnu Naire97d6122018-01-18 13:58:56 -0800179 }
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000180
181 int getErrorCode() {
182 std::lock_guard<std::mutex> lock(lock_);
183 return error_code_;
184 }
185
186 private:
187 int out_fd_;
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000188 int error_code_ = -1;
189 bool is_finished_ = false;
190 std::shared_ptr<std::vector<SectionInfo>> sections_;
191 std::mutex lock_;
Vishnu Naire97d6122018-01-18 13:58:56 -0800192};
193
194/**
195 * Generates bug report and provide access to the bug report file and other info for other tests.
196 * Since bug report generation is slow, the bugreport is only generated once.
197 */
198class ZippedBugreportGenerationTest : public Test {
199 public:
200 static std::shared_ptr<std::vector<SectionInfo>> sections;
201 static Dumpstate& ds;
202 static std::chrono::milliseconds duration;
203 static void SetUpTestCase() {
Vishnu Naire97d6122018-01-18 13:58:56 -0800204 // clang-format off
205 char* argv[] = {
206 (char*)"dumpstate",
207 (char*)"-d",
208 (char*)"-z",
Abhijeet Kaur07d587b2019-08-29 14:11:57 +0100209 (char*)"-B"
Vishnu Naire97d6122018-01-18 13:58:56 -0800210 };
211 // clang-format on
212 sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
213 ds.listener_ = listener;
Vishnu Naire97d6122018-01-18 13:58:56 -0800214 auto start = std::chrono::steady_clock::now();
Nandana Duttf02564e2019-02-15 15:24:24 +0000215 ds.ParseCommandlineAndRun(ARRAY_SIZE(argv), argv);
Vishnu Naire97d6122018-01-18 13:58:56 -0800216 auto end = std::chrono::steady_clock::now();
217 duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
218 }
219
Nick Desaulniers5cc046e2019-10-07 20:37:31 -0700220 static const std::string getZipFilePath() {
221 return ds.GetPath(".zip");
Vishnu Naire97d6122018-01-18 13:58:56 -0800222 }
223};
224std::shared_ptr<std::vector<SectionInfo>> ZippedBugreportGenerationTest::sections =
225 std::make_shared<std::vector<SectionInfo>>();
226Dumpstate& ZippedBugreportGenerationTest::ds = Dumpstate::GetInstance();
227std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
228
229TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
Nick Desaulniers5cc046e2019-10-07 20:37:31 -0700230 EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
Vishnu Naire97d6122018-01-18 13:58:56 -0800231}
232
233TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
234 struct stat st;
Nick Desaulniers5cc046e2019-10-07 20:37:31 -0700235 EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
Vishnu Naire97d6122018-01-18 13:58:56 -0800236 EXPECT_GE(st.st_size, 3000000 /* 3MB */);
237 EXPECT_LE(st.st_size, 30000000 /* 30MB */);
238}
239
240TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) {
241 EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
242 << duration.count() << " s.";
243 EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time "
244 << duration.count() << " s.";
245}
246
247/**
248 * Run tests on contents of zipped bug report.
249 */
250class ZippedBugReportContentsTest : public Test {
251 public:
252 ZipArchiveHandle handle;
253 void SetUp() {
Nick Desaulniers5cc046e2019-10-07 20:37:31 -0700254 ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath().c_str(), &handle), 0);
Vishnu Naire97d6122018-01-18 13:58:56 -0800255 }
256 void TearDown() {
257 CloseArchive(handle);
258 }
259
260 void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
261 ZipEntry entry;
Nandana Duttea71b382019-07-05 09:19:42 +0100262 GetEntry(handle, filename, &entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800263 EXPECT_GT(entry.uncompressed_length, minsize);
264 EXPECT_LT(entry.uncompressed_length, maxsize);
265 }
266};
267
268TEST_F(ZippedBugReportContentsTest, ContainsMainEntry) {
Nandana Duttea71b382019-07-05 09:19:42 +0100269 ZipEntry main_entry;
Vishnu Naire97d6122018-01-18 13:58:56 -0800270 // contains main entry name file
Nandana Duttea71b382019-07-05 09:19:42 +0100271 GetEntry(handle, "main_entry.txt", &main_entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800272
Nandana Duttea71b382019-07-05 09:19:42 +0100273 std::string bugreport_txt_name;
274 bugreport_txt_name.resize(main_entry.uncompressed_length);
275 ExtractToMemory(handle, &main_entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
276 main_entry.uncompressed_length);
Vishnu Naire97d6122018-01-18 13:58:56 -0800277
278 // contains main entry file
Nandana Duttea71b382019-07-05 09:19:42 +0100279 FileExists(bugreport_txt_name.c_str(), 1000000U, 50000000U);
Vishnu Naire97d6122018-01-18 13:58:56 -0800280}
281
282TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
283 ZipEntry entry;
284 // contains main entry name file
Nandana Duttea71b382019-07-05 09:19:42 +0100285 GetEntry(handle, "version.txt", &entry);
Vishnu Naire97d6122018-01-18 13:58:56 -0800286
287 char* buf = new char[entry.uncompressed_length + 1];
288 ExtractToMemory(handle, &entry, (uint8_t*)buf, entry.uncompressed_length);
289 buf[entry.uncompressed_length] = 0;
290 EXPECT_STREQ(buf, ZippedBugreportGenerationTest::ds.version_.c_str());
291 delete[] buf;
292}
293
294TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) {
295 FileExists("dumpstate_board.bin", 1000000U, 80000000U);
296 FileExists("dumpstate_board.txt", 100000U, 1000000U);
297}
298
Nandana Duttea71b382019-07-05 09:19:42 +0100299TEST_F(ZippedBugReportContentsTest, ContainsProtoFile) {
300 FileExists("proto/activity.proto", 100000U, 1000000U);
301}
302
Vishnu Naire97d6122018-01-18 13:58:56 -0800303// Spot check on some files pulled from the file system
304TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) {
305 // FS/proc/*/mountinfo size > 0
306 FileExists("FS/proc/1/mountinfo", 0U, 100000U);
307
308 // FS/data/misc/profiles/cur/0/*/primary.prof size > 0
309 FileExists("FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", 0U, 100000U);
310}
311
312/**
313 * Runs tests on section data generated by dumpstate and captured by DumpstateListener.
314 */
315class BugreportSectionTest : public Test {
316 public:
Nandana Duttea71b382019-07-05 09:19:42 +0100317 static void SetUpTestCase() {
Nick Desaulniers5cc046e2019-10-07 20:37:31 -0700318 ParseSections(ZippedBugreportGenerationTest::getZipFilePath().c_str(),
Nandana Duttea71b382019-07-05 09:19:42 +0100319 ZippedBugreportGenerationTest::sections.get());
320 }
321
Vishnu Naire97d6122018-01-18 13:58:56 -0800322 int numMatches(const std::string& substring) {
323 int matches = 0;
324 for (auto const& section : *ZippedBugreportGenerationTest::sections) {
325 if (section.name.find(substring) != std::string::npos) {
326 matches++;
327 }
328 }
329 return matches;
330 }
Nandana Duttea71b382019-07-05 09:19:42 +0100331
Vishnu Naire97d6122018-01-18 13:58:56 -0800332 void SectionExists(const std::string& sectionName, int minsize) {
333 for (auto const& section : *ZippedBugreportGenerationTest::sections) {
334 if (sectionName == section.name) {
Nandana Duttea71b382019-07-05 09:19:42 +0100335 EXPECT_GE(section.size_bytes, minsize) << " for section:" << sectionName;
Vishnu Naire97d6122018-01-18 13:58:56 -0800336 return;
337 }
338 }
339 FAIL() << sectionName << " not found.";
340 }
341};
342
Vishnu Naire97d6122018-01-18 13:58:56 -0800343TEST_F(BugreportSectionTest, Atleast3CriticalDumpsysSectionsGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100344 int numSections = numMatches("CRITICAL");
Vishnu Naire97d6122018-01-18 13:58:56 -0800345 EXPECT_GE(numSections, 3);
346}
347
348TEST_F(BugreportSectionTest, Atleast2HighDumpsysSectionsGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100349 int numSections = numMatches("HIGH");
Vishnu Naire97d6122018-01-18 13:58:56 -0800350 EXPECT_GE(numSections, 2);
351}
352
353TEST_F(BugreportSectionTest, Atleast50NormalDumpsysSectionsGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100354 int allSections = ZippedBugreportGenerationTest::sections->size();
355 int criticalSections = numMatches("CRITICAL");
356 int highSections = numMatches("HIGH");
Vishnu Naire97d6122018-01-18 13:58:56 -0800357 int normalSections = allSections - criticalSections - highSections;
358
359 EXPECT_GE(normalSections, 50) << "Total sections less than 50 (Critical:" << criticalSections
360 << "High:" << highSections << "Normal:" << normalSections << ")";
361}
362
Vishnu Naire97d6122018-01-18 13:58:56 -0800363// Test if some critical sections are being generated.
364TEST_F(BugreportSectionTest, CriticalSurfaceFlingerSectionGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100365 SectionExists("CRITICAL SurfaceFlinger", /* bytes= */ 10000);
Vishnu Naire97d6122018-01-18 13:58:56 -0800366}
367
368TEST_F(BugreportSectionTest, ActivitySectionsGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100369 SectionExists("CRITICAL activity", /* bytes= */ 5000);
370 SectionExists("activity", /* bytes= */ 10000);
Vishnu Naire97d6122018-01-18 13:58:56 -0800371}
372
373TEST_F(BugreportSectionTest, CpuinfoSectionGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100374 SectionExists("CRITICAL cpuinfo", /* bytes= */ 1000);
Vishnu Naire97d6122018-01-18 13:58:56 -0800375}
376
377TEST_F(BugreportSectionTest, WindowSectionGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100378 SectionExists("CRITICAL window", /* bytes= */ 20000);
Vishnu Naire97d6122018-01-18 13:58:56 -0800379}
380
381TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100382 SectionExists("HIGH connectivity", /* bytes= */ 3000);
383 SectionExists("connectivity", /* bytes= */ 5000);
Vishnu Naire97d6122018-01-18 13:58:56 -0800384}
385
386TEST_F(BugreportSectionTest, MeminfoSectionGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100387 SectionExists("HIGH meminfo", /* bytes= */ 100000);
Vishnu Naire97d6122018-01-18 13:58:56 -0800388}
389
390TEST_F(BugreportSectionTest, BatteryStatsSectionGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100391 SectionExists("batterystats", /* bytes= */ 1000);
Vishnu Naire97d6122018-01-18 13:58:56 -0800392}
393
394TEST_F(BugreportSectionTest, WifiSectionGenerated) {
Nandana Duttea71b382019-07-05 09:19:42 +0100395 SectionExists("wifi", /* bytes= */ 100000);
Vishnu Naire97d6122018-01-18 13:58:56 -0800396}
397
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000398class DumpstateBinderTest : public Test {
399 protected:
400 void SetUp() override {
401 // In case there is a stray service, stop it first.
402 property_set("ctl.stop", "bugreportd");
403 // dry_run results in a faster bugreport.
404 property_set("dumpstate.dry_run", "true");
405 // We need to receive some async calls later. Ensure we have binder threads.
406 ProcessState::self()->startThreadPool();
407 }
408
409 void TearDown() override {
410 property_set("ctl.stop", "bugreportd");
411 property_set("dumpstate.dry_run", "");
412
413 unlink("/data/local/tmp/tmp.zip");
414 unlink("/data/local/tmp/tmp.png");
415 }
416
417 // Waits until listener gets the callbacks.
418 void WaitTillExecutionComplete(DumpstateListener* listener) {
419 // Wait till one of finished, error or timeout.
420 static const int kBugreportTimeoutSeconds = 120;
421 int i = 0;
422 while (!listener->getIsFinished() && listener->getErrorCode() == -1 &&
423 i < kBugreportTimeoutSeconds) {
424 sleep(1);
425 i++;
426 }
427 }
428};
429
430TEST_F(DumpstateBinderTest, Baseline) {
431 // In the beginning dumpstate binder service is not running.
432 sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
433 EXPECT_EQ(ds_binder, nullptr);
434
435 // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
436 // and makes it wait.
437 property_set("dumpstate.dry_run", "true");
438 property_set("ctl.start", "bugreportd");
439
440 // Now we are able to retrieve dumpstate binder service.
441 ds_binder = GetDumpstateService();
442 EXPECT_NE(ds_binder, nullptr);
443
444 // Prepare arguments
445 unique_fd bugreport_fd(OpenForWrite("/bugreports/tmp.zip"));
446 unique_fd screenshot_fd(OpenForWrite("/bugreports/tmp.png"));
447
448 EXPECT_NE(bugreport_fd.get(), -1);
449 EXPECT_NE(screenshot_fd.get(), -1);
450
451 sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
452 android::binder::Status status =
Jiyong Park3b25ae12019-11-25 11:06:16 +0900453 ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000454 Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener);
455 // startBugreport is an async call. Verify binder call succeeded first, then wait till listener
456 // gets expected callbacks.
457 EXPECT_TRUE(status.isOk());
458 WaitTillExecutionComplete(listener.get());
459
460 // Bugreport generation requires user consent, which we cannot get in a test set up,
461 // so instead of getting is_finished_, we are more likely to get a consent error.
462 EXPECT_TRUE(
463 listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
464 listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
465
466 // The service should have died on its own, freeing itself up for a new invocation.
467 sleep(2);
468 ds_binder = GetDumpstateService();
469 EXPECT_EQ(ds_binder, nullptr);
470}
471
472TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) {
473 // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
474 // and makes it wait.
475 property_set("ctl.start", "bugreportd");
476 sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
477 EXPECT_NE(ds_binder, nullptr);
478
479 // Prepare arguments
480 unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
481 unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
482
483 EXPECT_NE(bugreport_fd.get(), -1);
484 EXPECT_NE(screenshot_fd.get(), -1);
485
486 // Call startBugreport with bad arguments.
487 sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
488 android::binder::Status status =
Jiyong Park3b25ae12019-11-25 11:06:16 +0900489 ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000490 2000, // invalid bugreport mode
491 listener);
492 EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
493
494 // The service should have died, freeing itself up for a new invocation.
495 sleep(2);
496 ds_binder = GetDumpstateService();
497 EXPECT_EQ(ds_binder, nullptr);
498}
499
500TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) {
501 // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
502 // and makes it wait.
503 property_set("dumpstate.dry_run", "true");
504 property_set("ctl.start", "bugreportd");
505 sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
506 EXPECT_NE(ds_binder, nullptr);
507
508 // Prepare arguments
509 unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
Jiyong Park3b25ae12019-11-25 11:06:16 +0900510 unique_fd bugreport_fd2(dup(bugreport_fd.get()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000511 unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
Jiyong Park3b25ae12019-11-25 11:06:16 +0900512 unique_fd screenshot_fd2(dup(screenshot_fd.get()));
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000513
514 EXPECT_NE(bugreport_fd.get(), -1);
Jiyong Park3b25ae12019-11-25 11:06:16 +0900515 EXPECT_NE(bugreport_fd2.get(), -1);
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000516 EXPECT_NE(screenshot_fd.get(), -1);
Jiyong Park3b25ae12019-11-25 11:06:16 +0900517 EXPECT_NE(screenshot_fd2.get(), -1);
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000518
519 sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout))));
520 android::binder::Status status =
Jiyong Park3b25ae12019-11-25 11:06:16 +0900521 ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000522 Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1);
523 EXPECT_TRUE(status.isOk());
524
525 // try to make another call to startBugreport. This should fail.
526 sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout))));
Jiyong Park3b25ae12019-11-25 11:06:16 +0900527 status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd2), std::move(screenshot_fd2),
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000528 Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2);
529 EXPECT_FALSE(status.isOk());
530 WaitTillExecutionComplete(listener2.get());
Nandana Dutt41d7dac2019-02-19 13:05:37 +0000531 EXPECT_EQ(listener2->getErrorCode(),
Nandana Dutt0eb86bf2019-02-21 16:10:10 +0000532 IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
Nandana Dutt16d1aee2019-02-15 16:13:53 +0000533
534 // Meanwhile the first call works as expected. Service should not die in this case.
535 WaitTillExecutionComplete(listener1.get());
536
537 // Bugreport generation requires user consent, which we cannot get in a test set up,
538 // so instead of getting is_finished_, we are more likely to get a consent error.
539 EXPECT_TRUE(
540 listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
541 listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
542}
543
Vishnu Naire97d6122018-01-18 13:58:56 -0800544} // namespace dumpstate
545} // namespace os
546} // namespace android