1 // Copyright 2014 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/metrics/plugin_metrics_provider.h"
6
7 #include <stddef.h>
8
9 #include <string>
10 #include <utility>
11
12 #include "base/macros.h"
13 #include "base/run_loop.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/test/task_environment.h"
16 #include "chrome/common/pref_names.h"
17 #include "components/prefs/pref_service.h"
18 #include "components/prefs/scoped_user_pref_update.h"
19 #include "components/prefs/testing_pref_service.h"
20 #include "content/public/browser/child_process_data.h"
21 #include "content/public/browser/child_process_termination_info.h"
22 #include "content/public/common/process_type.h"
23 #include "content/public/common/webplugininfo.h"
24 #include "content/public/test/browser_task_environment.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "third_party/metrics_proto/system_profile.pb.h"
27
28 namespace {
29
CreateFakePluginInfo(const std::string & name,const base::FilePath::CharType * path,const std::string & version)30 content::WebPluginInfo CreateFakePluginInfo(
31 const std::string& name,
32 const base::FilePath::CharType* path,
33 const std::string& version) {
34 content::WebPluginInfo plugin(base::UTF8ToUTF16(name),
35 base::FilePath(path),
36 base::UTF8ToUTF16(version),
37 base::string16());
38 plugin.type = content::WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS;
39 return plugin;
40 }
41
42 class PluginMetricsProviderTest : public ::testing::Test {
43 protected:
PluginMetricsProviderTest()44 PluginMetricsProviderTest()
45 : prefs_(new TestingPrefServiceSimple) {
46 PluginMetricsProvider::RegisterPrefs(prefs()->registry());
47 }
48
prefs()49 TestingPrefServiceSimple* prefs() {
50 return prefs_.get();
51 }
52
53 private:
54 std::unique_ptr<TestingPrefServiceSimple> prefs_;
55
56 DISALLOW_COPY_AND_ASSIGN(PluginMetricsProviderTest);
57 };
58
59 } // namespace
60
TEST_F(PluginMetricsProviderTest,IsPluginProcess)61 TEST_F(PluginMetricsProviderTest, IsPluginProcess) {
62 EXPECT_TRUE(PluginMetricsProvider::IsPluginProcess(
63 content::PROCESS_TYPE_PPAPI_PLUGIN));
64 EXPECT_FALSE(PluginMetricsProvider::IsPluginProcess(
65 content::PROCESS_TYPE_GPU));
66 }
67
TEST_F(PluginMetricsProviderTest,Plugins)68 TEST_F(PluginMetricsProviderTest, Plugins) {
69 content::BrowserTaskEnvironment task_environment;
70
71 PluginMetricsProvider provider(prefs());
72
73 std::vector<content::WebPluginInfo> plugins;
74 plugins.push_back(CreateFakePluginInfo("p1", FILE_PATH_LITERAL("p1.plugin"),
75 "1.5"));
76 plugins.push_back(CreateFakePluginInfo("p2", FILE_PATH_LITERAL("p2.plugin"),
77 "2.0"));
78 provider.SetPluginsForTesting(plugins);
79
80 metrics::SystemProfileProto system_profile;
81 provider.ProvideSystemProfileMetrics(&system_profile);
82
83 ASSERT_EQ(2, system_profile.plugin_size());
84 EXPECT_EQ("p1", system_profile.plugin(0).name());
85 EXPECT_EQ("p1.plugin", system_profile.plugin(0).filename());
86 EXPECT_EQ("1.5", system_profile.plugin(0).version());
87 EXPECT_TRUE(system_profile.plugin(0).is_pepper());
88 EXPECT_EQ("p2", system_profile.plugin(1).name());
89 EXPECT_EQ("p2.plugin", system_profile.plugin(1).filename());
90 EXPECT_EQ("2.0", system_profile.plugin(1).version());
91 EXPECT_TRUE(system_profile.plugin(1).is_pepper());
92
93 // Now set some plugin stability stats for p2 and verify they're recorded.
94 std::unique_ptr<base::DictionaryValue> plugin_dict(new base::DictionaryValue);
95 plugin_dict->SetString(prefs::kStabilityPluginName, "p2");
96 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, 1);
97 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, 2);
98 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, 3);
99 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors, 4);
100 {
101 ListPrefUpdate update(prefs(), prefs::kStabilityPluginStats);
102 update.Get()->Append(std::move(plugin_dict));
103 }
104
105 provider.ProvideStabilityMetrics(&system_profile);
106
107 const metrics::SystemProfileProto_Stability& stability =
108 system_profile.stability();
109 ASSERT_EQ(1, stability.plugin_stability_size());
110 EXPECT_EQ("p2", stability.plugin_stability(0).plugin().name());
111 EXPECT_EQ("p2.plugin", stability.plugin_stability(0).plugin().filename());
112 EXPECT_EQ("2.0", stability.plugin_stability(0).plugin().version());
113 EXPECT_TRUE(stability.plugin_stability(0).plugin().is_pepper());
114 EXPECT_EQ(1, stability.plugin_stability(0).launch_count());
115 EXPECT_EQ(2, stability.plugin_stability(0).crash_count());
116 EXPECT_EQ(3, stability.plugin_stability(0).instance_count());
117 EXPECT_EQ(4, stability.plugin_stability(0).loading_error_count());
118 }
119
TEST_F(PluginMetricsProviderTest,RecordCurrentStateWithDelay)120 TEST_F(PluginMetricsProviderTest, RecordCurrentStateWithDelay) {
121 content::BrowserTaskEnvironment task_environment(
122 base::test::TaskEnvironment::TimeSource::MOCK_TIME);
123
124 PluginMetricsProvider provider(prefs());
125
126 EXPECT_TRUE(provider.RecordCurrentStateWithDelay());
127 EXPECT_FALSE(provider.RecordCurrentStateWithDelay());
128
129 task_environment.FastForwardBy(PluginMetricsProvider::GetRecordStateDelay());
130 base::RunLoop().RunUntilIdle();
131
132 EXPECT_TRUE(provider.RecordCurrentStateWithDelay());
133 }
134
TEST_F(PluginMetricsProviderTest,RecordCurrentStateIfPending)135 TEST_F(PluginMetricsProviderTest, RecordCurrentStateIfPending) {
136 content::BrowserTaskEnvironment task_environment(
137 base::test::TaskEnvironment::TimeSource::MOCK_TIME);
138
139 PluginMetricsProvider provider(prefs());
140
141 // First there should be no need to force RecordCurrentState.
142 EXPECT_FALSE(provider.RecordCurrentStateIfPending());
143
144 // After delayed task is posted RecordCurrentStateIfPending should return
145 // true.
146 EXPECT_TRUE(provider.RecordCurrentStateWithDelay());
147 EXPECT_TRUE(provider.RecordCurrentStateIfPending());
148
149 // If RecordCurrentStateIfPending was successful then we should be able to
150 // post a new delayed task.
151 EXPECT_TRUE(provider.RecordCurrentStateWithDelay());
152 }
153
TEST_F(PluginMetricsProviderTest,ProvideStabilityMetricsWhenPendingTask)154 TEST_F(PluginMetricsProviderTest, ProvideStabilityMetricsWhenPendingTask) {
155 content::BrowserTaskEnvironment task_environment;
156
157 PluginMetricsProvider provider(prefs());
158
159 // Create plugin information for testing.
160 std::vector<content::WebPluginInfo> plugins;
161 plugins.push_back(
162 CreateFakePluginInfo("p1", FILE_PATH_LITERAL("p1.plugin"), "1.5"));
163 plugins.push_back(
164 CreateFakePluginInfo("p2", FILE_PATH_LITERAL("p2.plugin"), "1.5"));
165 provider.SetPluginsForTesting(plugins);
166 metrics::SystemProfileProto system_profile;
167 provider.ProvideSystemProfileMetrics(&system_profile);
168
169 // Increase number of process launches which should also start a delayed
170 // task.
171 content::ChildProcessTerminationInfo abnormal_termination_info;
172 abnormal_termination_info.status =
173 base::TERMINATION_STATUS_ABNORMAL_TERMINATION;
174 abnormal_termination_info.exit_code = 1;
175 content::ChildProcessData child_process_data1(
176 content::PROCESS_TYPE_PPAPI_PLUGIN);
177 child_process_data1.name = base::UTF8ToUTF16("p1");
178 provider.BrowserChildProcessHostConnected(child_process_data1);
179 provider.BrowserChildProcessCrashed(child_process_data1,
180 abnormal_termination_info);
181
182 // A disconnect should not generate a crash event.
183 provider.BrowserChildProcessHostConnected(child_process_data1);
184 provider.BrowserChildProcessHostDisconnected(child_process_data1);
185
186 content::ChildProcessData child_process_data2(
187 content::PROCESS_TYPE_PPAPI_PLUGIN);
188 child_process_data2.name = base::UTF8ToUTF16("p2");
189 provider.BrowserChildProcessHostConnected(child_process_data2);
190 provider.BrowserChildProcessCrashed(child_process_data2,
191 abnormal_termination_info);
192
193 // A kill should generate a crash event
194 provider.BrowserChildProcessHostConnected(child_process_data2);
195 provider.BrowserChildProcessKilled(child_process_data2,
196 abnormal_termination_info);
197
198 // Call ProvideStabilityMetrics to check that it will force pending tasks to
199 // be executed immediately.
200 provider.ProvideStabilityMetrics(&system_profile);
201
202 // Check current number of instances created.
203 const metrics::SystemProfileProto_Stability& stability =
204 system_profile.stability();
205 size_t found = 0;
206 EXPECT_EQ(stability.plugin_stability_size(), 2);
207 for (int i = 0; i < 2; i++) {
208 std::string name = stability.plugin_stability(i).plugin().name();
209 if (name == "p1") {
210 EXPECT_EQ(2, stability.plugin_stability(i).launch_count());
211 EXPECT_EQ(1, stability.plugin_stability(i).crash_count());
212 found++;
213 } else if (name == "p2") {
214 EXPECT_EQ(2, stability.plugin_stability(i).launch_count());
215 EXPECT_EQ(2, stability.plugin_stability(i).crash_count());
216 found++;
217 } else {
218 GTEST_FAIL() << "Unexpected plugin name : " << name;
219 }
220 }
221 EXPECT_EQ(found, 2U);
222 }
223