blob: e95cf0c91b28107f4f455861e59d33ef2cf44b79 [file] [log] [blame]
// 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/launch.h"
#include "base/process/process.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;
ProcessInfoSnapshot snapshot;
ProcessInfoSnapshot::ProcInfoEntry proc_info;
ASSERT_TRUE(snapshot.GetProcInfo(1, &proc_info));
EXPECT_EQ(1, static_cast<int64>(;
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()|.
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;
ProcessInfoSnapshot snapshot;
// Find our process.
ProcessInfoSnapshot::ProcInfoEntry proc_info;
ASSERT_TRUE(snapshot.GetProcInfo(pid, &proc_info));
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+.
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_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;
base::LaunchOptions options;
options.fds_to_remap = &fds_to_remap;
base::Process process = base::LaunchProcess(argv, options);
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;
ProcessInfoSnapshot snapshot;
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(process.Terminate(0, true));
PCHECK(IGNORE_EINTR(close(fds[0])) == 0);