1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/process_info_snapshot.h"
6
7 #include <sys/types.h> // For |uid_t| (and |pid_t|).
8 #include <unistd.h> // For |getpid()|, |getuid()|, etc.
9
10 #include <vector>
11
12 #include "base/command_line.h"
13 #include "base/eintr_wrapper.h"
14 #include "base/file_path.h"
15 #include "base/logging.h"
16 #include "base/process_util.h"
17
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 typedef testing::Test ProcessInfoSnapshotMacTest;
21
TEST_F(ProcessInfoSnapshotMacTest,FindPidOneTest)22 TEST_F(ProcessInfoSnapshotMacTest, FindPidOneTest) {
23 // Sample process with PID 1, which should exist and presumably belong to
24 // root.
25 std::vector<base::ProcessId> pid_list;
26 pid_list.push_back(1);
27 ProcessInfoSnapshot snapshot;
28 ASSERT_TRUE(snapshot.Sample(pid_list));
29
30 ProcessInfoSnapshot::ProcInfoEntry proc_info;
31 ASSERT_TRUE(snapshot.GetProcInfo(1, &proc_info));
32 EXPECT_EQ(1, static_cast<int64>(proc_info.pid));
33 EXPECT_EQ(0, static_cast<int64>(proc_info.ppid));
34 EXPECT_EQ(0, static_cast<int64>(proc_info.uid));
35 EXPECT_EQ(0, static_cast<int64>(proc_info.euid));
36 EXPECT_GE(proc_info.rss, 0u);
37 EXPECT_GT(proc_info.vsize, 0u);
38
39 // Try out the |Get...OfPID()|, but don't examine the results, since they
40 // depend on how we map |ProcInfoEntry| to |...KBytes|.
41 base::CommittedKBytes usage;
42 EXPECT_TRUE(snapshot.GetCommittedKBytesOfPID(1, &usage));
43 base::WorkingSetKBytes ws_usage;
44 EXPECT_TRUE(snapshot.GetWorkingSetKBytesOfPID(1, &ws_usage));
45
46 // Make sure it hasn't picked up some other PID (say, 2).
47 EXPECT_FALSE(snapshot.GetProcInfo(2, &proc_info));
48
49 // Make sure PID 2 still isn't there (in case I mess up my use of std::map).
50 EXPECT_FALSE(snapshot.GetProcInfo(2, &proc_info));
51
52 // Test |Reset()|.
53 snapshot.Reset();
54 EXPECT_FALSE(snapshot.GetProcInfo(1, &proc_info));
55 }
56
TEST_F(ProcessInfoSnapshotMacTest,FindPidSelfTest)57 TEST_F(ProcessInfoSnapshotMacTest, FindPidSelfTest) {
58 // Sample this process and its parent.
59 base::ProcessId pid = static_cast<base::ProcessId>(getpid());
60 base::ProcessId ppid = static_cast<base::ProcessId>(getppid());
61 uid_t uid = getuid();
62 uid_t euid = geteuid();
63 EXPECT_NE(static_cast<int64>(ppid), 0);
64
65 std::vector<base::ProcessId> pid_list;
66 pid_list.push_back(pid);
67 pid_list.push_back(ppid);
68 ProcessInfoSnapshot snapshot;
69 ASSERT_TRUE(snapshot.Sample(pid_list));
70
71 // Find our process.
72 ProcessInfoSnapshot::ProcInfoEntry proc_info;
73 ASSERT_TRUE(snapshot.GetProcInfo(pid, &proc_info));
74 EXPECT_EQ(pid, proc_info.pid);
75 EXPECT_EQ(ppid, proc_info.ppid);
76 EXPECT_EQ(uid, proc_info.uid);
77 EXPECT_EQ(euid, proc_info.euid);
78 EXPECT_GE(proc_info.rss, 100u); // Sanity check: we're running, so we
79 // should occupy at least 100 kilobytes.
80 EXPECT_GE(proc_info.vsize, 1024u); // Sanity check: our |vsize| is presumably
81 // at least a megabyte.
82 EXPECT_GE(proc_info.rshrd, 1024u); // Shared memory should also > 1 MB.
83 EXPECT_GE(proc_info.rprvt, 1024u); // Same with private memory.
84
85 // Find our parent.
86 ASSERT_TRUE(snapshot.GetProcInfo(ppid, &proc_info));
87 EXPECT_EQ(ppid, proc_info.pid);
88 EXPECT_NE(static_cast<int64>(proc_info.ppid), 0);
89 EXPECT_EQ(uid, proc_info.uid); // This (and the following) should be true
90 EXPECT_EQ(euid, proc_info.euid); // under reasonable circumstances.
91 // Can't say anything definite about its |rss|.
92 EXPECT_GT(proc_info.vsize, 0u); // Its |vsize| should be nonzero though.
93 }
94
95 // To verify that ProcessInfoSnapshot is getting the actual uid and effective
96 // uid, this test runs top. top should have a uid of the caller and effective
97 // uid of 0 (root).
TEST_F(ProcessInfoSnapshotMacTest,EffectiveVsRealUserIDTest)98 TEST_F(ProcessInfoSnapshotMacTest, EffectiveVsRealUserIDTest) {
99 // Create a pipe to be able to read top's output.
100 int fds[2];
101 PCHECK(pipe(fds) == 0);
102 base::file_handle_mapping_vector fds_to_remap;
103 fds_to_remap.push_back(std::make_pair(fds[1], 1));
104
105 // Hook up top's stderr to the test process' stderr.
106 fds_to_remap.push_back(std::make_pair(fileno(stderr), 2));
107
108 std::vector<std::string> argv;
109 argv.push_back("/usr/bin/top");
110 argv.push_back("-l");
111 argv.push_back("0");
112
113 base::ProcessHandle process_handle;
114 ASSERT_TRUE(base::LaunchApp(argv, fds_to_remap, false, &process_handle));
115 PCHECK(HANDLE_EINTR(close(fds[1])) == 0);
116
117 // Wait until there's some output form top. This is an easy way to tell that
118 // the exec() call is done and top is actually running.
119 char buf[1];
120 PCHECK(HANDLE_EINTR(read(fds[0], buf, 1)) == 1);
121
122 std::vector<base::ProcessId> pid_list;
123 pid_list.push_back(process_handle);
124 ProcessInfoSnapshot snapshot;
125 ASSERT_TRUE(snapshot.Sample(pid_list));
126
127 ProcessInfoSnapshot::ProcInfoEntry proc_info;
128 ASSERT_TRUE(snapshot.GetProcInfo(process_handle, &proc_info));
129 // Effective user ID should be 0 (root).
130 EXPECT_EQ(proc_info.euid, 0u);
131 // Real user ID should match the calling process's user id.
132 EXPECT_EQ(proc_info.uid, geteuid());
133
134 ASSERT_TRUE(base::KillProcess(process_handle, 0, true));
135 PCHECK(HANDLE_EINTR(close(fds[0])) == 0);
136 }
137