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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/task_manager/providers/child_process_task.h"
#include <stdint.h>
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/task_manager/providers/child_process_task_provider.h"
#include "chrome/browser/task_manager/task_manager_observer.h"
#include "chrome/grit/generated_resources.h"
#include "components/nacl/common/nacl_process_type.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/common/process_type.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
using content::ChildProcessData;
namespace task_manager {
namespace {
// Will be used to test the translation from |content::ProcessType| to
// |task_manager::Task::Type|.
struct ProcessTypeTaskTypePair {
int process_type_;
Task::Type expected_task_type_;
} process_task_types_pairs[] = {
{ content::PROCESS_TYPE_PPAPI_PLUGIN, Task::PLUGIN },
{ content::PROCESS_TYPE_PPAPI_BROKER, Task::PLUGIN },
{ content::PROCESS_TYPE_UTILITY, Task::UTILITY },
{ content::PROCESS_TYPE_ZYGOTE, Task::ZYGOTE },
{ content::PROCESS_TYPE_SANDBOX_HELPER, Task::SANDBOX_HELPER },
{ content::PROCESS_TYPE_GPU, Task::GPU },
{ PROCESS_TYPE_NACL_LOADER, Task::NACL },
{ PROCESS_TYPE_NACL_BROKER, Task::NACL },
};
} // namespace
// Defines a test for the child process task provider and the child process
// tasks themselves.
class ChildProcessTaskTest
: public testing::Test,
public TaskProviderObserver {
public:
ChildProcessTaskTest() = default;
ChildProcessTaskTest(const ChildProcessTaskTest&) = delete;
ChildProcessTaskTest& operator=(const ChildProcessTaskTest&) = delete;
~ChildProcessTaskTest() override = default;
// task_manager::TaskProviderObserver:
void TaskAdded(Task* task) override {
DCHECK(task);
if (provided_tasks_.find(task->process_handle()) != provided_tasks_.end())
FAIL() << "ChildProcessTaskProvider must never provide duplicate tasks";
provided_tasks_[task->process_handle()] = task;
}
void TaskRemoved(Task* task) override {
DCHECK(task);
provided_tasks_.erase(task->process_handle());
}
bool AreProviderContainersEmpty(
const ChildProcessTaskProvider& provider) const {
return provider.tasks_by_processid_.empty() &&
provider.tasks_by_child_id_.empty();
}
protected:
std::map<base::ProcessHandle, raw_ptr<Task, CtnExperimental>> provided_tasks_;
private:
content::BrowserTaskEnvironment task_environment_;
};
// Performs a basic test.
TEST_F(ChildProcessTaskTest, BasicTest) {
ChildProcessTaskProvider provider;
EXPECT_TRUE(provided_tasks_.empty());
provider.SetObserver(this);
content::RunAllPendingInMessageLoop();
ASSERT_TRUE(provided_tasks_.empty()) <<
"unit tests don't have any browser child processes";
provider.ClearObserver();
EXPECT_TRUE(provided_tasks_.empty());
EXPECT_TRUE(AreProviderContainersEmpty(provider));
}
// Tests everything related to child process task providing.
TEST_F(ChildProcessTaskTest, TestAll) {
ChildProcessTaskProvider provider;
EXPECT_TRUE(provided_tasks_.empty());
provider.SetObserver(this);
content::RunAllPendingInMessageLoop();
ASSERT_TRUE(provided_tasks_.empty());
// The following process which has handle = base::kNullProcessHandle, won't be
// added.
ChildProcessData data1(0, content::ChildProcessId());
ASSERT_FALSE(data1.GetProcess().IsValid());
provider.BrowserChildProcessLaunchedAndConnected(data1);
EXPECT_TRUE(provided_tasks_.empty());
const content::ChildProcessId unique_id(245);
const std::u16string name(u"Test Task");
const std::u16string expected_name(
l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_PLUGIN_PREFIX, name));
ChildProcessData data2(content::PROCESS_TYPE_PPAPI_PLUGIN, unique_id);
data2.SetProcess(base::Process::Current());
data2.name = name;
provider.BrowserChildProcessLaunchedAndConnected(data2);
ASSERT_EQ(1U, provided_tasks_.size());
Task* task = provided_tasks_.begin()->second;
// Process handles may not match, but process IDs must:
EXPECT_EQ(base::GetCurrentProcId(), base::GetProcId(task->process_handle()));
EXPECT_EQ(base::GetCurrentProcId(), task->process_id());
EXPECT_EQ(expected_name, task->title());
EXPECT_EQ(Task::PLUGIN, task->GetType());
// TODO(crbug.com/379869738): Remove GetUnsafeValue() usage.
EXPECT_EQ(unique_id.GetUnsafeValue(), task->GetChildProcessUniqueID());
EXPECT_EQ(std::u16string(), task->GetProfileName());
EXPECT_FALSE(task->ReportsSqliteMemory());
EXPECT_FALSE(task->ReportsWebCacheStats());
// Make sure that indexing by child_id works properly.
// TODO(crbug.com/379869738): Remove GetUnsafeValue() usage.
ASSERT_EQ(task, provider.GetTaskOfUrlRequest(unique_id.GetUnsafeValue(), 0));
ASSERT_EQ(task, provider.GetTaskOfUrlRequest(unique_id.GetUnsafeValue(), 1));
const int64_t bytes_read = 1024;
task->OnNetworkBytesRead(bytes_read);
task->Refresh(base::Seconds(1), REFRESH_TYPE_NETWORK_USAGE);
EXPECT_EQ(bytes_read, task->GetNetworkUsageRate());
// Clearing the observer won't notify us of any tasks removals even though
// tasks will be actually deleted.
provider.ClearObserver();
EXPECT_FALSE(provided_tasks_.empty());
EXPECT_TRUE(AreProviderContainersEmpty(provider));
}
// Tests the translation of |content::ProcessType| to
// |task_manager::Task::Type|.
TEST_F(ChildProcessTaskTest, ProcessTypeToTaskType) {
ChildProcessTaskProvider provider;
EXPECT_TRUE(provided_tasks_.empty());
provider.SetObserver(this);
content::RunAllPendingInMessageLoop();
ASSERT_TRUE(provided_tasks_.empty());
for (const auto& types_pair : process_task_types_pairs) {
// Add the task.
ChildProcessData data(types_pair.process_type_, content::ChildProcessId());
data.SetProcess(base::Process::Current());
provider.BrowserChildProcessLaunchedAndConnected(data);
ASSERT_EQ(1U, provided_tasks_.size());
Task* task = provided_tasks_.begin()->second;
EXPECT_EQ(base::GetCurrentProcId(),
base::GetProcId(task->process_handle()));
EXPECT_EQ(types_pair.expected_task_type_, task->GetType());
// Remove the task.
provider.BrowserChildProcessHostDisconnected(data);
EXPECT_TRUE(provided_tasks_.empty());
}
provider.ClearObserver();
EXPECT_TRUE(AreProviderContainersEmpty(provider));
}
} // namespace task_manager
|