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.
5 #include "chrome/browser/metrics/plugin_metrics_provider.h"
9 #include "base/basictypes.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "base/prefs/testing_pref_service.h"
13 #include "base/run_loop.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/common/pref_names.h"
16 #include "components/metrics/proto/system_profile.pb.h"
17 #include "content/public/browser/child_process_data.h"
18 #include "content/public/common/process_type.h"
19 #include "content/public/common/webplugininfo.h"
20 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "testing/gtest/include/gtest/gtest.h"
25 content::WebPluginInfo
CreateFakePluginInfo(
26 const std::string
& name
,
27 const base::FilePath::CharType
* path
,
28 const std::string
& version
,
30 content::WebPluginInfo
plugin(base::UTF8ToUTF16(name
),
32 base::UTF8ToUTF16(version
),
35 plugin
.type
= content::WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS
;
37 plugin
.type
= content::WebPluginInfo::PLUGIN_TYPE_NPAPI
;
41 class PluginMetricsProviderTest
: public ::testing::Test
{
43 PluginMetricsProviderTest()
44 : prefs_(new TestingPrefServiceSimple
) {
45 PluginMetricsProvider::RegisterPrefs(prefs()->registry());
48 TestingPrefServiceSimple
* prefs() {
53 scoped_ptr
<TestingPrefServiceSimple
> prefs_
;
55 DISALLOW_COPY_AND_ASSIGN(PluginMetricsProviderTest
);
60 TEST_F(PluginMetricsProviderTest
, IsPluginProcess
) {
61 EXPECT_TRUE(PluginMetricsProvider::IsPluginProcess(
62 content::PROCESS_TYPE_PLUGIN
));
63 EXPECT_TRUE(PluginMetricsProvider::IsPluginProcess(
64 content::PROCESS_TYPE_PPAPI_PLUGIN
));
65 EXPECT_FALSE(PluginMetricsProvider::IsPluginProcess(
66 content::PROCESS_TYPE_GPU
));
69 TEST_F(PluginMetricsProviderTest
, Plugins
) {
70 content::TestBrowserThreadBundle thread_bundle
;
72 PluginMetricsProvider
provider(prefs());
74 std::vector
<content::WebPluginInfo
> plugins
;
75 plugins
.push_back(CreateFakePluginInfo("p1", FILE_PATH_LITERAL("p1.plugin"),
77 plugins
.push_back(CreateFakePluginInfo("p2", FILE_PATH_LITERAL("p2.plugin"),
79 provider
.SetPluginsForTesting(plugins
);
81 metrics::SystemProfileProto system_profile
;
82 provider
.ProvideSystemProfileMetrics(&system_profile
);
84 ASSERT_EQ(2, system_profile
.plugin_size());
85 EXPECT_EQ("p1", system_profile
.plugin(0).name());
86 EXPECT_EQ("p1.plugin", system_profile
.plugin(0).filename());
87 EXPECT_EQ("1.5", system_profile
.plugin(0).version());
88 EXPECT_TRUE(system_profile
.plugin(0).is_pepper());
89 EXPECT_EQ("p2", system_profile
.plugin(1).name());
90 EXPECT_EQ("p2.plugin", system_profile
.plugin(1).filename());
91 EXPECT_EQ("2.0", system_profile
.plugin(1).version());
92 EXPECT_FALSE(system_profile
.plugin(1).is_pepper());
94 // Now set some plugin stability stats for p2 and verify they're recorded.
95 scoped_ptr
<base::DictionaryValue
> plugin_dict(new base::DictionaryValue
);
96 plugin_dict
->SetString(prefs::kStabilityPluginName
, "p2");
97 plugin_dict
->SetInteger(prefs::kStabilityPluginLaunches
, 1);
98 plugin_dict
->SetInteger(prefs::kStabilityPluginCrashes
, 2);
99 plugin_dict
->SetInteger(prefs::kStabilityPluginInstances
, 3);
100 plugin_dict
->SetInteger(prefs::kStabilityPluginLoadingErrors
, 4);
102 ListPrefUpdate
update(prefs(), prefs::kStabilityPluginStats
);
103 update
.Get()->Append(plugin_dict
.release());
106 provider
.ProvideStabilityMetrics(&system_profile
);
108 const metrics::SystemProfileProto_Stability
& stability
=
109 system_profile
.stability();
110 ASSERT_EQ(1, stability
.plugin_stability_size());
111 EXPECT_EQ("p2", stability
.plugin_stability(0).plugin().name());
112 EXPECT_EQ("p2.plugin", stability
.plugin_stability(0).plugin().filename());
113 EXPECT_EQ("2.0", stability
.plugin_stability(0).plugin().version());
114 EXPECT_FALSE(stability
.plugin_stability(0).plugin().is_pepper());
115 EXPECT_EQ(1, stability
.plugin_stability(0).launch_count());
116 EXPECT_EQ(2, stability
.plugin_stability(0).crash_count());
117 EXPECT_EQ(3, stability
.plugin_stability(0).instance_count());
118 EXPECT_EQ(4, stability
.plugin_stability(0).loading_error_count());
121 TEST_F(PluginMetricsProviderTest
, RecordCurrentStateWithDelay
) {
122 content::TestBrowserThreadBundle thread_bundle
;
124 PluginMetricsProvider
provider(prefs());
127 EXPECT_TRUE(provider
.RecordCurrentStateWithDelay(delay_ms
));
128 EXPECT_FALSE(provider
.RecordCurrentStateWithDelay(delay_ms
));
130 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(delay_ms
));
131 base::RunLoop().RunUntilIdle();
133 EXPECT_TRUE(provider
.RecordCurrentStateWithDelay(delay_ms
));
136 TEST_F(PluginMetricsProviderTest
, RecordCurrentStateIfPending
) {
137 content::TestBrowserThreadBundle thread_bundle
;
139 PluginMetricsProvider
provider(prefs());
141 // First there should be no need to force RecordCurrentState.
142 EXPECT_FALSE(provider
.RecordCurrentStateIfPending());
144 // After delayed task is posted RecordCurrentStateIfPending should return
146 int delay_ms
= 100000;
147 EXPECT_TRUE(provider
.RecordCurrentStateWithDelay(delay_ms
));
148 EXPECT_TRUE(provider
.RecordCurrentStateIfPending());
150 // If RecordCurrentStateIfPending was successful then we should be able to
151 // post a new delayed task.
152 EXPECT_TRUE(provider
.RecordCurrentStateWithDelay(delay_ms
));
155 TEST_F(PluginMetricsProviderTest
, ProvideStabilityMetricsWhenPendingTask
) {
156 content::TestBrowserThreadBundle thread_bundle
;
158 PluginMetricsProvider
provider(prefs());
160 // Create plugin information for testing.
161 std::vector
<content::WebPluginInfo
> plugins
;
162 plugins
.push_back(CreateFakePluginInfo("p1", FILE_PATH_LITERAL("p1.plugin"),
164 plugins
.push_back(CreateFakePluginInfo("p2", FILE_PATH_LITERAL("p2.plugin"),
166 provider
.SetPluginsForTesting(plugins
);
167 metrics::SystemProfileProto system_profile
;
168 provider
.ProvideSystemProfileMetrics(&system_profile
);
170 // Increase number of created instances which should also start a delayed
172 content::ChildProcessData
child_process_data1(content::PROCESS_TYPE_PLUGIN
);
173 child_process_data1
.name
= base::UTF8ToUTF16("p1");
174 provider
.BrowserChildProcessInstanceCreated(child_process_data1
);
175 provider
.BrowserChildProcessCrashed(child_process_data1
, 1);
177 // A disconnect should not generate a crash event.
178 provider
.BrowserChildProcessInstanceCreated(child_process_data1
);
179 provider
.BrowserChildProcessHostDisconnected(child_process_data1
);
181 content::ChildProcessData
child_process_data2(
182 content::PROCESS_TYPE_PPAPI_PLUGIN
);
183 child_process_data2
.name
= base::UTF8ToUTF16("p2");
184 provider
.BrowserChildProcessInstanceCreated(child_process_data2
);
185 provider
.BrowserChildProcessCrashed(child_process_data2
, 1);
187 // A kill should generate a crash event
188 provider
.BrowserChildProcessInstanceCreated(child_process_data2
);
189 provider
.BrowserChildProcessKilled(child_process_data2
, 1);
191 // Call ProvideStabilityMetrics to check that it will force pending tasks to
192 // be executed immediately.
193 provider
.ProvideStabilityMetrics(&system_profile
);
195 // Check current number of instances created.
196 const metrics::SystemProfileProto_Stability
& stability
=
197 system_profile
.stability();
199 EXPECT_EQ(stability
.plugin_stability_size(), 2);
200 for (int i
= 0; i
< 2; i
++) {
201 std::string name
= stability
.plugin_stability(i
).plugin().name();
203 EXPECT_EQ(2, stability
.plugin_stability(i
).instance_count());
204 EXPECT_EQ(1, stability
.plugin_stability(i
).crash_count());
206 } else if (name
== "p2") {
207 EXPECT_EQ(2, stability
.plugin_stability(i
).instance_count());
208 EXPECT_EQ(2, stability
.plugin_stability(i
).crash_count());
211 GTEST_FAIL() << "Unexpected plugin name : " << name
;
214 EXPECT_EQ(found
, 2U);