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