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