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