blob: 5a3886be5584cca713f93c16a30ea56abfbd468b [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/printing/synced_printers_manager.h"
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "base/guid.h"
#include "base/observer_list_threadsafe.h"
#include "base/optional.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/printing/enterprise_printers_provider.h"
#include "chrome/browser/chromeos/printing/printer_configurer.h"
#include "chrome/browser/chromeos/printing/printers_sync_bridge.h"
#include "chrome/browser/chromeos/printing/specifics_translation.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chromeos/printing/printer_configuration.h"
#include "chromeos/printing/printer_translator.h"
#include "chromeos/settings/cros_settings_names.h"
#include "components/policy/policy_constants.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
namespace chromeos {
namespace {
class SyncedPrintersManagerImpl : public SyncedPrintersManager,
public PrintersSyncBridge::Observer,
public EnterprisePrintersProvider::Observer {
public:
SyncedPrintersManagerImpl(Profile* profile,
std::unique_ptr<PrintersSyncBridge> sync_bridge)
: profile_(profile),
sync_bridge_(std::move(sync_bridge)),
observers_(new base::ObserverListThreadSafe<
SyncedPrintersManager::Observer>()),
weak_factory_(this) {
printers_provider_ =
EnterprisePrintersProvider::Create(CrosSettings::Get(), profile_);
printers_provider_->AddObserver(this);
sync_bridge_->AddObserver(this);
}
~SyncedPrintersManagerImpl() override {
printers_provider_->RemoveObserver(this);
sync_bridge_->RemoveObserver(this);
}
std::vector<Printer> GetConfiguredPrinters() const override {
// No need to lock here, since sync_bridge_ is thread safe and we don't
// touch anything else.
std::vector<Printer> printers;
std::vector<sync_pb::PrinterSpecifics> values =
sync_bridge_->GetAllPrinters();
for (const auto& value : values) {
printers.push_back(*SpecificsToPrinter(value));
}
return printers;
}
bool GetEnterprisePrinters(std::vector<Printer>& printers) const override {
base::AutoLock l(lock_);
printers = GetEnterprisePrintersLocked();
return enterprise_printers_are_ready_;
}
std::unique_ptr<Printer> GetPrinter(
const std::string& printer_id) const override {
base::AutoLock l(lock_);
return GetPrinterLocked(printer_id);
}
void UpdateConfiguredPrinter(const Printer& printer) override {
base::AutoLock l(lock_);
UpdateConfiguredPrinterLocked(printer);
}
bool RemoveConfiguredPrinter(const std::string& printer_id) override {
return sync_bridge_->RemovePrinter(printer_id);
}
void AddObserver(SyncedPrintersManager::Observer* observer) override {
observers_->AddObserver(observer);
}
void RemoveObserver(SyncedPrintersManager::Observer* observer) override {
observers_->RemoveObserver(observer);
}
void PrinterInstalled(const Printer& printer) override {
base::AutoLock l(lock_);
installed_printer_fingerprints_[printer.id()] =
PrinterConfigurer::SetupFingerprint(printer);
// Register this printer if it's the first time we're using it.
if (!IsPrinterRegistered(printer.id())) {
UpdateConfiguredPrinterLocked(printer);
}
}
bool IsConfigurationCurrent(const Printer& printer) const override {
base::AutoLock l(lock_);
auto found = installed_printer_fingerprints_.find(printer.id());
if (found == installed_printer_fingerprints_.end())
return false;
return found->second == PrinterConfigurer::SetupFingerprint(printer);
}
PrintersSyncBridge* GetSyncBridge() override { return sync_bridge_.get(); }
// PrintersSyncBridge::Observer override.
void OnPrintersUpdated() override {
observers_->Notify(
FROM_HERE,
&SyncedPrintersManager::Observer::OnConfiguredPrintersChanged,
GetConfiguredPrinters());
}
// EnterprisePrintersProvider::Observer override
void OnPrintersChanged(
bool complete,
const std::unordered_map<std::string, Printer>& printers) override {
// Enterprise printers policy changed. Update the lists.
base::AutoLock l(lock_);
enterprise_printers_ = printers;
enterprise_printers_are_ready_ = complete;
observers_->Notify(
FROM_HERE,
&SyncedPrintersManager::Observer::OnEnterprisePrintersChanged,
GetEnterprisePrintersLocked(), enterprise_printers_are_ready_);
}
private:
std::unique_ptr<Printer> GetPrinterLocked(
const std::string& printer_id) const {
lock_.AssertAcquired();
// check for a policy printer first
auto found = enterprise_printers_.find(printer_id);
if (found != enterprise_printers_.end()) {
// Copy a printer.
return std::make_unique<Printer>(found->second);
}
base::Optional<sync_pb::PrinterSpecifics> printer =
sync_bridge_->GetPrinter(printer_id);
return printer.has_value() ? SpecificsToPrinter(*printer) : nullptr;
}
// Determines whether or not the printer with the given |printer_id| has
// already been registered.
bool IsPrinterRegistered(const std::string& printer_id) {
return enterprise_printers_.find(printer_id) !=
enterprise_printers_.end() ||
sync_bridge_->HasPrinter(printer_id);
}
void UpdateConfiguredPrinterLocked(const Printer& printer_arg) {
lock_.AssertAcquired();
DCHECK_EQ(Printer::SRC_USER_PREFS, printer_arg.source());
// Need a local copy since we may set the id.
Printer printer = printer_arg;
if (printer.id().empty()) {
printer.set_id(base::GenerateGUID());
}
sync_bridge_->UpdatePrinter(PrinterToSpecifics(printer));
}
std::vector<Printer> GetEnterprisePrintersLocked() const {
lock_.AssertAcquired();
std::vector<Printer> ret;
ret.reserve(enterprise_printers_.size());
for (auto kv : enterprise_printers_) {
ret.push_back(kv.second);
}
return ret;
}
mutable base::Lock lock_;
Profile* profile_;
// The backend for profile printers.
std::unique_ptr<PrintersSyncBridge> sync_bridge_;
// The Object that provides updates about enterprise printers.
std::unique_ptr<EnterprisePrintersProvider> printers_provider_;
// Enterprise printers as of the last time we got a policy update.
std::unordered_map<std::string, Printer> enterprise_printers_;
// This flag is set to true if all enterprise policies were loaded.
bool enterprise_printers_are_ready_ = false;
// Map of printer ids to PrinterConfigurer setup fingerprints at the time
// the printers was last installed with CUPS.
std::map<std::string, std::string> installed_printer_fingerprints_;
scoped_refptr<base::ObserverListThreadSafe<SyncedPrintersManager::Observer>>
observers_;
base::WeakPtrFactory<SyncedPrintersManagerImpl> weak_factory_;
};
} // namespace
// static
void SyncedPrintersManager::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
EnterprisePrintersProvider::RegisterProfilePrefs(registry);
}
// static
std::unique_ptr<SyncedPrintersManager> SyncedPrintersManager::Create(
Profile* profile,
std::unique_ptr<PrintersSyncBridge> sync_bridge) {
return std::make_unique<SyncedPrintersManagerImpl>(profile,
std::move(sync_bridge));
}
} // namespace chromeos