1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/process_info_snapshot.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <sys/types.h>  // For |uid_t| (and |pid_t|).
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <unistd.h>  // For |getpid()|, |getuid()|, etc.
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/command_line.h"
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/eintr_wrapper.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/file_path.h"
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/logging.h"
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/process_util.h"
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/gtest/include/gtest/gtest.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef testing::Test ProcessInfoSnapshotMacTest;
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ProcessInfoSnapshotMacTest, FindPidOneTest) {
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Sample process with PID 1, which should exist and presumably belong to
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // root.
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<base::ProcessId> pid_list;
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pid_list.push_back(1);
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProcessInfoSnapshot snapshot;
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(snapshot.Sample(pid_list));
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProcessInfoSnapshot::ProcInfoEntry proc_info;
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(snapshot.GetProcInfo(1, &proc_info));
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, static_cast<int64>(proc_info.pid));
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, static_cast<int64>(proc_info.ppid));
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, static_cast<int64>(proc_info.uid));
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, static_cast<int64>(proc_info.euid));
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_GE(proc_info.rss, 0u);
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_GT(proc_info.vsize, 0u);
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Try out the |Get...OfPID()|, but don't examine the results, since they
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // depend on how we map |ProcInfoEntry| to |...KBytes|.
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::CommittedKBytes usage;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(snapshot.GetCommittedKBytesOfPID(1, &usage));
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::WorkingSetKBytes ws_usage;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(snapshot.GetWorkingSetKBytesOfPID(1, &ws_usage));
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure it hasn't picked up some other PID (say, 2).
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(snapshot.GetProcInfo(2, &proc_info));
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure PID 2 still isn't there (in case I mess up my use of std::map).
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(snapshot.GetProcInfo(2, &proc_info));
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Test |Reset()|.
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  snapshot.Reset();
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(snapshot.GetProcInfo(1, &proc_info));
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(ProcessInfoSnapshotMacTest, FindPidSelfTest) {
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Sample this process and its parent.
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::ProcessId pid = static_cast<base::ProcessId>(getpid());
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::ProcessId ppid = static_cast<base::ProcessId>(getppid());
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  uid_t uid = getuid();
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  uid_t euid = geteuid();
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_NE(static_cast<int64>(ppid), 0);
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<base::ProcessId> pid_list;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pid_list.push_back(pid);
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pid_list.push_back(ppid);
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProcessInfoSnapshot snapshot;
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(snapshot.Sample(pid_list));
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Find our process.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProcessInfoSnapshot::ProcInfoEntry proc_info;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(snapshot.GetProcInfo(pid, &proc_info));
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(pid, proc_info.pid);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(ppid, proc_info.ppid);
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(uid, proc_info.uid);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(euid, proc_info.euid);
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_GE(proc_info.rss, 100u);     // Sanity check: we're running, so we
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      // should occupy at least 100 kilobytes.
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_GE(proc_info.vsize, 1024u);  // Sanity check: our |vsize| is presumably
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      // at least a megabyte.
8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  EXPECT_GE(proc_info.rshrd, 1024u);  // Shared memory should also > 1 MB.
8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  EXPECT_GE(proc_info.rprvt, 1024u);  // Same with private memory.
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Find our parent.
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ASSERT_TRUE(snapshot.GetProcInfo(ppid, &proc_info));
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(ppid, proc_info.pid);
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_NE(static_cast<int64>(proc_info.ppid), 0);
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(uid, proc_info.uid);    // This (and the following) should be true
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(euid, proc_info.euid);  // under reasonable circumstances.
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Can't say anything definite about its |rss|.
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_GT(proc_info.vsize, 0u);   // Its |vsize| should be nonzero though.
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// To verify that ProcessInfoSnapshot is getting the actual uid and effective
9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// uid, this test runs top. top should have a uid of the caller and effective
9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// uid of 0 (root).
9821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenTEST_F(ProcessInfoSnapshotMacTest, EffectiveVsRealUserIDTest) {
9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Create a pipe to be able to read top's output.
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int fds[2];
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  PCHECK(pipe(fds) == 0);
10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::file_handle_mapping_vector fds_to_remap;
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  fds_to_remap.push_back(std::make_pair(fds[1], 1));
10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Hook up top's stderr to the test process' stderr.
10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  fds_to_remap.push_back(std::make_pair(fileno(stderr), 2));
10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::vector<std::string> argv;
10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  argv.push_back("/usr/bin/top");
11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  argv.push_back("-l");
11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  argv.push_back("0");
11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::ProcessHandle process_handle;
11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ASSERT_TRUE(base::LaunchApp(argv, fds_to_remap, false, &process_handle));
11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  PCHECK(HANDLE_EINTR(close(fds[1])) == 0);
11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Wait until there's some output form top. This is an easy way to tell that
11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // the exec() call is done and top is actually running.
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  char buf[1];
12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  PCHECK(HANDLE_EINTR(read(fds[0], buf, 1)) == 1);
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
12221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  std::vector<base::ProcessId> pid_list;
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  pid_list.push_back(process_handle);
12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ProcessInfoSnapshot snapshot;
12521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ASSERT_TRUE(snapshot.Sample(pid_list));
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
12721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ProcessInfoSnapshot::ProcInfoEntry proc_info;
12821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ASSERT_TRUE(snapshot.GetProcInfo(process_handle, &proc_info));
12921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Effective user ID should be 0 (root).
13021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  EXPECT_EQ(proc_info.euid, 0u);
13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Real user ID should match the calling process's user id.
13221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  EXPECT_EQ(proc_info.uid, geteuid());
13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
13421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ASSERT_TRUE(base::KillProcess(process_handle, 0, true));
13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  PCHECK(HANDLE_EINTR(close(fds[0])) == 0);
13621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
137