1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be
2 // found in the LICENSE file.
4 #include "chrome/browser/ui/network_profile_bubble.h"
9 // Make sure we link the wtsapi lib file in.
10 #pragma comment(lib, "wtsapi32.lib")
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/file_util.h"
15 #include "base/files/file_path.h"
16 #include "base/logging.h"
17 #include "base/metrics/histogram.h"
18 #include "base/prefs/pref_service.h"
19 #include "base/time/time.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser_finder.h"
23 #include "chrome/browser/ui/browser_list.h"
24 #include "chrome/browser/ui/browser_list_observer.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/common/pref_names.h"
27 #include "components/user_prefs/pref_registry_syncable.h"
28 #include "content/public/browser/browser_thread.h"
32 // The duration of the silent period before we start nagging the user again.
33 const int kSilenceDurationDays
= 100;
35 // The number of warnings to be shown on consequtive starts of Chrome before the
36 // silent period starts.
37 const int kMaxWarnings
= 2;
39 // Implementation of chrome::BrowserListObserver used to wait for a browser
41 class BrowserListObserver
: public chrome::BrowserListObserver
{
43 virtual ~BrowserListObserver();
45 // Overridden from chrome::BrowserListObserver:
46 virtual void OnBrowserAdded(Browser
* browser
) OVERRIDE
;
47 virtual void OnBrowserRemoved(Browser
* browser
) OVERRIDE
;
48 virtual void OnBrowserSetLastActive(Browser
* browser
) OVERRIDE
;
51 BrowserListObserver::~BrowserListObserver() {
54 void BrowserListObserver::OnBrowserAdded(Browser
* browser
) {
57 void BrowserListObserver::OnBrowserRemoved(Browser
* browser
) {
60 void BrowserListObserver::OnBrowserSetLastActive(Browser
* browser
) {
61 NetworkProfileBubble::ShowNotification(browser
);
62 // No need to observe anymore.
63 BrowserList::RemoveObserver(this);
67 // The name of the UMA histogram collecting our stats.
68 const char kMetricNetworkedProfileCheck
[] = "NetworkedProfile.Check";
73 bool NetworkProfileBubble::notification_shown_
= false;
76 bool NetworkProfileBubble::ShouldCheckNetworkProfile(Profile
* profile
) {
77 PrefService
* prefs
= profile
->GetPrefs();
78 if (prefs
->GetInteger(prefs::kNetworkProfileWarningsLeft
))
79 return !notification_shown_
;
80 int64 last_check
= prefs
->GetInt64(prefs::kNetworkProfileLastWarningTime
);
81 base::TimeDelta time_since_last_check
=
82 base::Time::Now() - base::Time::FromTimeT(last_check
);
83 if (time_since_last_check
.InDays() > kSilenceDurationDays
) {
84 prefs
->SetInteger(prefs::kNetworkProfileWarningsLeft
, kMaxWarnings
);
85 return !notification_shown_
;
91 void NetworkProfileBubble::CheckNetworkProfile(
92 const base::FilePath
& profile_folder
) {
93 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
94 // On Windows notify the users if their profiles are located on a network
95 // share as we don't officially support this setup yet.
96 // However we don't want to bother users on Cytrix setups as those have no
97 // real choice and their admins must be well aware of the risks associated.
98 // Also the command line flag --no-network-profile-warning can stop this
99 // warning from popping up. In this case we can skip the check to make the
101 // Collect a lot of stats along the way to see which cases do occur in the
102 // wild often enough.
103 if (CommandLine::ForCurrentProcess()->HasSwitch(
104 switches::kNoNetworkProfileWarning
)) {
105 RecordUmaEvent(METRIC_CHECK_SUPPRESSED
);
109 LPWSTR buffer
= NULL
;
110 DWORD buffer_length
= 0;
111 // Checking for RDP is cheaper than checking for a network drive so do this
113 if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER
, WTS_CURRENT_SESSION
,
114 WTSClientProtocolType
,
115 &buffer
, &buffer_length
)) {
116 RecordUmaEvent(METRIC_CHECK_FAILED
);
120 unsigned short* type
= reinterpret_cast<unsigned short*>(buffer
);
121 // We should warn the users if they have their profile on a network share only
122 // if running on a local session.
123 if (*type
== WTS_PROTOCOL_TYPE_CONSOLE
) {
124 bool profile_on_network
= false;
125 if (!profile_folder
.empty()) {
126 base::FilePath temp_file
;
127 // Try to create some non-empty temp file in the profile dir and use
128 // it to check if there is a reparse-point free path to it.
129 if (base::CreateTemporaryFileInDir(profile_folder
, &temp_file
) &&
130 (file_util::WriteFile(temp_file
, ".", 1) == 1)) {
131 base::FilePath normalized_temp_file
;
132 if (!base::NormalizeFilePath(temp_file
, &normalized_temp_file
))
133 profile_on_network
= true;
135 RecordUmaEvent(METRIC_CHECK_IO_FAILED
);
137 base::DeleteFile(temp_file
, false);
139 if (profile_on_network
) {
140 RecordUmaEvent(METRIC_PROFILE_ON_NETWORK
);
141 content::BrowserThread::PostTask(content::BrowserThread::UI
, FROM_HERE
,
142 base::Bind(&NotifyNetworkProfileDetected
));
144 RecordUmaEvent(METRIC_PROFILE_NOT_ON_NETWORK
);
147 RecordUmaEvent(METRIC_REMOTE_SESSION
);
150 ::WTSFreeMemory(buffer
);
154 void NetworkProfileBubble::SetNotificationShown(bool shown
) {
155 notification_shown_
= shown
;
159 void NetworkProfileBubble::RegisterProfilePrefs(
160 user_prefs::PrefRegistrySyncable
* registry
) {
161 registry
->RegisterIntegerPref(
162 prefs::kNetworkProfileWarningsLeft
,
164 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
165 registry
->RegisterInt64Pref(
166 prefs::kNetworkProfileLastWarningTime
,
168 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF
);
172 void NetworkProfileBubble::RecordUmaEvent(MetricNetworkedProfileCheck event
) {
173 UMA_HISTOGRAM_ENUMERATION(kMetricNetworkedProfileCheck
,
175 METRIC_NETWORKED_PROFILE_CHECK_SIZE
);
179 void NetworkProfileBubble::NotifyNetworkProfileDetected() {
180 Browser
* browser
= chrome::FindLastActiveWithHostDesktopType(
181 chrome::GetActiveDesktop());
184 ShowNotification(browser
);
186 BrowserList::AddObserver(new BrowserListObserver());