1 // Copyright (C) 2017 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 #define DEBUG false 15 #include "Log.h" 16 17 #include "Section.h" 18 19 #include <android-base/file.h> 20 #include <android-base/test_utils.h> 21 #include <android/os/IncidentReportArgs.h> 22 #include <android/util/protobuf.h> 23 #include <frameworks/base/core/proto/android/os/incident.pb.h> 24 #include <frameworks/base/core/proto/android/os/header.pb.h> 25 #include <gmock/gmock.h> 26 #include <gtest/gtest.h> 27 #include <string.h> 28 29 using namespace android; 30 using namespace android::base; 31 using namespace android::binder; 32 using namespace android::os; 33 using namespace android::os::incidentd; 34 using namespace android::util; 35 using ::testing::StrEq; 36 using ::testing::Test; 37 using ::testing::internal::CaptureStdout; 38 using ::testing::internal::GetCapturedStdout; 39 40 const int TIMEOUT_PARSER = -1; 41 const int NOOP_PARSER = 0; 42 const int REVERSE_PARSER = 1; 43 44 const int QUICK_TIMEOUT_MS = 100; 45 46 const std::string VARINT_FIELD_1 = "\x08\x96\x01"; // 150 47 const std::string STRING_FIELD_2 = "\x12\vandroidwins"; 48 const std::string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1 49 50 // NOTICE: this test requires /system/bin/incident_helper is installed. 51 class SectionTest : public Test { 52 public: SetUp()53 virtual void SetUp() override { ASSERT_NE(tf.fd, -1); } 54 printDebugString(std::string s)55 void printDebugString(std::string s) { 56 fprintf(stderr, "size: %zu\n", s.length()); 57 for (size_t i = 0; i < s.length(); i++) { 58 char c = s[i]; 59 fprintf(stderr, "\\x%x", c); 60 } 61 fprintf(stderr, "\n"); 62 } 63 64 protected: 65 TemporaryFile tf; 66 67 const std::string kTestPath = GetExecutableDirectory(); 68 const std::string kTestDataPath = kTestPath + "/testdata/"; 69 }; 70 71 class SimpleListener : public IIncidentReportStatusListener { 72 public: SimpleListener()73 SimpleListener(){}; ~SimpleListener()74 virtual ~SimpleListener(){}; 75 onReportStarted()76 virtual Status onReportStarted() { return Status::ok(); }; onReportSectionStatus(int,int)77 virtual Status onReportSectionStatus(int /*section*/, int /*status*/) 78 { return Status::ok(); }; onReportFinished()79 virtual Status onReportFinished() { return Status::ok(); }; onReportFailed()80 virtual Status onReportFailed() { return Status::ok(); }; 81 82 protected: onAsBinder()83 virtual IBinder* onAsBinder() override { return nullptr; }; 84 }; 85 86 /* 87 TEST_F(SectionTest, MetadataSection) { 88 MetadataSection ms; 89 90 vector<sp<ReportRequest>> requests; 91 ReportRequestSet requestSet(requests); 92 requestSet.setMainFd(STDOUT_FILENO); 93 94 requestSet.setMainPrivacyPolicy(android::os::PRIVACY_POLICY_LOCAL); 95 requestSet.editSectionStats(1)->set_success(true); 96 97 CaptureStdout(); 98 ASSERT_EQ(NO_ERROR, ms.Execute(&requestSet)); 99 100 string out = GetCapturedStdout(); 101 IncidentProto expectedIncident; 102 expectedIncident.ParseFromArray(out.data(), out.size()); 103 ASSERT_TRUE(expectedIncident.has_metadata()); 104 const IncidentMetadata& expectedMetadata = expectedIncident.metadata(); 105 ASSERT_EQ(IncidentMetadata::LOCAL, expectedMetadata.dest()); 106 ASSERT_EQ(1, expectedMetadata.sections_size()); 107 ASSERT_EQ(1, expectedMetadata.sections(0).id()); 108 ASSERT_TRUE(expectedMetadata.sections(0).has_success()); 109 ASSERT_TRUE(expectedMetadata.sections(0).success()); 110 } 111 112 TEST_F(SectionTest, FileSection) { 113 FileSection fs(REVERSE_PARSER, tf.path); 114 115 ASSERT_TRUE(WriteStringToFile("iamtestdata", tf.path)); 116 117 vector<sp<ReportRequest>> requests; 118 ReportRequestSet requestSet(requests); 119 requestSet.setMainFd(STDOUT_FILENO); 120 121 CaptureStdout(); 122 ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet)); 123 // The input string is reversed in incident helper 124 // The length is 11, in 128Varint it is "0000 1011" -> \v 125 EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\vatadtsetmai")); 126 } 127 128 TEST_F(SectionTest, FileSectionNotExist) { 129 vector<sp<ReportRequest>> requests; 130 ReportRequestSet requestSet(requests); 131 132 FileSection fs1(NOOP_PARSER, "notexist", QUICK_TIMEOUT_MS); 133 ASSERT_EQ(NO_ERROR, fs1.Execute(&requestSet)); 134 135 FileSection fs2(NOOP_PARSER, "notexist", QUICK_TIMEOUT_MS); 136 ASSERT_EQ(NO_ERROR, fs2.Execute(&requestSet)); 137 } 138 139 TEST_F(SectionTest, FileSectionTimeout) { 140 vector<sp<ReportRequest>> requests; 141 ReportRequestSet requestSet(requests); 142 143 FileSection fs(TIMEOUT_PARSER, tf.path, QUICK_TIMEOUT_MS); 144 ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet)); 145 ASSERT_TRUE(requestSet.getSectionStats(TIMEOUT_PARSER)->timed_out()); 146 } 147 148 TEST_F(SectionTest, GZipSection) { 149 const std::string testFile = kTestDataPath + "kmsg.txt"; 150 const std::string testGzFile = testFile + ".gz"; 151 GZipSection gs(NOOP_PARSER, "/tmp/nonexist", testFile.c_str(), NULL); 152 153 vector<sp<ReportRequest>> requests; 154 ReportRequestSet requestSet(requests); 155 requestSet.setMainFd(tf.fd); 156 requestSet.setMainPrivacyPolicy(android::os::PRIVACY_POLICY_LOCAL); 157 158 ASSERT_EQ(NO_ERROR, gs.Execute(&requestSet)); 159 std::string expected, gzFile, actual; 160 ASSERT_TRUE(ReadFileToString(testGzFile, &gzFile)); 161 ASSERT_TRUE(ReadFileToString(tf.path, &actual)); 162 // generates the expected protobuf result. 163 size_t fileLen = testFile.size(); 164 size_t totalLen = 1 + get_varint_size(fileLen) + fileLen + 3 + gzFile.size(); 165 uint8_t header[20]; 166 header[0] = '\x2'; // header 0 << 3 + 2 167 uint8_t* ptr = write_raw_varint(header + 1, totalLen); 168 *ptr = '\n'; // header 1 << 3 + 2 169 ptr = write_raw_varint(++ptr, fileLen); 170 expected.assign((const char*)header, ptr - header); 171 expected += testFile + "\x12\x9F\x6" + gzFile; 172 EXPECT_THAT(actual, StrEq(expected)); 173 } 174 175 TEST_F(SectionTest, GZipSectionNoFileFound) { 176 GZipSection gs(NOOP_PARSER, "/tmp/nonexist1", "/tmp/nonexist2", NULL); 177 vector<sp<ReportRequest>> requests; 178 ReportRequestSet requestSet(requests); 179 requestSet.setMainFd(STDOUT_FILENO); 180 ASSERT_EQ(NO_ERROR, gs.Execute(&requestSet)); 181 } 182 183 TEST_F(SectionTest, CommandSectionConstructor) { 184 CommandSection cs1(1, "echo", "\"this is a test\"", "ooo", NULL); 185 CommandSection cs2(2, "single_command", NULL); 186 CommandSection cs3(1, 3123, "echo", "\"this is a test\"", "ooo", NULL); 187 CommandSection cs4(2, 43214, "single_command", NULL); 188 189 EXPECT_THAT(cs1.name.string(), StrEq("cmd echo \"this is a test\" ooo")); 190 EXPECT_THAT(cs2.name.string(), StrEq("cmd single_command")); 191 EXPECT_EQ(3123, cs3.timeoutMs); 192 EXPECT_EQ(43214, cs4.timeoutMs); 193 EXPECT_THAT(cs3.name.string(), StrEq("cmd echo \"this is a test\" ooo")); 194 EXPECT_THAT(cs4.name.string(), StrEq("cmd single_command")); 195 } 196 197 TEST_F(SectionTest, CommandSectionEcho) { 198 CommandSection cs(REVERSE_PARSER, "/system/bin/echo", "about", NULL); 199 vector<sp<ReportRequest>> requests; 200 ReportRequestSet requestSet(requests); 201 requestSet.setMainFd(STDOUT_FILENO); 202 CaptureStdout(); 203 ASSERT_EQ(NO_ERROR, cs.Execute(&requestSet)); 204 EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\x06\ntuoba")); 205 } 206 207 TEST_F(SectionTest, CommandSectionCommandTimeout) { 208 CommandSection cs(NOOP_PARSER, QUICK_TIMEOUT_MS, "/system/bin/yes", NULL); 209 vector<sp<ReportRequest>> requests; 210 ReportRequestSet requestSet(requests); 211 ASSERT_EQ(NO_ERROR, cs.Execute(&requestSet)); 212 ASSERT_TRUE(requestSet.getSectionStats(NOOP_PARSER)->timed_out()); 213 } 214 215 TEST_F(SectionTest, CommandSectionIncidentHelperTimeout) { 216 CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "/system/bin/echo", "about", NULL); 217 vector<sp<ReportRequest>> requests; 218 ReportRequestSet requestSet(requests); 219 requestSet.setMainFd(STDOUT_FILENO); 220 ASSERT_EQ(NO_ERROR, cs.Execute(&requestSet)); 221 ASSERT_TRUE(requestSet.getSectionStats(TIMEOUT_PARSER)->timed_out()); 222 } 223 224 TEST_F(SectionTest, CommandSectionBadCommand) { 225 CommandSection cs(NOOP_PARSER, "echoo", "about", NULL); 226 vector<sp<ReportRequest>> requests; 227 ReportRequestSet requestSet(requests); 228 ASSERT_EQ(NAME_NOT_FOUND, cs.Execute(&requestSet)); 229 } 230 231 TEST_F(SectionTest, CommandSectionBadCommandAndTimeout) { 232 CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "nonexistcommand", "-opt", NULL); 233 // timeout will return first 234 vector<sp<ReportRequest>> requests; 235 ReportRequestSet requestSet(requests); 236 ASSERT_EQ(NO_ERROR, cs.Execute(&requestSet)); 237 ASSERT_TRUE(requestSet.getSectionStats(TIMEOUT_PARSER)->timed_out()); 238 } 239 240 TEST_F(SectionTest, LogSectionBinary) { 241 LogSection ls(1, LOG_ID_EVENTS); 242 vector<sp<ReportRequest>> requests; 243 ReportRequestSet requestSet(requests); 244 requestSet.setMainFd(STDOUT_FILENO); 245 CaptureStdout(); 246 ASSERT_EQ(NO_ERROR, ls.Execute(&requestSet)); 247 std::string results = GetCapturedStdout(); 248 EXPECT_FALSE(results.empty()); 249 } 250 251 TEST_F(SectionTest, LogSectionSystem) { 252 LogSection ls(1, LOG_ID_SYSTEM); 253 vector<sp<ReportRequest>> requests; 254 ReportRequestSet requestSet(requests); 255 requestSet.setMainFd(STDOUT_FILENO); 256 CaptureStdout(); 257 ASSERT_EQ(NO_ERROR, ls.Execute(&requestSet)); 258 std::string results = GetCapturedStdout(); 259 EXPECT_FALSE(results.empty()); 260 } 261 262 TEST_F(SectionTest, TestFilterPiiTaggedFields) { 263 FileSection fs(NOOP_PARSER, tf.path); 264 265 ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); 266 267 vector<sp<ReportRequest>> requests; 268 ReportRequestSet requestSet(requests); 269 requestSet.setMainFd(STDOUT_FILENO); 270 271 CaptureStdout(); 272 ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet)); 273 EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2)); 274 } 275 276 TEST_F(SectionTest, TestBadFdRequest) { 277 FileSection fs(NOOP_PARSER, tf.path); 278 ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); 279 280 IncidentReportArgs args; 281 args.setAll(true); 282 args.setPrivacyPolicy(0); 283 sp<ReportRequest> badFdRequest = new ReportRequest(args, new SimpleListener(), 1234567); 284 285 vector<sp<ReportRequest>> requests; 286 requests.push_back(badFdRequest); 287 ReportRequestSet requestSet(requests); 288 requestSet.setMainFd(STDOUT_FILENO); 289 290 CaptureStdout(); 291 ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet)); 292 EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2)); 293 EXPECT_EQ(badFdRequest->err, -EBADF); 294 } 295 296 TEST_F(SectionTest, TestBadRequests) { 297 FileSection fs(NOOP_PARSER, tf.path); 298 ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); 299 300 IncidentReportArgs args; 301 args.setAll(true); 302 args.setPrivacyPolicy(0); 303 304 vector<sp<ReportRequest>> requests; 305 requests.push_back(new ReportRequest(args, new SimpleListener(), -1)); 306 ReportRequestSet requestSet(requests); 307 308 EXPECT_EQ(fs.Execute(&requestSet), -EBADF); 309 } 310 311 TEST_F(SectionTest, TestMultipleRequests) { 312 TemporaryFile output1, output2, output3; 313 FileSection fs(NOOP_PARSER, tf.path); 314 315 ASSERT_TRUE(output1.fd != -1); 316 ASSERT_TRUE(output2.fd != -1); 317 ASSERT_TRUE(output3.fd != -1); 318 ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); 319 320 IncidentReportArgs args1, args2, args3; 321 args1.setAll(true); 322 args1.setPrivacyPolicy(android::os::PRIVACY_POLICY_LOCAL); 323 args2.setAll(true); 324 args2.setPrivacyPolicy(android::os::PRIVACY_POLICY_EXPLICIT); 325 sp<SimpleListener> l = new SimpleListener(); 326 327 vector<sp<ReportRequest>> requests; 328 requests.push_back(new ReportRequest(args1, l, output1.fd)); 329 requests.push_back(new ReportRequest(args2, l, output2.fd)); 330 requests.push_back(new ReportRequest(args3, l, output3.fd)); 331 ReportRequestSet requestSet(requests); 332 requestSet.setMainFd(STDOUT_FILENO); 333 334 CaptureStdout(); 335 ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet)); 336 EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2)); 337 338 std::string content, expect; 339 expect = VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3; 340 char c = (char)expect.size(); 341 EXPECT_TRUE(ReadFileToString(output1.path, &content)); 342 EXPECT_THAT(content, StrEq(string("\x02") + c + expect)); 343 344 expect = STRING_FIELD_2 + FIX64_FIELD_3; 345 c = (char)expect.size(); 346 EXPECT_TRUE(ReadFileToString(output2.path, &content)); 347 EXPECT_THAT(content, StrEq(string("\x02") + c + expect)); 348 349 // because args3 doesn't set section, so it should receive nothing 350 EXPECT_TRUE(ReadFileToString(output3.path, &content)); 351 EXPECT_THAT(content, StrEq("")); 352 } 353 354 TEST_F(SectionTest, TestMultipleRequestsBySpec) { 355 TemporaryFile output1, output2, output3; 356 FileSection fs(NOOP_PARSER, tf.path); 357 358 ASSERT_TRUE(output1.fd != -1); 359 ASSERT_TRUE(output2.fd != -1); 360 ASSERT_TRUE(output3.fd != -1); 361 362 ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); 363 364 IncidentReportArgs args1, args2, args3; 365 args1.setAll(true); 366 args1.setPrivacyPolicy(android::os::PRIVACY_POLICY_EXPLICIT); 367 args2.setAll(true); 368 args2.setPrivacyPolicy(android::os::PRIVACY_POLICY_EXPLICIT); 369 args3.setAll(true); 370 sp<SimpleListener> l = new SimpleListener(); 371 372 vector<sp<ReportRequest>> requests; 373 requests.push_back(new ReportRequest(args1, l, output1.fd)); 374 requests.push_back(new ReportRequest(args2, l, output2.fd)); 375 requests.push_back(new ReportRequest(args3, l, output3.fd)); 376 ReportRequestSet requestSet(requests); 377 requestSet.setMainFd(STDOUT_FILENO); 378 379 CaptureStdout(); 380 ASSERT_EQ(NO_ERROR, fs.Execute(&requestSet)); 381 EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2)); 382 383 std::string content, expect; 384 expect = STRING_FIELD_2 + FIX64_FIELD_3; 385 char c = (char)expect.size(); 386 387 // output1 and output2 are the same 388 EXPECT_TRUE(ReadFileToString(output1.path, &content)); 389 EXPECT_THAT(content, StrEq(string("\x02") + c + expect)); 390 EXPECT_TRUE(ReadFileToString(output2.path, &content)); 391 EXPECT_THAT(content, StrEq(string("\x02") + c + expect)); 392 393 // output3 has only auto field 394 c = (char)STRING_FIELD_2.size(); 395 EXPECT_TRUE(ReadFileToString(output3.path, &content)); 396 EXPECT_THAT(content, StrEq(string("\x02") + c + STRING_FIELD_2)); 397 } 398 */ 399