Commit 391e9004 authored by Patrick Monette's avatar Patrick Monette Committed by Commit Bot

[3p-Conflicts] Make ModuleListFilter initialize on a background sequence

This is to avoid doing IO access on the UI thread.

Bug: 819791
Change-Id: I0f92f316ebc29d0c4270af46b3a6ccc854adfded
Reviewed-on: https://chromium-review.googlesource.com/955670
Commit-Queue: Patrick Monette <pmonette@chromium.org>
Reviewed-by: default avatarGreg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543085}
parent a42f0327
...@@ -6,13 +6,10 @@ ...@@ -6,13 +6,10 @@
#include <algorithm> #include <algorithm>
#include "base/callback.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/task_scheduler/post_task.h" #include "base/threading/thread_restrictions.h"
#include "base/win/registry.h" #include "base/win/registry.h"
#include "chrome/browser/conflicts/msi_util_win.h" #include "chrome/browser/conflicts/msi_util_win.h"
...@@ -87,15 +84,73 @@ bool GetInstalledFilesUsingMsiGuid( ...@@ -87,15 +84,73 @@ bool GetInstalledFilesUsingMsiGuid(
return true; return true;
} }
// Checks if the registry key references an installed program in the Apps & // Helper function to sort |container| using CompareLessIgnoreCase.
// Features settings page. void SortByFilePaths(
void CheckRegistryKeyForInstalledProgram( std::vector<std::pair<base::FilePath, size_t>>* container) {
std::sort(container->begin(), container->end(),
[](const auto& lhs, const auto& rhs) {
return base::FilePath::CompareLessIgnoreCase(lhs.first.value(),
rhs.first.value());
});
}
} // namespace
InstalledPrograms::InstalledPrograms()
: InstalledPrograms(std::make_unique<MsiUtil>()) {}
InstalledPrograms::~InstalledPrograms() = default;
bool InstalledPrograms::GetInstalledPrograms(
const base::FilePath& file,
std::vector<ProgramInfo>* programs) const {
// First, check if an exact file match exists in the installed files list.
if (GetProgramsFromInstalledFiles(file, programs))
return true;
// Then try to find a parent directory in the install directories list.
return GetProgramsFromInstallDirectories(file, programs);
}
InstalledPrograms::InstalledPrograms(std::unique_ptr<MsiUtil> msi_util) {
base::AssertBlockingAllowed();
SCOPED_UMA_HISTOGRAM_TIMER("ThirdPartyModules.InstalledPrograms.GetDataTime");
// Iterate over all the variants of the uninstall registry key.
static constexpr wchar_t kUninstallKeyPath[] =
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
// The "HKCU\SOFTWARE\" registry subtree is shared between both 32-bits and
// 64-bits views. Accessing both would create duplicate entries.
// https://msdn.microsoft.com/library/windows/desktop/aa384253.aspx
static const std::pair<HKEY, REGSAM> kCombinations[] = {
{HKEY_CURRENT_USER, 0},
{HKEY_LOCAL_MACHINE, KEY_WOW64_32KEY},
{HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY},
};
for (const auto& combination : kCombinations) {
for (base::win::RegistryKeyIterator i(combination.first, kUninstallKeyPath,
combination.second);
i.Valid(); ++i) {
CheckRegistryKeyForInstalledProgram(combination.first, kUninstallKeyPath,
combination.second, i.Name(),
*msi_util);
}
}
// The vectors are sorted so that binary searching can be used. No additional
// entries will be added anyways.
SortByFilePaths(&installed_files_);
SortByFilePaths(&install_directories_);
}
void InstalledPrograms::CheckRegistryKeyForInstalledProgram(
HKEY hkey, HKEY hkey,
const base::string16& key_path, const base::string16& key_path,
REGSAM wow64access, REGSAM wow64access,
const base::string16& key_name, const base::string16& key_name,
const MsiUtil& msi_util, const MsiUtil& msi_util) {
InstalledPrograms::ProgramsData* programs_data) {
base::string16 candidate_key_path = base::string16 candidate_key_path =
base::StringPrintf(L"%ls\\%ls", key_path.c_str(), key_name.c_str()); base::StringPrintf(L"%ls\\%ls", key_path.c_str(), key_name.c_str());
base::win::RegKey candidate(hkey, candidate_key_path.c_str(), base::win::RegKey candidate(hkey, candidate_key_path.c_str(),
...@@ -129,121 +184,26 @@ void CheckRegistryKeyForInstalledProgram( ...@@ -129,121 +184,26 @@ void CheckRegistryKeyForInstalledProgram(
base::FilePath install_path; base::FilePath install_path;
if (GetInstallPathUsingInstallLocation(candidate, &install_path)) { if (GetInstallPathUsingInstallLocation(candidate, &install_path)) {
programs_data->programs.push_back({std::move(display_name), hkey, programs_.push_back({std::move(display_name), hkey,
std::move(candidate_key_path), std::move(candidate_key_path), wow64access});
wow64access});
const size_t program_index = programs_data->programs.size() - 1; const size_t program_index = programs_.size() - 1;
programs_data->install_directories.emplace_back(std::move(install_path), install_directories_.emplace_back(std::move(install_path), program_index);
program_index);
return; return;
} }
std::vector<base::FilePath> installed_files; std::vector<base::FilePath> installed_files;
if (GetInstalledFilesUsingMsiGuid(key_name, msi_util, &installed_files)) { if (GetInstalledFilesUsingMsiGuid(key_name, msi_util, &installed_files)) {
programs_data->programs.push_back({std::move(display_name), hkey, programs_.push_back({std::move(display_name), hkey,
std::move(candidate_key_path), std::move(candidate_key_path), wow64access});
wow64access});
const size_t program_index = programs_data->programs.size() - 1; const size_t program_index = programs_.size() - 1;
for (auto& installed_file : installed_files) { for (auto& installed_file : installed_files) {
programs_data->installed_files.emplace_back(std::move(installed_file), installed_files_.emplace_back(std::move(installed_file), program_index);
program_index);
} }
} }
} }
// Helper function to sort |container| using CompareLessIgnoreCase.
void SortByFilePaths(
std::vector<std::pair<base::FilePath, size_t>>* container) {
std::sort(container->begin(), container->end(),
[](const auto& lhs, const auto& rhs) {
return base::FilePath::CompareLessIgnoreCase(lhs.first.value(),
rhs.first.value());
});
}
// Populates and returns a ProgramsData instance.
std::unique_ptr<InstalledPrograms::ProgramsData> GetProgramsData(
std::unique_ptr<MsiUtil> msi_util) {
SCOPED_UMA_HISTOGRAM_TIMER("ThirdPartyModules.InstalledPrograms.GetDataTime");
auto programs_data = std::make_unique<InstalledPrograms::ProgramsData>();
// Iterate over all the variants of the uninstall registry key.
const wchar_t kUninstallKeyPath[] =
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
// The "HKCU\SOFTWARE\" registry subtree is shared between both 32-bits and
// 64-bits views. Accessing both would create duplicate entries.
// https://msdn.microsoft.com/library/windows/desktop/aa384253.aspx
static const std::pair<HKEY, REGSAM> kCombinations[] = {
{HKEY_CURRENT_USER, 0},
{HKEY_LOCAL_MACHINE, KEY_WOW64_32KEY},
{HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY},
};
for (const auto& combination : kCombinations) {
for (base::win::RegistryKeyIterator i(combination.first, kUninstallKeyPath,
combination.second);
i.Valid(); ++i) {
CheckRegistryKeyForInstalledProgram(combination.first, kUninstallKeyPath,
combination.second, i.Name(),
*msi_util, programs_data.get());
}
}
// The vectors are sorted so that binary searching can be used. No additional
// entries will be added anyways.
SortByFilePaths(&programs_data->installed_files);
SortByFilePaths(&programs_data->install_directories);
return programs_data;
}
} // namespace
InstalledPrograms::ProgramsData::ProgramsData() = default;
InstalledPrograms::ProgramsData::~ProgramsData() = default;
InstalledPrograms::InstalledPrograms()
: initialized_(false), weak_ptr_factory_(this) {}
InstalledPrograms::~InstalledPrograms() = default;
void InstalledPrograms::Initialize(base::OnceClosure on_initialized_callback) {
Initialize(std::move(on_initialized_callback), std::make_unique<MsiUtil>());
}
bool InstalledPrograms::GetInstalledPrograms(
const base::FilePath& file,
std::vector<ProgramInfo>* programs) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(initialized_);
// First, check if an exact file match exists in the installed files list.
if (GetProgramsFromInstalledFiles(file, programs))
return true;
// Then try to find a parent directory in the install directories list.
return GetProgramsFromInstallDirectories(file, programs);
}
void InstalledPrograms::Initialize(base::OnceClosure on_initialized_callback,
std::unique_ptr<MsiUtil> msi_util) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!initialized_);
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&GetProgramsData, std::move(msi_util)),
base::BindOnce(&InstalledPrograms::OnInitializationDone,
weak_ptr_factory_.GetWeakPtr(),
std::move(on_initialized_callback)));
}
bool InstalledPrograms::GetProgramsFromInstalledFiles( bool InstalledPrograms::GetProgramsFromInstalledFiles(
const base::FilePath& file, const base::FilePath& file,
std::vector<ProgramInfo>* programs) const { std::vector<ProgramInfo>* programs) const {
...@@ -262,9 +222,8 @@ bool InstalledPrograms::GetProgramsFromInstalledFiles( ...@@ -262,9 +222,8 @@ bool InstalledPrograms::GetProgramsFromInstalledFiles(
} }
}; };
auto equal_range = std::equal_range(programs_data_->installed_files.begin(), auto equal_range = std::equal_range(
programs_data_->installed_files.end(), installed_files_.begin(), installed_files_.end(), file, FilePathLess());
file, FilePathLess());
auto nb_matches = std::distance(equal_range.first, equal_range.second); auto nb_matches = std::distance(equal_range.first, equal_range.second);
if (nb_matches == 0) if (nb_matches == 0)
...@@ -272,7 +231,7 @@ bool InstalledPrograms::GetProgramsFromInstalledFiles( ...@@ -272,7 +231,7 @@ bool InstalledPrograms::GetProgramsFromInstalledFiles(
programs->reserve(programs->size() + nb_matches); programs->reserve(programs->size() + nb_matches);
for (auto iter = equal_range.first; iter != equal_range.second; ++iter) for (auto iter = equal_range.first; iter != equal_range.second; ++iter)
programs->push_back(programs_data_->programs[iter->second]); programs->push_back(programs_[iter->second]);
return true; return true;
} }
...@@ -300,32 +259,19 @@ bool InstalledPrograms::GetProgramsFromInstallDirectories( ...@@ -300,32 +259,19 @@ bool InstalledPrograms::GetProgramsFromInstallDirectories(
} }
}; };
auto equal_range = std::equal_range( auto equal_range =
programs_data_->install_directories.begin(), std::equal_range(install_directories_.begin(), install_directories_.end(),
programs_data_->install_directories.end(), file, FilePathParentLess()); file, FilePathParentLess());
// Skip cases where there are multiple matches because there is no way to know // Skip cases where there are multiple matches because there is no way to know
// which program is the real owner of the |file| with the data owned by us. // which program is the real owner of the |file| with the data owned by us.
if (std::distance(equal_range.first, equal_range.second) != 1) if (std::distance(equal_range.first, equal_range.second) != 1)
return false; return false;
programs->push_back(programs_data_->programs[equal_range.first->second]); programs->push_back(programs_[equal_range.first->second]);
return true; return true;
} }
void InstalledPrograms::OnInitializationDone(
base::OnceClosure on_initialized_callback,
std::unique_ptr<ProgramsData> programs_data) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!initialized_);
programs_data_ = std::move(programs_data);
initialized_ = true;
if (on_initialized_callback)
std::move(on_initialized_callback).Run();
}
bool operator<(const InstalledPrograms::ProgramInfo& lhs, bool operator<(const InstalledPrograms::ProgramInfo& lhs,
const InstalledPrograms::ProgramInfo& rhs) { const InstalledPrograms::ProgramInfo& rhs) {
return std::tie(lhs.name, lhs.registry_root, lhs.registry_key_path, return std::tie(lhs.name, lhs.registry_root, lhs.registry_key_path,
......
...@@ -9,12 +9,10 @@ ...@@ -9,12 +9,10 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "base/callback_forward.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/win/windows_types.h"
class MsiUtil; class MsiUtil;
...@@ -49,8 +47,6 @@ class MsiUtil; ...@@ -49,8 +47,6 @@ class MsiUtil;
// - The uninstall entry has no display name. // - The uninstall entry has no display name.
// - The uninstall entry has no UninstallString. // - The uninstall entry has no UninstallString.
// //
// This class is not thread safe and should be only accessed on the same
// sequence.
class InstalledPrograms { class InstalledPrograms {
public: public:
struct ProgramInfo { struct ProgramInfo {
...@@ -62,73 +58,53 @@ class InstalledPrograms { ...@@ -62,73 +58,53 @@ class InstalledPrograms {
REGSAM registry_wow64_access; REGSAM registry_wow64_access;
}; };
// The guts of the class, this structure is populated on a background sequence // Initializes this instance with the list of installed programs. While the
// and moved back to this instance after initialization. // constructor must be called in a sequence that allows blocking, its public
struct ProgramsData { // method can be used without such restrictions.
ProgramsData();
~ProgramsData();
// Programs are stored in this vector because multiple entries in
// |installed_files| could point to the same one. This is to avoid
// duplicating them.
std::vector<ProgramInfo> programs;
// Contains all the files from programs installed via Microsoft Installer.
// The second part of the pair is the index into |programs|.
std::vector<std::pair<base::FilePath, size_t>> installed_files;
// For some programs, the best information available is the directory of the
// installation. The compare functor treats file paths where one is the
// parent of the other as equal.
// The second part of the pair is the index into |programs|.
std::vector<std::pair<base::FilePath, size_t>> install_directories;
};
InstalledPrograms(); InstalledPrograms();
virtual ~InstalledPrograms();
// Initializes this class on a background sequence. virtual ~InstalledPrograms();
void Initialize(base::OnceClosure on_initialized_callback);
// Given a |file|, checks if it matches an installed program on the user's // Given a |file|, checks if it matches an installed program on the user's
// machine and appends all the matching programs to |programs|. Do not call // machine and appends all the matching programs to |programs|.
// this before initialization completes.
// Virtual to allow mocking. // Virtual to allow mocking.
virtual bool GetInstalledPrograms(const base::FilePath& file, virtual bool GetInstalledPrograms(const base::FilePath& file,
std::vector<ProgramInfo>* programs) const; std::vector<ProgramInfo>* programs) const;
// Returns true if this instance is initialized and GetInstalledPrograms() can
// be called.
bool initialized() const { return initialized_; }
protected: protected:
// Protected so that tests can subclass InstalledPrograms and access it. // Protected so that tests can subclass InstalledPrograms and access it.
void Initialize(base::OnceClosure on_initialized_callback, explicit InstalledPrograms(std::unique_ptr<MsiUtil> msi_util);
std::unique_ptr<MsiUtil> msi_util);
private: private:
// If the registry key references a valid installed program, this function
// adds an entry to |programs_| with its list of files or installation
// directory to their associated vector.
void CheckRegistryKeyForInstalledProgram(HKEY hkey,
const base::string16& key_path,
REGSAM wow64access,
const base::string16& key_name,
const MsiUtil& msi_util);
bool GetProgramsFromInstalledFiles(const base::FilePath& file, bool GetProgramsFromInstalledFiles(const base::FilePath& file,
std::vector<ProgramInfo>* programs) const; std::vector<ProgramInfo>* programs) const;
bool GetProgramsFromInstallDirectories( bool GetProgramsFromInstallDirectories(
const base::FilePath& file, const base::FilePath& file,
std::vector<ProgramInfo>* programs) const; std::vector<ProgramInfo>* programs) const;
// Takes the result from the initialization and moves it to this instance, // Programs are stored in this vector because multiple entries in
// then calls |on_initialized_callback| to indicate that the initialization // |installed_files| could point to the same one. This is to avoid
// is done. // duplicating them.
void OnInitializationDone(base::OnceClosure on_initialized_callback, std::vector<ProgramInfo> programs_;
std::unique_ptr<ProgramsData> programs_data);
// Used to assert that initialization was completed before calling
// GetInstalledPrograms().
bool initialized_;
std::unique_ptr<ProgramsData> programs_data_;
// Make sure this class isn't accessed via multiple sequences. // Contains all the files from programs installed via Microsoft Installer.
SEQUENCE_CHECKER(sequence_checker_); // The second part of the pair is the index into |programs|.
std::vector<std::pair<base::FilePath, size_t>> installed_files_;
base::WeakPtrFactory<InstalledPrograms> weak_ptr_factory_; // For some programs, the best information available is the directory of the
// installation. The compare functor treats file paths where one is the
// parent of the other as equal.
// The second part of the pair is the index into |programs|.
std::vector<std::pair<base::FilePath, size_t>> install_directories_;
DISALLOW_COPY_AND_ASSIGN(InstalledPrograms); DISALLOW_COPY_AND_ASSIGN(InstalledPrograms);
}; };
......
...@@ -7,9 +7,7 @@ ...@@ -7,9 +7,7 @@
#include <map> #include <map>
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/test_reg_util_win.h" #include "base/test/test_reg_util_win.h"
#include "base/win/registry.h" #include "base/win/registry.h"
#include "chrome/browser/conflicts/msi_util_win.h" #include "chrome/browser/conflicts/msi_util_win.h"
...@@ -62,7 +60,8 @@ class MockMsiUtil : public MsiUtil { ...@@ -62,7 +60,8 @@ class MockMsiUtil : public MsiUtil {
class TestInstalledPrograms : public InstalledPrograms { class TestInstalledPrograms : public InstalledPrograms {
public: public:
using InstalledPrograms::Initialize; explicit TestInstalledPrograms(std::unique_ptr<MsiUtil> msi_util)
: InstalledPrograms(std::move(msi_util)) {}
}; };
class InstalledProgramsTest : public testing::Test { class InstalledProgramsTest : public testing::Test {
...@@ -114,22 +113,18 @@ class InstalledProgramsTest : public testing::Test { ...@@ -114,22 +113,18 @@ class InstalledProgramsTest : public testing::Test {
program_info.install_location.c_str()); program_info.install_location.c_str());
} }
TestInstalledPrograms& installed_programs() { return installed_programs_; } TestInstalledPrograms& installed_programs() { return *installed_programs_; }
void InitializeInstalledProgramsSynchronously() { void InitializeInstalledPrograms() {
installed_programs_.Initialize( installed_programs_ = std::make_unique<TestInstalledPrograms>(
base::Closure(), std::make_unique<MockMsiUtil>(component_paths_map_)); std::make_unique<MockMsiUtil>(component_paths_map_));
scoped_task_environment_.RunUntilIdle();
} }
private: private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
registry_util::RegistryOverrideManager registry_override_manager_; registry_util::RegistryOverrideManager registry_override_manager_;
TestInstalledPrograms installed_programs_; std::unique_ptr<TestInstalledPrograms> installed_programs_;
// This should not get modified after InitializeInstalledPrograms() is called
// because it will end up being accessed on a different thread by MockMsiUtil.
std::map<base::string16, std::vector<base::string16>> component_paths_map_; std::map<base::string16, std::vector<base::string16>> component_paths_map_;
DISALLOW_COPY_AND_ASSIGN(InstalledProgramsTest); DISALLOW_COPY_AND_ASSIGN(InstalledProgramsTest);
...@@ -175,7 +170,7 @@ TEST_F(InstalledProgramsTest, InvalidEntries) { ...@@ -175,7 +170,7 @@ TEST_F(InstalledProgramsTest, InvalidEntries) {
for (const auto& test_case : kTestCases) for (const auto& test_case : kTestCases)
AddFakeProgram(test_case); AddFakeProgram(test_case);
InitializeInstalledProgramsSynchronously(); InitializeInstalledPrograms();
// None of the invalid entries were picked up. // None of the invalid entries were picked up.
const base::FilePath valid_child_file = const base::FilePath valid_child_file =
...@@ -201,7 +196,7 @@ TEST_F(InstalledProgramsTest, InstallLocation) { ...@@ -201,7 +196,7 @@ TEST_F(InstalledProgramsTest, InstallLocation) {
AddFakeProgram(kTestCase); AddFakeProgram(kTestCase);
InitializeInstalledProgramsSynchronously(); InitializeInstalledPrograms();
// Child file path. // Child file path.
const base::FilePath valid_child_file = const base::FilePath valid_child_file =
...@@ -242,7 +237,7 @@ TEST_F(InstalledProgramsTest, Msi) { ...@@ -242,7 +237,7 @@ TEST_F(InstalledProgramsTest, Msi) {
AddFakeProgram(kTestCase); AddFakeProgram(kTestCase);
InitializeInstalledProgramsSynchronously(); InitializeInstalledPrograms();
// Checks that all the files match the program. // Checks that all the files match the program.
for (const auto& component : kTestCase.components) { for (const auto& component : kTestCase.components) {
...@@ -293,7 +288,7 @@ TEST_F(InstalledProgramsTest, PrioritizeMsi) { ...@@ -293,7 +288,7 @@ TEST_F(InstalledProgramsTest, PrioritizeMsi) {
AddFakeProgram(kInstallLocationFakeProgram); AddFakeProgram(kInstallLocationFakeProgram);
AddFakeProgram(kMsiFakeProgram); AddFakeProgram(kMsiFakeProgram);
InitializeInstalledProgramsSynchronously(); InitializeInstalledPrograms();
std::vector<InstalledPrograms::ProgramInfo> programs; std::vector<InstalledPrograms::ProgramInfo> programs;
EXPECT_TRUE(installed_programs().GetInstalledPrograms( EXPECT_TRUE(installed_programs().GetInstalledPrograms(
...@@ -330,7 +325,7 @@ TEST_F(InstalledProgramsTest, ConflictingInstallLocations) { ...@@ -330,7 +325,7 @@ TEST_F(InstalledProgramsTest, ConflictingInstallLocations) {
AddFakeProgram(kFakeProgram1); AddFakeProgram(kFakeProgram1);
AddFakeProgram(kFakeProgram2); AddFakeProgram(kFakeProgram2);
InitializeInstalledProgramsSynchronously(); InitializeInstalledPrograms();
std::vector<InstalledPrograms::ProgramInfo> programs; std::vector<InstalledPrograms::ProgramInfo> programs;
EXPECT_FALSE(installed_programs().GetInstalledPrograms(base::FilePath(kFile), EXPECT_FALSE(installed_programs().GetInstalledPrograms(base::FilePath(kFile),
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/i18n/case_conversion.h" #include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/sha1.h" #include "base/sha1.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
......
...@@ -6,11 +6,9 @@ ...@@ -6,11 +6,9 @@
#define CHROME_BROWSER_CONFLICTS_MODULE_LIST_FILTER_WIN_H_ #define CHROME_BROWSER_CONFLICTS_MODULE_LIST_FILTER_WIN_H_
#include <memory> #include <memory>
#include <string>
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/conflicts/proto/module_list.pb.h" #include "chrome/browser/conflicts/proto/module_list.pb.h"
#include "url/gurl.h"
struct ModuleInfoKey; struct ModuleInfoKey;
struct ModuleInfoData; struct ModuleInfoData;
...@@ -26,9 +24,6 @@ class ModuleListFilter { ...@@ -26,9 +24,6 @@ class ModuleListFilter {
ModuleListFilter(); ModuleListFilter();
virtual ~ModuleListFilter(); virtual ~ModuleListFilter();
// Initializes the filter with the serialized proto at |module_list_path|.
// This must be invoked before any calls to IsWhitelisted() and
// IsBlacklisted().
bool Initialize(const base::FilePath& module_list_path); bool Initialize(const base::FilePath& module_list_path);
// Returns true if the module is whitelisted. // Returns true if the module is whitelisted.
......
...@@ -139,7 +139,7 @@ constexpr wchar_t kDllPath2[] = L"c:\\some\\shellextension.dll"; ...@@ -139,7 +139,7 @@ constexpr wchar_t kDllPath2[] = L"c:\\some\\shellextension.dll";
} // namespace } // namespace
class ModuleListFilterTest : public ::testing::Test { class ModuleListFilterTest : public ::testing::Test {
public: protected:
ModuleListFilterTest() : dll1_(kDllPath1), dll2_(kDllPath2) {} ModuleListFilterTest() : dll1_(kDllPath1), dll2_(kDllPath2) {}
~ModuleListFilterTest() override = default; ~ModuleListFilterTest() override = default;
......
...@@ -7,57 +7,98 @@ ...@@ -7,57 +7,98 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/location.h"
#include "base/task_scheduler/post_task.h"
#include "chrome/browser/conflicts/installed_programs_win.h"
#include "chrome/browser/conflicts/module_database_win.h" #include "chrome/browser/conflicts/module_database_win.h"
#include "chrome/browser/conflicts/module_list_filter_win.h" #include "chrome/browser/conflicts/module_list_filter_win.h"
#include "chrome/browser/conflicts/problematic_programs_updater_win.h" #include "chrome/browser/conflicts/problematic_programs_updater_win.h"
namespace {
std::unique_ptr<ModuleListFilter> CreateModuleListFilter(
const base::FilePath& module_list_path) {
auto module_list_filter = std::make_unique<ModuleListFilter>();
if (!module_list_filter->Initialize(module_list_path))
return nullptr;
return module_list_filter;
}
} // namespace
ThirdPartyConflictsManager::ThirdPartyConflictsManager( ThirdPartyConflictsManager::ThirdPartyConflictsManager(
ModuleDatabase* module_database) ModuleDatabase* module_database)
: module_database_(module_database), module_list_received_(false) {} : module_database_(module_database),
module_list_received_(false),
on_module_database_idle_called_(false),
weak_ptr_factory_(this) {}
ThirdPartyConflictsManager::~ThirdPartyConflictsManager() = default; ThirdPartyConflictsManager::~ThirdPartyConflictsManager() = default;
void ThirdPartyConflictsManager::OnModuleDatabaseIdle() { void ThirdPartyConflictsManager::OnModuleDatabaseIdle() {
if (installed_programs_.initialized()) if (on_module_database_idle_called_)
return; return;
// ThirdPartyConflictsManager owns |installed_programs_|, so it is safe to use on_module_database_idle_called_ = true;
// base::Unretained().
installed_programs_.Initialize(base::BindOnce( base::PostTaskWithTraitsAndReplyWithResult(
&ThirdPartyConflictsManager::OnInstalledProgramsInitialized, FROM_HERE,
base::Unretained(this))); {base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce([]() { return std::make_unique<InstalledPrograms>(); }),
base::BindOnce(&ThirdPartyConflictsManager::OnInstalledProgramsCreated,
weak_ptr_factory_.GetWeakPtr()));
} }
void ThirdPartyConflictsManager::LoadModuleList(const base::FilePath& path) { void ThirdPartyConflictsManager::LoadModuleList(const base::FilePath& path) {
// No attempt is made to dynamically reconcile a new module list version. The
// next Chrome launch will pick it up.
if (module_list_received_) if (module_list_received_)
return; return;
auto module_list_filter = std::make_unique<ModuleListFilter>(); module_list_received_ = true;
if (!module_list_filter->Initialize(path))
return; base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&CreateModuleListFilter, path),
base::BindOnce(&ThirdPartyConflictsManager::OnModuleListFilterCreated,
weak_ptr_factory_.GetWeakPtr()));
}
void ThirdPartyConflictsManager::OnModuleListFilterCreated(
std::unique_ptr<ModuleListFilter> module_list_filter) {
module_list_filter_ = std::move(module_list_filter); module_list_filter_ = std::move(module_list_filter);
// Mark the module list as received here so that if Initialize() fails, // A valid |module_list_filter_| is critical to the blocking of third-party
// another attempt will be made with a newer version. // modules. By returning early here, the |problematic_programs_updater_|
module_list_received_ = true; // instance never gets created, thus disabling the identification of
// incompatible applications.
if (!module_list_filter_) {
// Mark the module list as not received so that a new one may trigger the
// creation of a valid filter.
module_list_received_ = false;
return;
}
if (installed_programs_.initialized()) if (installed_programs_)
InitializeProblematicProgramsUpdater(); InitializeProblematicProgramsUpdater();
} }
void ThirdPartyConflictsManager::OnInstalledProgramsInitialized() { void ThirdPartyConflictsManager::OnInstalledProgramsCreated(
if (module_list_received_) std::unique_ptr<InstalledPrograms> installed_programs) {
installed_programs_ = std::move(installed_programs);
if (module_list_filter_)
InitializeProblematicProgramsUpdater(); InitializeProblematicProgramsUpdater();
} }
void ThirdPartyConflictsManager::InitializeProblematicProgramsUpdater() { void ThirdPartyConflictsManager::InitializeProblematicProgramsUpdater() {
DCHECK(module_list_received_); DCHECK(module_list_filter_);
DCHECK(installed_programs_.initialized()); DCHECK(installed_programs_);
problematic_programs_updater_ = ProblematicProgramsUpdater::MaybeCreate( problematic_programs_updater_ = ProblematicProgramsUpdater::MaybeCreate(
*module_list_filter_, installed_programs_); *module_list_filter_, *installed_programs_);
if (problematic_programs_updater_) if (problematic_programs_updater_)
module_database_->AddObserver(problematic_programs_updater_.get()); module_database_->AddObserver(problematic_programs_updater_.get());
} }
...@@ -8,11 +8,12 @@ ...@@ -8,11 +8,12 @@
#include <memory> #include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/conflicts/installed_programs_win.h" #include "base/memory/weak_ptr.h"
#include "chrome/browser/conflicts/module_database_observer_win.h" #include "chrome/browser/conflicts/module_database_observer_win.h"
class ModuleDatabase; class ModuleDatabase;
class ModuleListFilter; class ModuleListFilter;
class InstalledPrograms;
class ProblematicProgramsUpdater; class ProblematicProgramsUpdater;
namespace base { namespace base {
...@@ -33,8 +34,12 @@ class ThirdPartyConflictsManager : public ModuleDatabaseObserver { ...@@ -33,8 +34,12 @@ class ThirdPartyConflictsManager : public ModuleDatabaseObserver {
void LoadModuleList(const base::FilePath& path); void LoadModuleList(const base::FilePath& path);
private: private:
// Called when |module_list_filter_| finishes its initialization.
void OnModuleListFilterCreated(std::unique_ptr<ModuleListFilter>);
// Called when |installed_programs_| finishes its initialization. // Called when |installed_programs_| finishes its initialization.
void OnInstalledProgramsInitialized(); void OnInstalledProgramsCreated(
std::unique_ptr<InstalledPrograms> installed_programs);
// Initializes |problematic_programs_updater_| when both the ModuleListFilter // Initializes |problematic_programs_updater_| when both the ModuleListFilter
// and the InstalledPrograms are available. // and the InstalledPrograms are available.
...@@ -42,18 +47,26 @@ class ThirdPartyConflictsManager : public ModuleDatabaseObserver { ...@@ -42,18 +47,26 @@ class ThirdPartyConflictsManager : public ModuleDatabaseObserver {
ModuleDatabase* module_database_; ModuleDatabase* module_database_;
// Indicates if the initial Module List has been received. // Indicates if the initial Module List has been received. Used to prevent the
// creation of multiple ModuleListFilter instances.
bool module_list_received_; bool module_list_received_;
// Indicates if the OnModuleDatabaseIdle() function has been called once
// already. Used to prevent the creation of multiple InstalledPrograms
// instances.
bool on_module_database_idle_called_;
// Filters third-party modules against a whitelist and a blacklist. // Filters third-party modules against a whitelist and a blacklist.
std::unique_ptr<ModuleListFilter> module_list_filter_; std::unique_ptr<ModuleListFilter> module_list_filter_;
// Retrieves the list of installed programs. // Retrieves the list of installed programs.
InstalledPrograms installed_programs_; std::unique_ptr<InstalledPrograms> installed_programs_;
// Maintains the cache of problematic programs. // Maintains the cache of problematic programs.
std::unique_ptr<ProblematicProgramsUpdater> problematic_programs_updater_; std::unique_ptr<ProblematicProgramsUpdater> problematic_programs_updater_;
base::WeakPtrFactory<ThirdPartyConflictsManager> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ThirdPartyConflictsManager); DISALLOW_COPY_AND_ASSIGN(ThirdPartyConflictsManager);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment