1 /*
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 
17 #include "src/profiling/common/proc_utils.h"
18 #include "perfetto/ext/base/optional.h"
19 #include "perfetto/profiling/normalize.h"
20 
21 #include "perfetto/ext/base/utils.h"
22 #include "test/gtest_and_gmock.h"
23 
24 namespace perfetto {
25 namespace profiling {
26 namespace {
27 
28 using ::testing::Contains;
29 using ::testing::Not;
30 
NormalizeToString(char * cmdline,size_t size)31 std::string NormalizeToString(char* cmdline, size_t size) {
32   ssize_t new_size = NormalizeCmdLine(&cmdline, size);
33   if (new_size == -1)
34     return "";
35   return std::string(cmdline, static_cast<size_t>(new_size));
36 }
37 
TEST(ProcUtilsTest,NormalizeNoop)38 TEST(ProcUtilsTest, NormalizeNoop) {
39   char kCmdline[] = "surfaceflinger";
40   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "surfaceflinger");
41 }
42 
TEST(ProcUtilsTest,NormalizeTwoArgs)43 TEST(ProcUtilsTest, NormalizeTwoArgs) {
44   char kCmdline[] = "surfaceflinger\0--foo";
45   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "surfaceflinger");
46 }
47 
TEST(ProcUtilsTest,NormalizePath)48 TEST(ProcUtilsTest, NormalizePath) {
49   char kCmdline[] = "/system/bin/surfaceflinger";
50   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "surfaceflinger");
51 }
52 
TEST(ProcUtilsTest,NormalizeAt)53 TEST(ProcUtilsTest, NormalizeAt) {
54   char kCmdline[] = "some.app@2.0";
55   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "some.app");
56 }
57 
TEST(ProcUtilsTest,NormalizeEmpty)58 TEST(ProcUtilsTest, NormalizeEmpty) {
59   char kCmdline[] = "";
60   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "");
61 }
62 
TEST(ProcUtilsTest,NormalizeTrailingAt)63 TEST(ProcUtilsTest, NormalizeTrailingAt) {
64   char kCmdline[] = "foo@";
65   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "foo");
66 }
67 
TEST(ProcUtilsTest,NormalizeOnlyTrailingAt)68 TEST(ProcUtilsTest, NormalizeOnlyTrailingAt) {
69   char kCmdline[] = "@";
70   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "");
71 }
72 
TEST(ProcUtilsTest,NormalizeTrailingSlash)73 TEST(ProcUtilsTest, NormalizeTrailingSlash) {
74   char kCmdline[] = "foo/";
75   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "");
76 }
77 
TEST(ProcUtilsTest,NormalizeOnlySlash)78 TEST(ProcUtilsTest, NormalizeOnlySlash) {
79   char kCmdline[] = "/";
80   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "");
81 }
82 
TEST(ProcUtilsTest,NormalizeTwoArgsSlash)83 TEST(ProcUtilsTest, NormalizeTwoArgsSlash) {
84   char kCmdline[] = "surfaceflinger/\0--foo";
85   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "");
86 }
87 
TEST(ProcUtilsTest,NormalizeEmptyFirstArg)88 TEST(ProcUtilsTest, NormalizeEmptyFirstArg) {
89   char kCmdline[] = "\0--foo";
90   EXPECT_EQ(NormalizeToString(kCmdline, sizeof(kCmdline)), "");
91 }
92 
TEST(ProcUtilsTest,NormalizeNoNullTerminated)93 TEST(ProcUtilsTest, NormalizeNoNullTerminated) {
94   char kCmdline[] = {'f'};
95   char* cmdline = kCmdline;
96   EXPECT_EQ(NormalizeCmdLine(&cmdline, sizeof(kCmdline)), -1);
97 }
98 
TEST(ProcUtilsTest,NormalizeZeroLength)99 TEST(ProcUtilsTest, NormalizeZeroLength) {
100   char* cmdline = nullptr;
101   EXPECT_EQ(NormalizeCmdLine(&cmdline, 0), -1);
102 }
103 
TEST(ProcUtilsTest,FindProfilablePids)104 TEST(ProcUtilsTest, FindProfilablePids) {
105   std::set<pid_t> pids;
106   int pipefds[2];
107   PERFETTO_CHECK(pipe(pipefds) == 0);
108   pid_t pid = fork();
109   PERFETTO_CHECK(pid >= 0);
110   switch (pid) {
111     case 0: {
112       close(pipefds[1]);
113       char buf[1];
114       // Block until the other end shuts down the pipe.
115       read(pipefds[0], buf, sizeof(buf));
116       exit(0);
117     }
118     default:
119       close(pipefds[0]);
120       break;
121   }
122   FindAllProfilablePids(&pids);
123   close(pipefds[1]);
124   EXPECT_THAT(pids, Contains(pid));
125   EXPECT_THAT(pids, Not(Contains(getpid())));
126   PERFETTO_CHECK(PERFETTO_EINTR(waitpid(pid, nullptr, 0)) == pid);
127 }
128 
TEST(ProcUtilsTest,GetRssAnonAndSwap)129 TEST(ProcUtilsTest, GetRssAnonAndSwap) {
130   std::string status = "Name: foo\nRssAnon:  10000 kB\nVmSwap:\t10000 kB";
131   EXPECT_EQ(GetRssAnonAndSwap(status), 20000u);
132 }
133 
TEST(ProcUtilsTest,GetRssAnonAndSwapInvalidInput)134 TEST(ProcUtilsTest, GetRssAnonAndSwapInvalidInput) {
135   EXPECT_EQ(GetRssAnonAndSwap(""), base::nullopt);
136   EXPECT_EQ(GetRssAnonAndSwap("RssAnon: 10000 kB"), base::nullopt);
137   EXPECT_EQ(GetRssAnonAndSwap("VmSwap: 10000"), base::nullopt);
138 }
139 
TEST(ProcUtilsTest,GetUids)140 TEST(ProcUtilsTest, GetUids) {
141   std::string status =
142       "Name: foo\nRssAnon:  10000 kB\nVmSwap:\t10000 kB\n"
143       "Uid: 1 2 3 4\n";
144   auto uids = GetUids(status);
145   ASSERT_NE(uids, base::nullopt);
146   EXPECT_EQ(uids->real, 1u);
147   EXPECT_EQ(uids->effective, 2u);
148   EXPECT_EQ(uids->saved_set, 3u);
149   EXPECT_EQ(uids->filesystem, 4u);
150 }
151 
TEST(ProcUtilsTest,GetUidsInvalidInt)152 TEST(ProcUtilsTest, GetUidsInvalidInt) {
153   std::string status =
154       "Name: foo\nRssAnon:  10000 kB\nVmSwap:\t10000 kB\n"
155       "Uid: 1a 2 3 4\n";
156   auto uids = GetUids(status);
157   EXPECT_EQ(uids, base::nullopt);
158 }
159 
TEST(ProcUtilsTest,GetUidsInvalidTooFew)160 TEST(ProcUtilsTest, GetUidsInvalidTooFew) {
161   std::string status =
162       "Name: foo\nRssAnon:  10000 kB\nVmSwap:\t10000 kB\n"
163       "Uid: 1 2 3\n";
164   auto uids = GetUids(status);
165   EXPECT_EQ(uids, base::nullopt);
166 }
167 
168 }  // namespace
169 }  // namespace profiling
170 }  // namespace perfetto
171