910e62b5创建于 1月15日历史提交
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_UPDATER_POLICY_SERVICE_H_
#define CHROME_UPDATER_POLICY_SERVICE_H_

#include <optional>
#include <set>
#include <string>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/updater/event_history.h"
#include "chrome/updater/external_constants.h"
#include "chrome/updater/persisted_data.h"
#include "chrome/updater/policy/manager.h"

namespace policy {
enum class PolicyFetchReason;
}  // namespace policy

namespace updater {

class PolicyFetcher;

// This class contains the aggregate status of a policy value. It determines
// whether a conflict exists when multiple policy providers set the same policy.
// Instances are logically true if an effective policy is set.
template <typename T>
class PolicyStatus {
 public:
  struct Entry {
    Entry(const std::string& s, T p) : source(s), policy(p) {}
    std::string source;
    T policy{};
  };

  PolicyStatus() = default;
  PolicyStatus(const PolicyStatus&) = default;
  PolicyStatus& operator=(const PolicyStatus&) = default;

  void AddPolicy(bool is_managed, const std::string& source, const T& policy) {
    all_policies_.emplace_back(source, policy);

    if (conflict_policy_) {
      return;  // We already have enough policies.
    }

    if (!effective_policy_ && is_managed) {
      effective_policy_ = std::make_optional<Entry>(source, policy);
    } else if (effective_policy_ &&
               policy != effective_policy_.value().policy) {
      conflict_policy_ = std::make_optional<Entry>(source, policy);
    }
  }

  const std::optional<Entry>& effective_policy() const {
    return effective_policy_;
  }
  const std::optional<Entry>& conflict_policy() const {
    return conflict_policy_;
  }
  const std::vector<Entry>& all_policies() const { return all_policies_; }

  std::optional<T> effective_policy_value() const {
    return effective_policy_ ? std::optional<T>(effective_policy_->policy)
                             : std::nullopt;
  }

  explicit operator bool() const { return effective_policy_.has_value(); }
  // Convenience method to extract the effective policy's value.
  const T& policy() const {
    CHECK(effective_policy_);
    return effective_policy_->policy;
  }
  const T& policy_or(const T& fallback) const {
    return effective_policy_ ? policy() : fallback;
  }

 private:
  std::optional<Entry> effective_policy_;
  std::optional<Entry> conflict_policy_;
  std::vector<Entry> all_policies_;
};

// The PolicyService returns policies for enterprise managed machines from the
// source with the highest priority where the policy available.
// This class is sequence affine and its instance is bound to the main sequence.
class PolicyService : public base::RefCountedThreadSafe<PolicyService> {
 public:
  class PolicyManagers {
   public:
    explicit PolicyManagers(
        scoped_refptr<ExternalConstants> external_constants);
    ~PolicyManagers();

    void ResetDeviceManagementManager(
        scoped_refptr<PolicyManagerInterface> dm_manager);

    std::vector<scoped_refptr<PolicyManagerInterface>> managers() const {
      return managers_;
    }

    void SetManagersForTesting(
        std::vector<scoped_refptr<PolicyManagerInterface>> managers);

   private:
    void CreateManagers(scoped_refptr<ExternalConstants> external_constants);
    void InitializeManagersVector();
    void SortManagersVector();
    static bool CloudPolicyOverridesPlatformPolicy(
        const std::vector<scoped_refptr<PolicyManagerInterface>>& providers);

    std::vector<scoped_refptr<PolicyManagerInterface>> managers_;
    scoped_refptr<PolicyManagerInterface> dm_policy_manager_;
    scoped_refptr<PolicyManagerInterface> external_constants_policy_manager_;
    scoped_refptr<PolicyManagerInterface> platform_policy_manager_;
    scoped_refptr<PolicyManagerInterface> default_policy_manager_;
  };

  PolicyService(scoped_refptr<ExternalConstants> external_constants,
                scoped_refptr<PersistedData> persisted_data);
  PolicyService(const PolicyService&) = delete;
  PolicyService& operator=(const PolicyService&) = delete;

  // Fetches policies from device management and updates the PolicyService
  // instance. `callback` is passed a result that is `kErrorOk` on success,
  // `kErrorDMRegistrationFailed` if DM registration fails, or any other error.
  // While a call to FetchPolicies is outstanding (i.e. has not invoked the
  // callback), concurrent calls to FetchPolicies will reuse the results of the
  // outstanding request.
  void FetchPolicies(policy::PolicyFetchReason reason,
                     base::OnceCallback<void(int)> callback);

  std::string source() const;

  // These methods call and aggregate the results from the policy managers.
  PolicyStatus<bool> CloudPolicyOverridesPlatformPolicy() const;
  PolicyStatus<base::TimeDelta> GetLastCheckPeriod() const;
  PolicyStatus<UpdatesSuppressedTimes> GetUpdatesSuppressedTimes() const;
  PolicyStatus<std::string> GetDownloadPreference() const;
  PolicyStatus<int> GetPackageCacheSizeLimitMBytes() const;
  PolicyStatus<int> GetPackageCacheExpirationTimeDays() const;
  PolicyStatus<int> GetPolicyForAppInstalls(const std::string& app_id) const;
  PolicyStatus<int> GetPolicyForAppUpdates(const std::string& app_id) const;
  PolicyStatus<std::string> GetTargetChannel(const std::string& app_id) const;
  PolicyStatus<std::string> GetTargetVersionPrefix(
      const std::string& app_id) const;
  PolicyStatus<bool> IsRollbackToTargetVersionAllowed(
      const std::string& app_id) const;
  PolicyStatus<int> GetMajorVersionRolloutPolicy(
      const std::string& app_id) const;
  PolicyStatus<int> GetMinorVersionRolloutPolicy(
      const std::string& app_id) const;
  PolicyStatus<std::string> GetProxyMode() const;
  PolicyStatus<std::string> GetProxyPacUrl() const;
  PolicyStatus<std::string> GetProxyServer() const;
  PolicyStatus<std::vector<std::string>> GetForceInstallApps() const;

  // DEPRECATED: Prefer |GetLastCheckPeriod|. This function should only be used
  // in legacy interfaces where a PolicyStatus<int> is required.
  PolicyStatus<int> DeprecatedGetLastCheckPeriodMinutes() const;

  // Helper methods.
  base::Value::Dict GetAllPolicies() const;
  std::string GetAllPoliciesAsString() const;
  bool AreUpdatesSuppressedNow(base::Time now = base::Time::Now()) const;

  void SetManagersForTesting(
      std::vector<scoped_refptr<PolicyManagerInterface>> managers);

 protected:
  virtual ~PolicyService();

 private:
  friend class base::RefCountedThreadSafe<PolicyService>;

  template <typename T>
  using PolicyQueryFunction =
      std::optional<T> (PolicyManagerInterface::*)() const;
  template <typename T>
  using AppPolicyQueryFunction =
      std::optional<T> (PolicyManagerInterface::*)(const std::string&) const;

  void DoFetchPolicies(policy::PolicyFetchReason reason,
                       base::OnceCallback<void(int)> callback,
                       bool has_enrollment_token);

  // Called when `FetchPolicies` has completed. If `dm_policy_manager` is valid,
  // the policy managers within the policy service are reloaded/reset with the
  // provided DM policy manager.
  void FetchPoliciesDone(
      scoped_refptr<PolicyFetcher> fetcher,
      LoadPolicyEndEvent event,
      int result,
      scoped_refptr<PolicyManagerInterface> dm_policy_manager);

  // Queries the policy from the managed policy providers and determines the
  // policy status. The provided `transform` can be used to modify the queried
  // value to be a different type, or to nullify it when invalid.
  template <typename T, typename U = T>
  PolicyStatus<U> QueryPolicy(
      PolicyQueryFunction<T> policy_query_function,
      const base::RepeatingCallback<std::optional<U>(std::optional<T>)>&
          transform = base::NullCallback()) const;

  // Queries app policy from the managed policy providers and determines the
  // policy status.
  template <typename T>
  PolicyStatus<T> QueryAppPolicy(
      AppPolicyQueryFunction<T> policy_query_function,
      const std::string& app_id) const;

  std::set<std::string> GetAppsWithPolicy() const;

  SEQUENCE_CHECKER(sequence_checker_);

  // List of policy providers in descending order of priority. All managed
  // providers should be ahead of non-managed providers.
  // Also contains a named map indexed by `source()` for all the policy
  // managers.
  std::unique_ptr<PolicyManagers> policy_managers_;
  const scoped_refptr<ExternalConstants> external_constants_;

  base::OnceCallback<void(int)> fetch_policies_callback_;
  scoped_refptr<PersistedData> persisted_data_;
};

// Decouples the proxy configuration from `PolicyService`.
struct PolicyServiceProxyConfiguration {
  PolicyServiceProxyConfiguration();
  ~PolicyServiceProxyConfiguration();
  PolicyServiceProxyConfiguration(const PolicyServiceProxyConfiguration&);
  PolicyServiceProxyConfiguration(PolicyServiceProxyConfiguration&&);
  PolicyServiceProxyConfiguration& operator=(
      const PolicyServiceProxyConfiguration&);
  PolicyServiceProxyConfiguration& operator=(PolicyServiceProxyConfiguration&&);

  // Note `Get()` returns a nullopt when there's no proxy policies. Otherwise
  // `proxy_auto_detect` must have a value, and is only set to true when the
  // policy chooses "auto-detect".
  static std::optional<PolicyServiceProxyConfiguration> Get(
      scoped_refptr<PolicyService> policy_service);

  bool proxy_auto_detect = false;
  std::optional<std::string> proxy_pac_url;
  std::optional<std::string> proxy_url;
};

// Queries whether the machine appears to be cloud managed by Chrome
// Enterprise Core (formerly Chrome Enterprise Cloud Management). Performs
// blocking IO.
bool IsCloudManaged();

}  // namespace updater

#endif  // CHROME_UPDATER_POLICY_SERVICE_H_