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 184
|
// Copyright 2012 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/ui/network_profile_bubble.h"
#include <windows.h>
#include <stdint.h>
#include <wtsapi32.h>
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_macros.h"
#include "base/time/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
namespace {
// The duration of the silent period before we start nagging the user again.
const int kSilenceDurationDays = 100;
// The number of warnings to be shown on consequtive starts of Chrome before the
// silent period starts.
const int kMaxWarnings = 2;
// Implementation of BrowserListObserver used to wait for a browser
// window.
class NetworkProfileBubbleBrowserListObserver : public BrowserListObserver {
private:
~NetworkProfileBubbleBrowserListObserver() override;
// Overridden from ::BrowserListObserver:
void OnBrowserAdded(Browser* browser) override;
void OnBrowserRemoved(Browser* browser) override;
void OnBrowserSetLastActive(Browser* browser) override;
};
NetworkProfileBubbleBrowserListObserver::
~NetworkProfileBubbleBrowserListObserver() = default;
void NetworkProfileBubbleBrowserListObserver::OnBrowserAdded(Browser* browser) {
}
void NetworkProfileBubbleBrowserListObserver::OnBrowserRemoved(
Browser* browser) {}
void NetworkProfileBubbleBrowserListObserver::OnBrowserSetLastActive(
Browser* browser) {
NetworkProfileBubble::ShowNotification(browser);
// No need to observe anymore.
BrowserList::RemoveObserver(this);
delete this;
}
// The name of the UMA histogram collecting our stats.
const char kMetricNetworkedProfileCheck[] = "NetworkedProfile.Check";
} // namespace
// static
bool NetworkProfileBubble::notification_shown_ = false;
// static
bool NetworkProfileBubble::ShouldCheckNetworkProfile(Profile* profile) {
PrefService* prefs = profile->GetPrefs();
if (prefs->GetInteger(prefs::kNetworkProfileWarningsLeft)) {
return !notification_shown_;
}
int64_t last_check = prefs->GetInt64(prefs::kNetworkProfileLastWarningTime);
base::TimeDelta time_since_last_check =
base::Time::Now() - base::Time::FromTimeT(last_check);
if (time_since_last_check.InDays() > kSilenceDurationDays) {
prefs->SetInteger(prefs::kNetworkProfileWarningsLeft, kMaxWarnings);
return !notification_shown_;
}
return false;
}
// static
void NetworkProfileBubble::CheckNetworkProfile(
const base::FilePath& profile_folder) {
// On Windows notify the users if their profiles are located on a network
// share as we don't officially support this setup yet.
// However we don't want to bother users on Cytrix setups as those have no
// real choice and their admins must be well aware of the risks associated.
// Also the command line flag --no-network-profile-warning can stop this
// warning from popping up. In this case we can skip the check to make the
// start faster.
// Collect a lot of stats along the way to see which cases do occur in the
// wild often enough.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kNoNetworkProfileWarning)) {
RecordUmaEvent(METRIC_CHECK_SUPPRESSED);
return;
}
LPWSTR buffer = NULL;
DWORD buffer_length = 0;
// Checking for RDP is cheaper than checking for a network drive so do this
// one first.
if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION,
WTSClientProtocolType, &buffer,
&buffer_length)) {
RecordUmaEvent(METRIC_CHECK_FAILED);
return;
}
unsigned short* type = reinterpret_cast<unsigned short*>(buffer);
// We should warn the users if they have their profile on a network share only
// if running on a local session.
if (*type == WTS_PROTOCOL_TYPE_CONSOLE) {
bool profile_on_network = false;
if (!profile_folder.empty()) {
base::FilePath temp_file;
// Try to create some non-empty temp file in the profile dir and use
// it to check if there is a reparse-point free path to it.
if (base::CreateTemporaryFileInDir(profile_folder, &temp_file) &&
base::WriteFile(temp_file, ".")) {
base::FilePath normalized_temp_file;
if (!base::NormalizeFilePath(temp_file, &normalized_temp_file)) {
profile_on_network = true;
}
} else {
RecordUmaEvent(METRIC_CHECK_IO_FAILED);
}
base::DeleteFile(temp_file);
}
if (profile_on_network) {
RecordUmaEvent(METRIC_PROFILE_ON_NETWORK);
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&NotifyNetworkProfileDetected));
} else {
RecordUmaEvent(METRIC_PROFILE_NOT_ON_NETWORK);
}
} else {
RecordUmaEvent(METRIC_REMOTE_SESSION);
}
::WTSFreeMemory(buffer);
}
// static
void NetworkProfileBubble::SetNotificationShown(bool shown) {
notification_shown_ = shown;
}
// static
void NetworkProfileBubble::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterIntegerPref(prefs::kNetworkProfileWarningsLeft,
kMaxWarnings);
registry->RegisterInt64Pref(prefs::kNetworkProfileLastWarningTime, 0);
}
// static
void NetworkProfileBubble::RecordUmaEvent(MetricNetworkedProfileCheck event) {
UMA_HISTOGRAM_ENUMERATION(kMetricNetworkedProfileCheck, event,
METRIC_NETWORKED_PROFILE_CHECK_SIZE);
}
// static
void NetworkProfileBubble::NotifyNetworkProfileDetected() {
Browser* browser = chrome::FindLastActive();
if (browser) {
ShowNotification(browser);
} else {
BrowserList::AddObserver(new NetworkProfileBubbleBrowserListObserver());
}
}
|