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