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