chromium/chrome/browser/ash/policy/core/device_policy_decoder.cc

// 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/ash/policy/core/device_policy_decoder.h"

#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>

#include "ash/system/privacy_hub/privacy_hub_controller.h"
#include "base/containers/fixed_flat_map.h"
#include "base/functional/callback.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/syslog_logging.h"
#include "base/types/expected_macros.h"
#include "chrome/browser/ash/policy/handlers/device_dlc_predownload_list_policy_handler.h"
#include "chrome/browser/ash/policy/off_hours/off_hours_proto_parser.h"
#include "chrome/browser/ash/tpm_firmware_update.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chromeos/ash/components/dbus/dbus_thread_manager.h"
#include "chromeos/ash/components/dbus/update_engine/update_engine_client.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "components/policy/core/browser/policy_error_map.h"
#include "components/policy/core/common/chrome_schema.h"
#include "components/policy/core/common/device_local_account_type.h"
#include "components/policy/core/common/external_data_fetcher.h"
#include "components/policy/core/common/external_data_manager.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/core/common/schema.h"
#include "components/policy/policy_constants.h"
#include "components/strings/grit/components_strings.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "third_party/re2/src/re2/re2.h"
#include "ui/base/l10n/l10n_util.h"

namespace policy {

using ::google::protobuf::RepeatedPtrField;

namespace em = ::enterprise_management;

// A pattern for validating hostnames.
const char hostNameRegex[] = "^([A-z0-9][A-z0-9-]*\\.)+[A-z0-9]+$";

namespace {

void SetJsonDevicePolicyWithError(
    const std::string& policy_name,
    const std::string& json_string,
    std::unique_ptr<ExternalDataFetcher> external_data_fetcher,
    PolicyMap* policies,
    std::string error) {
  policies->Set(policy_name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                POLICY_SOURCE_CLOUD, base::Value(json_string),
                std::move(external_data_fetcher));

  policies->AddMessage(policy_name, PolicyMap::MessageType::kError,
                       IDS_POLICY_PROTO_PARSING_ERROR,
                       {base::UTF8ToUTF16(error)});
}

// If the |json_string| can be decoded and validated against the schema
// identified by |policy_name| in policy_templates.json, the policy
// |policy_name| in |policies| will be set to the decoded base::Value.
// Otherwise, the policy will be set to a base::Value of the original
// |json_string|. This way, the faulty value can still be seen in
// chrome://policy along with any errors/warnings.
void SetJsonDevicePolicy(
    const std::string& policy_name,
    const std::string& json_string,
    std::unique_ptr<ExternalDataFetcher> external_data_fetcher,
    PolicyMap* policies) {
  if (auto result = DecodeJsonStringAndNormalize(json_string, policy_name);
      result.has_value()) {
    policies->Set(policy_name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD, std::move(result->decoded_json),
                  std::move(external_data_fetcher));

    if (result->non_fatal_errors.has_value()) {
      policies->AddMessage(policy_name, PolicyMap::MessageType::kError,
                           IDS_POLICY_PROTO_PARSING_ERROR,
                           {base::UTF8ToUTF16(*result->non_fatal_errors)});
    }
  } else {
    SetJsonDevicePolicyWithError(policy_name, json_string,
                                 std::move(external_data_fetcher), policies,
                                 result.error());
  }
}

void SetDeviceDlcPredownloadListPolicy(
    const RepeatedPtrField<std::string>& raw_policy_value,
    PolicyMap* policies) {
  std::string warning;
  base::Value::List decoded_dlc_list =
      policy::DeviceDlcPredownloadListPolicyHandler::
          DecodeDeviceDlcPredownloadListPolicy(raw_policy_value, warning);
  policies->Set(key::kDeviceDlcPredownloadList, POLICY_LEVEL_MANDATORY,
                POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                base::Value(std::move(decoded_dlc_list)), nullptr);
  if (!warning.empty()) {
    policies->AddMessage(
        key::kDeviceDlcPredownloadList, PolicyMap::MessageType::kWarning,
        IDS_POLICY_PROTO_PARSING_ERROR, {base::UTF8ToUTF16(warning)});
  }
}
// Returns a `PolicyLevel` if the policy has been set at that level. If the
// policy has been set at the level of `PolicyOptions::UNSET` returns
// `std::nullopt` instead.
std::optional<PolicyLevel> GetPolicyLevel(
    bool has_policy_options,
    const em::PolicyOptions& policy_option_proto) {
  if (!has_policy_options) {
    return POLICY_LEVEL_MANDATORY;
  }
  switch (policy_option_proto.mode()) {
    case em::PolicyOptions::MANDATORY:
      return POLICY_LEVEL_MANDATORY;
    case em::PolicyOptions::RECOMMENDED:
      return POLICY_LEVEL_RECOMMENDED;
    case em::PolicyOptions::UNSET:
      return std::nullopt;
  }
  NOTREACHED_IN_MIGRATION();
  return std::nullopt;
}

void SetJsonDevicePolicy(const std::string& policy_name,
                         const std::string& json_string,
                         PolicyMap* policies) {
  SetJsonDevicePolicy(policy_name, json_string,
                      /* external_data_fetcher */ nullptr, policies);
}

// Function that sets the policy value and validates it with a regex, adding
// error in case of not matching.
void SetPolicyWithValidatingRegex(const std::string& policy_name,
                                  const std::string& policy_value,
                                  const std::string& pattern,
                                  PolicyMap* policies) {
  policies->Set(policy_name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                POLICY_SOURCE_CLOUD, base::Value(policy_value), nullptr);
  if (!RE2::FullMatch(policy_value, pattern)) {
    policies->AddMessage(policy_name, PolicyMap::MessageType::kError,
                         IDS_POLICY_INVALID_VALUE);
  }
}

void SetExternalDataDevicePolicy(
    const std::string& policy_name,
    const std::string& json_string,
    base::WeakPtr<ExternalDataManager> external_data_manager,
    PolicyMap* policies) {
  SetJsonDevicePolicy(
      policy_name, json_string,
      std::make_unique<ExternalDataFetcher>(external_data_manager, policy_name),
      policies);
}

// Decodes a protobuf integer to an IntegerValue. Returns nullopt in case the
// input value is out of bounds.
std::optional<base::Value> DecodeIntegerValue(google::protobuf::int64 value) {
  if (value < std::numeric_limits<int>::min() ||
      value > std::numeric_limits<int>::max()) {
    LOG(WARNING) << "Integer value " << value
                 << " out of numeric limits, ignoring.";
    return std::nullopt;
  }

  return base::Value(static_cast<int>(value));
}

std::optional<base::Value> DecodeConnectionType(int value) {
  static constexpr auto kConnectionTypes =
      base::MakeFixedFlatMap<int, std::string_view>({
          {em::AutoUpdateSettingsProto::CONNECTION_TYPE_ETHERNET,
           shill::kTypeEthernet},
          {em::AutoUpdateSettingsProto::CONNECTION_TYPE_WIFI, shill::kTypeWifi},
          {em::AutoUpdateSettingsProto::CONNECTION_TYPE_CELLULAR,
           shill::kTypeCellular},
      });
  const auto iter = kConnectionTypes.find(value);
  if (iter == kConnectionTypes.end()) {
    return std::nullopt;
  }
  return base::Value(iter->second);
}

void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy,
                         PolicyMap* policies) {
  if (policy.has_guest_mode_enabled()) {
    const em::GuestModeEnabledProto& container(policy.guest_mode_enabled());
    if (container.has_guest_mode_enabled()) {
      policies->Set(key::kDeviceGuestModeEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.guest_mode_enabled()), nullptr);
    }
  }

  if (policy.has_device_chrome_variations_type()) {
    const em::IntegerPolicyProto& container(
        policy.device_chrome_variations_type());
    if (container.has_value()) {
      if (auto value = DecodeIntegerValue(container.value())) {
        policies->Set(key::kDeviceChromeVariations, POLICY_LEVEL_MANDATORY,
                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                      std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_login_screen_primary_mouse_button_switch()) {
    const em::BooleanPolicyProto& container(
        policy.login_screen_primary_mouse_button_switch());
    if (container.has_value()) {
      auto policy_level = GetPolicyLevel(container.has_policy_options(),
                                         container.policy_options());
      if (policy_level) {
        policies->Set(key::kDeviceLoginScreenPrimaryMouseButtonSwitch,
                      policy_level.value(), POLICY_SCOPE_MACHINE,
                      POLICY_SOURCE_CLOUD, base::Value(container.value()),
                      nullptr);
      }
    }
  }

  if (policy.has_reboot_on_shutdown()) {
    const em::RebootOnShutdownProto& container(policy.reboot_on_shutdown());
    if (container.has_reboot_on_shutdown()) {
      policies->Set(key::kDeviceRebootOnShutdown, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.reboot_on_shutdown()), nullptr);
    }
  }

  if (policy.has_show_user_names()) {
    const em::ShowUserNamesOnSigninProto& container(policy.show_user_names());
    if (container.has_show_user_names()) {
      policies->Set(key::kDeviceShowUserNamesOnSignin, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.show_user_names()), nullptr);
    }
  }

  if (policy.has_allow_new_users()) {
    const em::AllowNewUsersProto& container(policy.allow_new_users());
    if (container.has_allow_new_users()) {
      policies->Set(key::kDeviceAllowNewUsers, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.allow_new_users()), nullptr);
    }
  }

  if (policy.has_user_allowlist()) {
    const em::UserAllowlistProto& container(policy.user_allowlist());
    base::Value::List allowlist;
    for (const auto& entry : container.user_allowlist()) {
      allowlist.Append(entry);
    }
    policies->Set(key::kDeviceUserAllowlist, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(allowlist)), nullptr);
  }

  if (policy.has_family_link_accounts_allowed()) {
    const em::DeviceFamilyLinkAccountsAllowedProto& container(
        policy.family_link_accounts_allowed());
    if (container.has_family_link_accounts_allowed()) {
      policies->Set(
          key::kDeviceFamilyLinkAccountsAllowed, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.family_link_accounts_allowed()), nullptr);
    }
  }

  if (policy.has_ephemeral_users_enabled()) {
    const em::EphemeralUsersEnabledProto& container(
        policy.ephemeral_users_enabled());
    if (container.has_ephemeral_users_enabled()) {
      policies->Set(key::kDeviceEphemeralUsersEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.ephemeral_users_enabled()), nullptr);
    }
  }

  if (policy.has_saml_settings()) {
    const em::SAMLSettingsProto& container(policy.saml_settings());
    if (container.has_transfer_saml_cookies()) {
      policies->Set(key::kDeviceTransferSAMLCookies, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.transfer_saml_cookies()), nullptr);
    }
  }

  if (policy.has_saml_username()) {
    const em::SAMLUsernameProto& container(policy.saml_username());
    if (container.has_url_parameter_to_autofill_saml_username()) {
      policies->Set(
          key::kDeviceAutofillSAMLUsername, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.url_parameter_to_autofill_saml_username()),
          nullptr);
    }
  }

  if (policy.has_login_authentication_behavior()) {
    const em::LoginAuthenticationBehaviorProto& container(
        policy.login_authentication_behavior());
    if (container.has_login_authentication_behavior()) {
      if (auto value =
              DecodeIntegerValue(container.login_authentication_behavior())) {
        policies->Set(key::kLoginAuthenticationBehavior, POLICY_LEVEL_MANDATORY,
                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                      std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_allow_bluetooth()) {
    const em::AllowBluetoothProto& container(policy.allow_bluetooth());
    if (container.has_allow_bluetooth()) {
      policies->Set(key::kDeviceAllowBluetooth, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.allow_bluetooth()), nullptr);
    }
  }

  if (policy.has_login_video_capture_allowed_urls()) {
    const em::LoginVideoCaptureAllowedUrlsProto& container(
        policy.login_video_capture_allowed_urls());
    base::Value::List urls;
    for (const auto& entry : container.urls()) {
      urls.Append(entry);
    }
    policies->Set(key::kLoginVideoCaptureAllowedUrls, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(urls)), nullptr);
  }

  if (policy.has_device_login_screen_extensions()) {
    const em::DeviceLoginScreenExtensionsProto& proto(
        policy.device_login_screen_extensions());
    base::Value::List apps;
    for (const auto& app : proto.device_login_screen_extensions()) {
      apps.Append(app);
    }
    policies->Set(key::kDeviceLoginScreenExtensions, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(apps)), nullptr);
  }

  if (policy.has_login_screen_extension_manifest_v2_availability()) {
    const em::LoginScreenExtensionManifestV2AvailabilityProto& proto(
        policy.login_screen_extension_manifest_v2_availability());
    policies->Set(
        key::kDeviceLoginScreenExtensionManifestV2Availability,
        POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
        base::Value(proto.login_screen_extension_manifest_v2_availability()),
        nullptr);
  }

  if (policy.has_login_screen_power_management()) {
    const em::LoginScreenPowerManagementProto& container(
        policy.login_screen_power_management());
    if (container.has_login_screen_power_management()) {
      SetJsonDevicePolicy(key::kDeviceLoginScreenPowerManagement,
                          container.login_screen_power_management(), policies);
    }
  }

  if (policy.has_login_screen_domain_auto_complete()) {
    const em::LoginScreenDomainAutoCompleteProto& container(
        policy.login_screen_domain_auto_complete());
    SetPolicyWithValidatingRegex(key::kDeviceLoginScreenDomainAutoComplete,
                                 container.login_screen_domain_auto_complete(),
                                 hostNameRegex, policies);
  }

  if (policy.has_login_screen_locales()) {
    base::Value::List locales;
    const em::LoginScreenLocalesProto& login_screen_locales(
        policy.login_screen_locales());
    for (const auto& locale : login_screen_locales.login_screen_locales()) {
      locales.Append(locale);
    }
    policies->Set(key::kDeviceLoginScreenLocales, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(locales)), nullptr);
  }

  if (policy.has_login_screen_input_methods()) {
    base::Value::List input_methods;
    const em::LoginScreenInputMethodsProto& login_screen_input_methods(
        policy.login_screen_input_methods());
    for (const auto& input_method :
         login_screen_input_methods.login_screen_input_methods()) {
      input_methods.Append(input_method);
    }
    policies->Set(key::kDeviceLoginScreenInputMethods, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(input_methods)), nullptr);
  }

  if (policy.has_device_login_screen_auto_select_certificate_for_urls()) {
    base::Value::List rules;
    const em::DeviceLoginScreenAutoSelectCertificateForUrls& proto_rules(
        policy.device_login_screen_auto_select_certificate_for_urls());
    for (const auto& rule :
         proto_rules.login_screen_auto_select_certificate_rules()) {
      rules.Append(rule);
    }
    policies->Set(key::kDeviceLoginScreenAutoSelectCertificateForUrls,
                  POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD, base::Value(std::move(rules)), nullptr);
  }

  if (policy.has_device_login_screen_webhid_allow_devices_for_urls()) {
    const em::StringPolicyProto& container(
        policy.device_login_screen_webhid_allow_devices_for_urls());
    if (container.has_value()) {
      SetJsonDevicePolicy(key::kDeviceLoginScreenWebHidAllowDevicesForUrls,
                          container.value(), policies);
    }
  }

  if (policy.has_device_login_screen_webusb_allow_devices_for_urls()) {
    const em::DeviceLoginScreenWebUsbAllowDevicesForUrlsProto& container(
        policy.device_login_screen_webusb_allow_devices_for_urls());
    if (container.has_device_login_screen_webusb_allow_devices_for_urls()) {
      SetJsonDevicePolicy(
          key::kDeviceLoginScreenWebUsbAllowDevicesForUrls,
          container.device_login_screen_webusb_allow_devices_for_urls(),
          policies);
    }
  }

  if (policy.has_device_login_screen_system_info_enforced()) {
    const em::BooleanPolicyProto& container(
        policy.device_login_screen_system_info_enforced());
    if (container.has_value()) {
      auto policy_level = GetPolicyLevel(container.has_policy_options(),
                                         container.policy_options());
      if (policy_level) {
        policies->Set(key::kDeviceLoginScreenSystemInfoEnforced,
                      policy_level.value(), POLICY_SCOPE_MACHINE,
                      POLICY_SOURCE_CLOUD, base::Value(container.value()),
                      nullptr);
      }
    }
  }

  if (policy.has_device_show_numeric_keyboard_for_password()) {
    const em::BooleanPolicyProto& container(
        policy.device_show_numeric_keyboard_for_password());
    if (container.has_value()) {
      auto policy_level = GetPolicyLevel(container.has_policy_options(),
                                         container.policy_options());
      if (policy_level) {
        policies->Set(key::kDeviceShowNumericKeyboardForPassword,
                      policy_level.value(), POLICY_SCOPE_MACHINE,
                      POLICY_SOURCE_CLOUD, base::Value(container.value()),
                      nullptr);
      }
    }
  }

  if (policy.has_device_reboot_on_user_signout()) {
    const em::DeviceRebootOnUserSignoutProto& container(
        policy.device_reboot_on_user_signout());
    if (container.has_reboot_on_signout_mode()) {
      policies->Set(key::kDeviceRebootOnUserSignout, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.reboot_on_signout_mode()), nullptr);
    }
  }

  if (policy.has_device_powerwash_allowed()) {
    const em::DevicePowerwashAllowedProto& container(
        policy.device_powerwash_allowed());
    if (container.has_device_powerwash_allowed()) {
      policies->Set(key::kDevicePowerwashAllowed, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.device_powerwash_allowed()), nullptr);
    }
  }

  if (policy.has_device_web_based_attestation_allowed_urls()) {
    const em::StringListPolicyProto& container(
        policy.device_web_based_attestation_allowed_urls());

    auto policy_level = GetPolicyLevel(container.has_policy_options(),
                                       container.policy_options());
    if (policy_level) {
      base::Value::List urls;

      if (container.has_value()) {
        for (const std::string& entry : container.value().entries()) {
          urls.Append(entry);
        }
      }

      policies->Set(key::kDeviceWebBasedAttestationAllowedUrls,
                    policy_level.value(), POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(std::move(urls)), nullptr);
    }
  }

  if (policy.has_device_login_screen_context_aware_access_signals_allowlist()) {
    const em::StringListPolicyProto& container(
        policy.device_login_screen_context_aware_access_signals_allowlist());
    base::Value::List allowlist;
    if (container.has_value()) {
      for (const std::string& entry : container.value().entries()) {
        allowlist.Append(entry);
      }
    }

    policies->Set(key::kDeviceLoginScreenContextAwareAccessSignalsAllowlist,
                  POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD, base::Value(std::move(allowlist)),
                  nullptr);
  }

  if (policy.has_required_client_certificate_for_device()) {
    const em::RequiredClientCertificateForDeviceProto& container(
        policy.required_client_certificate_for_device());
    if (container.has_required_client_certificate_for_device()) {
      SetJsonDevicePolicy(key::kRequiredClientCertificateForDevice,
                          container.required_client_certificate_for_device(),
                          policies);
    }
  }

  if (policy.has_managed_guest_session_privacy_warnings()) {
    const em::ManagedGuestSessionPrivacyWarningsProto& container(
        policy.managed_guest_session_privacy_warnings());
    if (container.has_enabled()) {
      policies->Set(key::kManagedGuestSessionPrivacyWarningsEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_login_screen_prompt_on_multiple_matching_certificates()) {
    const em::BooleanPolicyProto& container(
        policy.login_screen_prompt_on_multiple_matching_certificates());
    if (container.has_value()) {
      policies->Set(key::kDeviceLoginScreenPromptOnMultipleMatchingCertificates,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_kiosk_crx_manifest_update_url_ignored()) {
    const em::BooleanPolicyProto& container(
        policy.kiosk_crx_manifest_update_url_ignored());
    if (container.has_value()) {
      policies->Set(key::kKioskCRXManifestUpdateURLIgnored,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_device_screensaver_login_screen_enabled()) {
    const em::DeviceScreensaverLoginScreenEnabledProto& container(
        policy.device_screensaver_login_screen_enabled());
    if (container.has_device_screensaver_login_screen_enabled()) {
      policies->Set(
          key::kDeviceScreensaverLoginScreenEnabled, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.device_screensaver_login_screen_enabled()),
          nullptr);
    }
  }

  if (policy.has_device_screensaver_login_screen_idle_timeout_seconds()) {
    const em::DeviceScreensaverLoginScreenIdleTimeoutSecondsProto& container(
        policy.device_screensaver_login_screen_idle_timeout_seconds());
    if (container.has_device_screensaver_login_screen_idle_timeout_seconds()) {
      if (auto value = DecodeIntegerValue(
              container
                  .device_screensaver_login_screen_idle_timeout_seconds())) {
        policies->Set(key::kDeviceScreensaverLoginScreenIdleTimeoutSeconds,
                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                      POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
      }
    }
  }

  if (policy
          .has_device_screensaver_login_screen_image_display_interval_seconds()) {
    const em::DeviceScreensaverLoginScreenImageDisplayIntervalSecondsProto&
        container(
            policy
                .device_screensaver_login_screen_image_display_interval_seconds());
    if (container
            .has_device_screensaver_login_screen_image_display_interval_seconds()) {
      if (auto value = DecodeIntegerValue(
              container
                  .device_screensaver_login_screen_image_display_interval_seconds())) {
        policies->Set(
            key::kDeviceScreensaverLoginScreenImageDisplayIntervalSeconds,
            POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_device_screensaver_login_screen_images()) {
    const em::DeviceScreensaverLoginScreenImagesProto& container(
        policy.device_screensaver_login_screen_images());
    base::Value::List image_urls;
    for (const auto& entry :
         container.device_screensaver_login_screen_images()) {
      image_urls.Append(entry);
    }
    policies->Set(key::kDeviceScreensaverLoginScreenImages,
                  POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD, base::Value(std::move(image_urls)),
                  nullptr);
  }

  if (policy.has_device_authentication_url_blocklist()) {
    const em::StringListPolicyProto& container(
        policy.device_authentication_url_blocklist());

    base::Value::List blocklist;
    if (container.has_value()) {
      for (const auto& entry : container.value().entries()) {
        blocklist.Append(entry);
      }
    }

    policies->Set(key::kDeviceAuthenticationURLBlocklist,
                  POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD, base::Value(std::move(blocklist)),
                  nullptr);
  }

  if (policy.has_device_authentication_url_allowlist()) {
    const em::StringListPolicyProto& container(
        policy.device_authentication_url_allowlist());

    base::Value::List allowlist;
    if (container.has_value()) {
      for (const auto& entry : container.value().entries()) {
        allowlist.Append(entry);
      }
    }

    policies->Set(key::kDeviceAuthenticationURLAllowlist,
                  POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD, base::Value(std::move(allowlist)),
                  nullptr);
  }

  if (policy.has_deviceauthenticationflowautoreloadinterval()) {
    const em::IntegerPolicyProto& container(
        policy.deviceauthenticationflowautoreloadinterval());
    if (container.has_value()) {
      if (auto value = DecodeIntegerValue(container.value())) {
        policies->Set(key::kDeviceAuthenticationFlowAutoReloadInterval,
                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                      POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
      }
    }
  }
}

base::Value::Dict DecodeDeviceLocalAccountInfoProto(
    const em::DeviceLocalAccountInfoProto& entry) {
  if (!entry.has_type()) {
    if (entry.has_deprecated_public_session_id()) {
      // Deprecated public session specification.
      return base::Value::Dict()
          .Set(ash::kAccountsPrefDeviceLocalAccountsKeyId,
               entry.deprecated_public_session_id())
          .Set(ash::kAccountsPrefDeviceLocalAccountsKeyType,
               static_cast<int>(DeviceLocalAccountType::kPublicSession));
    } else {
      return base::Value::Dict();
    }
  }

  base::Value::Dict entry_dict;
  if (entry.has_account_id()) {
    entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyId,
                   entry.account_id());
  }
  entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyType,
                 static_cast<int>(entry.type()));
  if (entry.kiosk_app().has_app_id()) {
    entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyKioskAppId,
                   entry.kiosk_app().app_id());
  }
  if (entry.kiosk_app().has_update_url()) {
    entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyKioskAppUpdateURL,
                   entry.kiosk_app().update_url());
  }
  if (entry.web_kiosk_app().has_url()) {
    entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyWebKioskUrl,
                   entry.web_kiosk_app().url());
  }
  if (entry.web_kiosk_app().has_title()) {
    entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyWebKioskTitle,
                   entry.web_kiosk_app().title());
  }
  if (entry.web_kiosk_app().has_icon_url()) {
    entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyWebKioskIconUrl,
                   entry.web_kiosk_app().icon_url());
  }
  if (entry.has_ephemeral_mode()) {
    entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyEphemeralMode,
                   static_cast<int>(entry.ephemeral_mode()));
  } else {
    entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyEphemeralMode,
                   static_cast<int>(
                       em::DeviceLocalAccountInfoProto::EPHEMERAL_MODE_UNSET));
  }
  if (entry.has_isolated_kiosk_app()) {
    if (entry.isolated_kiosk_app().has_web_bundle_id()) {
      entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyIwaKioskBundleId,
                     entry.isolated_kiosk_app().web_bundle_id());
    }
    if (entry.isolated_kiosk_app().has_update_manifest_url()) {
      entry_dict.Set(ash::kAccountsPrefDeviceLocalAccountsKeyIwaKioskUpdateUrl,
                     entry.isolated_kiosk_app().update_manifest_url());
    }
  }
  return entry_dict;
}

void DecodeDeviceLocalAccountsPolicy(
    const em::ChromeDeviceSettingsProto& policy,
    PolicyMap* policies) {
  if (!policy.has_device_local_accounts()) {
    return;
  }
  const em::DeviceLocalAccountsProto& container(policy.device_local_accounts());
  const RepeatedPtrField<em::DeviceLocalAccountInfoProto>& accounts =
      container.account();
  base::Value::List account_list;
  for (const auto& entry : accounts) {
    account_list.Append(DecodeDeviceLocalAccountInfoProto(entry));
  }

  policies->Set(key::kDeviceLocalAccounts, POLICY_LEVEL_MANDATORY,
                POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                base::Value(std::move(account_list)), nullptr);
  if (container.has_auto_login_id()) {
    policies->Set(key::kDeviceLocalAccountAutoLoginId, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(container.auto_login_id()), nullptr);
  }
  if (container.has_auto_login_delay()) {
    if (auto value = DecodeIntegerValue(container.auto_login_delay())) {
      policies->Set(key::kDeviceLocalAccountAutoLoginDelay,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
    }
  }
  if (container.has_enable_auto_login_bailout()) {
    policies->Set(key::kDeviceLocalAccountAutoLoginBailoutEnabled,
                  POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD,
                  base::Value(container.enable_auto_login_bailout()), nullptr);
  }
  if (container.has_prompt_for_network_when_offline()) {
    policies->Set(
        key::kDeviceLocalAccountPromptForNetworkWhenOffline,
        POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
        base::Value(container.prompt_for_network_when_offline()), nullptr);
  }
}

void DecodeNetworkPolicies(const em::ChromeDeviceSettingsProto& policy,
                           PolicyMap* policies) {
  if (policy.has_data_roaming_enabled()) {
    const em::DataRoamingEnabledProto& container(policy.data_roaming_enabled());
    if (container.has_data_roaming_enabled()) {
      policies->Set(key::kDeviceDataRoamingEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.data_roaming_enabled()), nullptr);
    }
  }

  if (policy.has_device_wifi_fast_transition_enabled()) {
    const em::DeviceWiFiFastTransitionEnabledProto& container(
        policy.device_wifi_fast_transition_enabled());
    if (container.has_device_wifi_fast_transition_enabled()) {
      policies->Set(
          key::kDeviceWiFiFastTransitionEnabled, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.device_wifi_fast_transition_enabled()),
          nullptr);
    }
  }

  if (policy.has_network_throttling()) {
    const em::NetworkThrottlingEnabledProto& container(
        policy.network_throttling());
    bool enabled = (container.has_enabled()) ? container.enabled() : false;
    uint32_t upload_rate_kbits =
        (container.has_upload_rate_kbits()) ? container.upload_rate_kbits() : 0;
    uint32_t download_rate_kbits = (container.has_download_rate_kbits())
                                       ? container.download_rate_kbits()
                                       : 0;

    auto throttling_status =
        base::Value::Dict()
            .Set("enabled", enabled)
            .Set("upload_rate_kbits", static_cast<int>(upload_rate_kbits))
            .Set("download_rate_kbits", static_cast<int>(download_rate_kbits));
    policies->Set(key::kNetworkThrottlingEnabled, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(throttling_status)), nullptr);
  }

  if (policy.has_open_network_configuration() &&
      policy.open_network_configuration().has_open_network_configuration()) {
    std::string config(
        policy.open_network_configuration().open_network_configuration());
    policies->Set(key::kDeviceOpenNetworkConfiguration, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(config), nullptr);
  }

  if (policy.has_network_hostname() &&
      policy.network_hostname().has_device_hostname_template()) {
    std::string hostname(policy.network_hostname().device_hostname_template());
    policies->Set(key::kDeviceHostnameTemplate, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(hostname), nullptr);
  }

  if (policy.has_system_proxy_settings()) {
    const em::SystemProxySettingsProto& settings_proto(
        policy.system_proxy_settings());
    if (settings_proto.has_system_proxy_settings()) {
      SetJsonDevicePolicy(key::kSystemProxySettings,
                          settings_proto.system_proxy_settings(), policies);
    }
  }

  if (policy.has_device_debug_packet_capture_allowed() &&
      policy.device_debug_packet_capture_allowed().has_allowed()) {
    policies->Set(
        key::kDeviceDebugPacketCaptureAllowed, POLICY_LEVEL_MANDATORY,
        POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
        base::Value(policy.device_debug_packet_capture_allowed().allowed()),
        nullptr);
  }

  if (policy.has_device_ephemeral_network_policies_enabled()) {
    const em::BooleanPolicyProto& container(
        policy.device_ephemeral_network_policies_enabled());
    if (container.has_value()) {
      policies->Set(key::kDeviceEphemeralNetworkPoliciesEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    /*external_data_fetcher=*/nullptr);
    }
  }

  if (policy.has_devicepostquantumkeyagreementenabled()) {
    const em::BooleanPolicyProto& container(
        policy.devicepostquantumkeyagreementenabled());
    if (container.has_value()) {
      policies->Set(key::kDevicePostQuantumKeyAgreementEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }
}

void DecodeIntegerReportingPolicy(PolicyMap* policies,
                                  const std::string& policy_path,
                                  google::protobuf::int64 int_value) {
  if (auto value = DecodeIntegerValue(int_value)) {
    policies->Set(policy_path, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
  }
}

void DecodeReportingPolicies(const em::ChromeDeviceSettingsProto& policy,
                             PolicyMap* policies) {
  if (policy.has_device_reporting()) {
    const em::DeviceReportingProto& container(policy.device_reporting());
    if (container.has_report_version_info()) {
      policies->Set(key::kReportDeviceVersionInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_version_info()), nullptr);
    }
    if (container.has_report_activity_times()) {
      policies->Set(key::kReportDeviceActivityTimes, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_activity_times()), nullptr);
    }
    if (container.has_report_audio_status()) {
      policies->Set(key::kReportDeviceAudioStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_audio_status()), nullptr);
    }
    if (container.has_report_boot_mode()) {
      policies->Set(key::kReportDeviceBootMode, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_boot_mode()), nullptr);
    }
    if (container.has_report_network_configuration()) {
      policies->Set(
          key::kReportDeviceNetworkConfiguration, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.report_network_configuration()), nullptr);
    }
    if (container.has_report_network_status()) {
      policies->Set(key::kReportDeviceNetworkStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_network_status()), nullptr);
    }
    if (container.has_report_users()) {
      policies->Set(key::kReportDeviceUsers, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_users()), nullptr);
    }
    if (container.has_report_session_status()) {
      policies->Set(key::kReportDeviceSessionStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_session_status()), nullptr);
    }
    if (container.has_report_runtime_counters()) {
      policies->Set(key::kDeviceReportRuntimeCounters, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_runtime_counters()), nullptr);
    }
    if (container.has_report_os_update_status()) {
      policies->Set(key::kReportDeviceOsUpdateStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_os_update_status()), nullptr);
    }
    if (container.has_report_graphics_status()) {
      policies->Set(key::kReportDeviceGraphicsStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_graphics_status()), nullptr);
    }
    if (container.has_report_crash_report_info()) {
      policies->Set(key::kReportDeviceCrashReportInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_crash_report_info()), nullptr);
    }
    if (container.has_report_peripherals()) {
      policies->Set(key::kReportDevicePeripherals, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_peripherals()), nullptr);
    }
    if (container.has_report_power_status()) {
      policies->Set(key::kReportDevicePowerStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_power_status()), nullptr);
    }
    if (container.has_report_storage_status()) {
      policies->Set(key::kReportDeviceStorageStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_storage_status()), nullptr);
    }
    if (container.has_report_board_status()) {
      policies->Set(key::kReportDeviceBoardStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_board_status()), nullptr);
    }
    if (container.has_device_status_frequency()) {
      DecodeIntegerReportingPolicy(policies, key::kReportUploadFrequency,
                                   container.device_status_frequency());
    }
    if (container.has_report_cpu_info()) {
      policies->Set(key::kReportDeviceCpuInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_cpu_info()), nullptr);
    }
    if (container.has_report_timezone_info()) {
      policies->Set(key::kReportDeviceTimezoneInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_timezone_info()), nullptr);
    }
    if (container.has_report_memory_info()) {
      policies->Set(key::kReportDeviceMemoryInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_memory_info()), nullptr);
    }
    if (container.has_report_backlight_info()) {
      policies->Set(key::kReportDeviceBacklightInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_backlight_info()), nullptr);
    }
    if (container.has_report_app_info()) {
      policies->Set(key::kReportDeviceAppInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_app_info()), nullptr);
    }
    if (container.has_report_bluetooth_info()) {
      policies->Set(key::kReportDeviceBluetoothInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_bluetooth_info()), nullptr);
    }
    if (container.has_report_fan_info()) {
      policies->Set(key::kReportDeviceFanInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_fan_info()), nullptr);
    }
    if (container.has_report_vpd_info()) {
      policies->Set(key::kReportDeviceVpdInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_vpd_info()), nullptr);
    }
    if (container.has_report_system_info()) {
      policies->Set(key::kReportDeviceSystemInfo, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_system_info()), nullptr);
    }
    if (container.has_report_security_status()) {
      policies->Set(key::kReportDeviceSecurityStatus, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_security_status()), nullptr);
    }
    if (container.has_report_print_jobs()) {
      policies->Set(key::kReportDevicePrintJobs, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_print_jobs()), nullptr);
    }
    if (container.has_report_login_logout()) {
      policies->Set(key::kReportDeviceLoginLogout, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_login_logout()), nullptr);
    }
    if (container.has_report_crd_sessions()) {
      policies->Set(key::kReportCRDSessions, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_crd_sessions()), nullptr);
    }
    if (container.has_report_network_telemetry_collection_rate_ms()) {
      DecodeIntegerReportingPolicy(
          policies, key::kReportDeviceNetworkTelemetryCollectionRateMs,
          container.report_network_telemetry_collection_rate_ms());
    }
    if (container.has_report_network_telemetry_event_checking_rate_ms()) {
      DecodeIntegerReportingPolicy(
          policies, key::kReportDeviceNetworkTelemetryEventCheckingRateMs,
          container.report_network_telemetry_event_checking_rate_ms());
    }
    if (container.has_report_device_audio_status_checking_rate_ms()) {
      DecodeIntegerReportingPolicy(
          policies, key::kReportDeviceAudioStatusCheckingRateMs,
          container.report_device_audio_status_checking_rate_ms());
    }
    if (container.has_device_report_runtime_counters_checking_rate_ms()) {
      DecodeIntegerReportingPolicy(
          policies, key::kDeviceReportRuntimeCountersCheckingRateMs,
          container.device_report_runtime_counters_checking_rate_ms());
    }
    if (container.has_report_signal_strength_event_driven_telemetry()) {
      base::Value::List signal_strength_telemetry_list;
      for (const std::string& telemetry_entry :
           container.report_signal_strength_event_driven_telemetry()
               .entries()) {
        signal_strength_telemetry_list.Append(telemetry_entry);
      }
      policies->Set(
          key::kReportDeviceSignalStrengthEventDrivenTelemetry,
          POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(std::move(signal_strength_telemetry_list)), nullptr);
    }
    if (container.has_device_activity_heartbeat_enabled()) {
      policies->Set(
          key::kDeviceActivityHeartbeatEnabled, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.device_activity_heartbeat_enabled()), nullptr);
    }
    if (container.has_device_activity_heartbeat_collection_rate_ms()) {
      DecodeIntegerReportingPolicy(
          policies, key::kDeviceActivityHeartbeatCollectionRateMs,
          container.device_activity_heartbeat_collection_rate_ms());
    }
    if (container.has_report_network_events()) {
      policies->Set(key::kDeviceReportNetworkEvents, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.report_network_events()), nullptr);
    }
  }

  if (policy.has_device_heartbeat_settings()) {
    const em::DeviceHeartbeatSettingsProto& container(
        policy.device_heartbeat_settings());
    if (container.has_heartbeat_enabled()) {
      policies->Set(key::kHeartbeatEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.heartbeat_enabled()), nullptr);
    }
    if (container.has_heartbeat_frequency()) {
      DecodeIntegerReportingPolicy(policies, key::kHeartbeatFrequency,
                                   container.heartbeat_frequency());
    }
  }

  if (policy.has_device_log_upload_settings()) {
    const em::DeviceLogUploadSettingsProto& container(
        policy.device_log_upload_settings());
    if (container.has_system_log_upload_enabled()) {
      policies->Set(key::kLogUploadEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.system_log_upload_enabled()),
                    nullptr);
    }
  }
}

void DecodeAutoUpdatePolicies(const em::ChromeDeviceSettingsProto& policy,
                              PolicyMap* policies) {
  if (policy.has_release_channel()) {
    const em::ReleaseChannelProto& container(policy.release_channel());
    if (container.has_release_channel()) {
      std::string channel(container.release_channel());
      policies->Set(key::kChromeOsReleaseChannel, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(channel), nullptr);
    }
    if (container.has_release_channel_delegated()) {
      policies->Set(
          key::kChromeOsReleaseChannelDelegated, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.release_channel_delegated()), nullptr);
    }
    if (container.has_release_lts_tag()) {
      policies->Set(key::kDeviceReleaseLtsTag, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.release_lts_tag()), nullptr);
    }
  }

  if (policy.has_auto_update_settings()) {
    const em::AutoUpdateSettingsProto& container(policy.auto_update_settings());
    if (container.has_update_disabled()) {
      policies->Set(key::kDeviceAutoUpdateDisabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.update_disabled()), nullptr);
    }

    if (container.has_target_version_prefix()) {
      policies->Set(key::kDeviceTargetVersionPrefix, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.target_version_prefix()), nullptr);
    }

    // target_version_display_name is not actually a policy, but a display
    // string for target_version_prefix, so we ignore it.

    if (container.has_rollback_to_target_version()) {
      policies->Set(key::kDeviceRollbackToTargetVersion, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.rollback_to_target_version()),
                    nullptr);
    }

    if (container.has_rollback_allowed_milestones()) {
      policies->Set(
          key::kDeviceRollbackAllowedMilestones, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.rollback_allowed_milestones()), nullptr);
    }

    if (container.has_scatter_factor_in_seconds()) {
      if (auto value =
              DecodeIntegerValue(container.scatter_factor_in_seconds())) {
        policies->Set(key::kDeviceUpdateScatterFactor, POLICY_LEVEL_MANDATORY,
                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                      std::move(*value), nullptr);
      }
    }

    if (container.allowed_connection_types_size()) {
      base::Value::List allowed_connection_types;
      for (const auto& entry : container.allowed_connection_types()) {
        if (auto value = DecodeConnectionType(entry)) {
          allowed_connection_types.Append(std::move(*value));
        }
      }
      policies->Set(key::kDeviceUpdateAllowedConnectionTypes,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD,
                    base::Value(std::move(allowed_connection_types)), nullptr);
    }

    if (container.has_http_downloads_enabled()) {
      policies->Set(key::kDeviceUpdateHttpDownloadsEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD,
                    base::Value(container.http_downloads_enabled()), nullptr);
    }

    if (container.has_reboot_after_update()) {
      policies->Set(key::kRebootAfterUpdate, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.reboot_after_update()), nullptr);
    }

    if (container.has_p2p_enabled()) {
      policies->Set(key::kDeviceAutoUpdateP2PEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.p2p_enabled()), nullptr);
    }

    if (container.has_disallowed_time_intervals()) {
      SetJsonDevicePolicy(key::kDeviceAutoUpdateTimeRestrictions,
                          container.disallowed_time_intervals(), policies);
    }

    if (container.has_staging_schedule()) {
      SetJsonDevicePolicy(key::kDeviceUpdateStagingSchedule,
                          container.staging_schedule(), policies);
    }

    if (container.has_device_quick_fix_build_token()) {
      policies->Set(key::kDeviceQuickFixBuildToken, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.device_quick_fix_build_token()),
                    nullptr);
    }

    if (container.has_channel_downgrade_behavior()) {
      policies->Set(
          key::kDeviceChannelDowngradeBehavior, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.channel_downgrade_behavior()), nullptr);
    }
  }

  if (policy.has_allow_kiosk_app_control_chrome_version()) {
    const em::AllowKioskAppControlChromeVersionProto& container(
        policy.allow_kiosk_app_control_chrome_version());
    if (container.has_allow_kiosk_app_control_chrome_version()) {
      policies->Set(
          key::kAllowKioskAppControlChromeVersion, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.allow_kiosk_app_control_chrome_version()),
          nullptr);
    }
  }

  if (policy.has_device_scheduled_update_check()) {
    const em::DeviceScheduledUpdateCheckProto& container(
        policy.device_scheduled_update_check());
    if (container.has_device_scheduled_update_check_settings()) {
      SetJsonDevicePolicy(key::kDeviceScheduledUpdateCheck,
                          container.device_scheduled_update_check_settings(),
                          policies);
    }
  }

  if (policy.has_deviceextendedautoupdateenabled()) {
    const em::BooleanPolicyProto& container(
        policy.deviceextendedautoupdateenabled());
    if (container.has_value()) {
      policies->Set(key::kDeviceExtendedAutoUpdateEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }
}

void DecodeAccessibilityPolicies(const em::ChromeDeviceSettingsProto& policy,
                                 PolicyMap* policies) {
  if (policy.has_accessibility_settings()) {
    const em::AccessibilitySettingsProto& container(
        policy.accessibility_settings());

    if (container.has_login_screen_default_large_cursor_enabled()) {
      policies->Set(
          key::kDeviceLoginScreenDefaultLargeCursorEnabled,
          POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.login_screen_default_large_cursor_enabled()),
          nullptr);
    }

    if (container.has_login_screen_large_cursor_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_large_cursor_enabled_options(),
          container.login_screen_large_cursor_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenLargeCursorEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_large_cursor_enabled()),
            nullptr);
      }
    }

    if (container.has_login_screen_show_options_in_system_tray_menu_enabled()) {
      auto policy_level = GetPolicyLevel(
          container
              .has_login_screen_show_options_in_system_tray_menu_enabled_options(),
          container
              .login_screen_show_options_in_system_tray_menu_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenShowOptionsInSystemTrayMenu,
            policy_level.value(), POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(
                container
                    .login_screen_show_options_in_system_tray_menu_enabled()),
            nullptr);
      }
    }

    if (container.has_login_screen_default_spoken_feedback_enabled()) {
      policies->Set(
          key::kDeviceLoginScreenDefaultSpokenFeedbackEnabled,
          POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.login_screen_default_spoken_feedback_enabled()),
          nullptr);
    }

    if (container.has_login_screen_spoken_feedback_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_spoken_feedback_enabled_options(),
          container.login_screen_spoken_feedback_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenSpokenFeedbackEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_spoken_feedback_enabled()),
            nullptr);
      }
    }

    if (container.has_login_screen_default_high_contrast_enabled()) {
      policies->Set(
          key::kDeviceLoginScreenDefaultHighContrastEnabled,
          POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.login_screen_default_high_contrast_enabled()),
          nullptr);
    }

    if (container.has_login_screen_high_contrast_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_high_contrast_enabled_options(),
          container.login_screen_high_contrast_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenHighContrastEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_high_contrast_enabled()),
            nullptr);
      }
    }

    if (container.has_login_screen_shortcuts_enabled()) {
      auto policy_level =
          GetPolicyLevel(container.has_login_screen_shortcuts_enabled_options(),
                         container.login_screen_shortcuts_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenAccessibilityShortcutsEnabled,
            policy_level.value(), POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_shortcuts_enabled()), nullptr);
      }
    }

    if (container.has_login_screen_default_screen_magnifier_type()) {
      if (auto value = DecodeIntegerValue(
              container.login_screen_default_screen_magnifier_type())) {
        policies->Set(key::kDeviceLoginScreenDefaultScreenMagnifierType,
                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                      POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
      }
    }

    if (container.has_login_screen_default_virtual_keyboard_enabled()) {
      policies->Set(
          key::kDeviceLoginScreenDefaultVirtualKeyboardEnabled,
          POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(
              container.login_screen_default_virtual_keyboard_enabled()),
          nullptr);
    }

    if (container.has_login_screen_virtual_keyboard_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_virtual_keyboard_enabled_options(),
          container.login_screen_virtual_keyboard_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenVirtualKeyboardEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_virtual_keyboard_enabled()),
            nullptr);
      }
    }

    if (container.has_login_screen_dictation_enabled()) {
      auto policy_level =
          GetPolicyLevel(container.has_login_screen_dictation_enabled_options(),
                         container.login_screen_dictation_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenDictationEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_dictation_enabled()), nullptr);
      }
    }
    if (container.has_login_screen_select_to_speak_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_select_to_speak_enabled_options(),
          container.login_screen_select_to_speak_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenSelectToSpeakEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_select_to_speak_enabled()),
            nullptr);
      }
    }
    if (container.has_login_screen_cursor_highlight_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_cursor_highlight_enabled_options(),
          container.login_screen_cursor_highlight_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenCursorHighlightEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_cursor_highlight_enabled()),
            nullptr);
      }
    }
    if (container.has_login_screen_caret_highlight_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_caret_highlight_enabled_options(),
          container.login_screen_caret_highlight_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenCaretHighlightEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_caret_highlight_enabled()),
            nullptr);
      }
    }
    if (container.has_login_screen_mono_audio_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_mono_audio_enabled_options(),
          container.login_screen_mono_audio_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenMonoAudioEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_mono_audio_enabled()), nullptr);
      }
    }
    if (container.has_login_screen_autoclick_enabled()) {
      auto policy_level =
          GetPolicyLevel(container.has_login_screen_autoclick_enabled_options(),
                         container.login_screen_autoclick_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenAutoclickEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_autoclick_enabled()), nullptr);
      }
    }

    if (container.has_login_screen_sticky_keys_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_sticky_keys_enabled_options(),
          container.login_screen_sticky_keys_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenStickyKeysEnabled, policy_level.value(),
            POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(container.login_screen_sticky_keys_enabled()), nullptr);
      }
    }

    if (container.has_login_screen_screen_magnifier_type()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_screen_magnifier_type_options(),
          container.login_screen_screen_magnifier_type_options());
      if (policy_level) {
        if (auto value = DecodeIntegerValue(
                container.login_screen_screen_magnifier_type())) {
          policies->Set(key::kDeviceLoginScreenScreenMagnifierType,
                        policy_level.value(), POLICY_SCOPE_MACHINE,
                        POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
        }
      }
    }

    if (container.has_login_screen_keyboard_focus_highlight_enabled()) {
      auto policy_level = GetPolicyLevel(
          container.has_login_screen_keyboard_focus_highlight_enabled_options(),
          container.login_screen_keyboard_focus_highlight_enabled_options());
      if (policy_level) {
        policies->Set(
            key::kDeviceLoginScreenKeyboardFocusHighlightEnabled,
            policy_level.value(), POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
            base::Value(
                container.login_screen_keyboard_focus_highlight_enabled()),
            nullptr);
      }
    }
  }
}

void DecodeExternalDataPolicies(
    const em::ChromeDeviceSettingsProto& policy,
    base::WeakPtr<ExternalDataManager> external_data_manager,
    PolicyMap* policies) {
  if (policy.has_device_wallpaper_image()) {
    const em::DeviceWallpaperImageProto& container(
        policy.device_wallpaper_image());
    if (container.has_device_wallpaper_image()) {
      SetExternalDataDevicePolicy(key::kDeviceWallpaperImage,
                                  container.device_wallpaper_image(),
                                  external_data_manager, policies);
    }
  }

  if (policy.has_device_printers()) {
    const em::DevicePrintersProto& container(policy.device_printers());
    if (container.has_external_policy()) {
      SetExternalDataDevicePolicy(key::kDevicePrinters,
                                  container.external_policy(),
                                  external_data_manager, policies);
    }
  }

  if (policy.has_external_print_servers()) {
    const em::DeviceExternalPrintServersProto& container(
        policy.external_print_servers());
    if (container.has_external_policy()) {
      SetExternalDataDevicePolicy(key::kDeviceExternalPrintServers,
                                  container.external_policy(),
                                  external_data_manager, policies);
    }
  }
}

void DecodeGenericPolicies(const em::ChromeDeviceSettingsProto& policy,
                           PolicyMap* policies) {
  if (policy.has_device_policy_refresh_rate()) {
    const em::DevicePolicyRefreshRateProto& container(
        policy.device_policy_refresh_rate());
    if (container.has_device_policy_refresh_rate()) {
      if (auto value =
              DecodeIntegerValue(container.device_policy_refresh_rate())) {
        policies->Set(key::kDevicePolicyRefreshRate, POLICY_LEVEL_MANDATORY,
                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                      std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_device_system_aec_enabled()) {
    const em::DeviceSystemAecEnabledProto& container(
        policy.device_system_aec_enabled());
    if (container.has_device_system_aec_enabled()) {
      policies->Set(key::kDeviceSystemAecEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.device_system_aec_enabled()),
                    nullptr);
    }
  }

  if (policy.has_metrics_enabled()) {
    const em::MetricsEnabledProto& container(policy.metrics_enabled());
    if (container.has_metrics_enabled()) {
      policies->Set(key::kDeviceMetricsReportingEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.metrics_enabled()), nullptr);
    }
  }

  if (policy.has_device_login_screen_geolocation_access_level() &&
      policy.device_login_screen_geolocation_access_level()
          .has_geolocation_access_level()) {
    if (auto value = DecodeIntegerValue(
            policy.device_login_screen_geolocation_access_level()
                .geolocation_access_level())) {
      policies->Set(key::kDeviceLoginScreenGeolocationAccessLevel,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
    }
  } else {
    // Set policy default to kAllowed if the policy is unset.
    policies->Set(
        key::kDeviceLoginScreenGeolocationAccessLevel, POLICY_LEVEL_MANDATORY,
        POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT,
        base::Value(enterprise_management::
                        DeviceLoginScreenGeolocationAccessLevelProto::ALLOWED),
        nullptr);
  }

  if (policy.has_system_timezone()) {
    if (policy.system_timezone().has_timezone()) {
      policies->Set(key::kSystemTimezone, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(policy.system_timezone().timezone()), nullptr);
    }

    if (policy.system_timezone().has_timezone_detection_type()) {
      if (auto value = DecodeIntegerValue(
              policy.system_timezone().timezone_detection_type())) {
        policies->Set(key::kSystemTimezoneAutomaticDetection,
                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                      POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_use_24hour_clock()) {
    if (policy.use_24hour_clock().has_use_24hour_clock()) {
      policies->Set(key::kSystemUse24HourClock, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(policy.use_24hour_clock().use_24hour_clock()),
                    nullptr);
    }
  }

  if (policy.has_keyboard_backlight_color()) {
    const em::KeyboardBacklightColorProto& container(
        policy.keyboard_backlight_color());
    if (container.has_color()) {
      // This policy is interpreted as "Recommended".
      // See the comment at the definition of the
      // ash::prefs::kPersonalizationKeyboardBacklightColor pref (to which this
      // policy will be mapped) for more details.
      policies->Set(key::kDeviceKeyboardBacklightColor,
                    POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.color()),
                    nullptr);
    }
  }

  if (policy.has_device_hindi_inscript_layout_enabled()) {
    const em::DeviceHindiInscriptLayoutEnabledProto& container(
        policy.device_hindi_inscript_layout_enabled());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceHindiInscriptLayoutEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_allow_redeem_offers()) {
    const em::AllowRedeemChromeOsRegistrationOffersProto& container(
        policy.allow_redeem_offers());
    if (container.has_allow_redeem_offers()) {
      policies->Set(key::kDeviceAllowRedeemChromeOsRegistrationOffers,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD,
                    base::Value(container.allow_redeem_offers()), nullptr);
    }
  }

  if (policy.has_uptime_limit()) {
    const em::UptimeLimitProto& container(policy.uptime_limit());
    if (container.has_uptime_limit()) {
      if (auto value = DecodeIntegerValue(container.uptime_limit())) {
        policies->Set(key::kUptimeLimit, POLICY_LEVEL_MANDATORY,
                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                      std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_variations_parameter()) {
    if (policy.variations_parameter().has_parameter()) {
      policies->Set(
          key::kDeviceVariationsRestrictParameter, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(policy.variations_parameter().parameter()), nullptr);
    }
  }

  if (policy.has_attestation_settings()) {
    if (policy.attestation_settings().has_content_protection_enabled()) {
      policies->Set(
          key::kAttestationForContentProtectionEnabled, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(
              policy.attestation_settings().content_protection_enabled()),
          nullptr);
    }
  }

  if (policy.has_system_settings()) {
    const em::SystemSettingsProto& container(policy.system_settings());
    if (container.has_block_devmode()) {
      policies->Set(key::kDeviceBlockDevmode, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.block_devmode()), nullptr);
    }
  }

  if (policy.has_extension_cache_size()) {
    const em::ExtensionCacheSizeProto& container(policy.extension_cache_size());
    if (container.has_extension_cache_size()) {
      if (auto value = DecodeIntegerValue(container.extension_cache_size())) {
        policies->Set(key::kExtensionCacheSize, POLICY_LEVEL_MANDATORY,
                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                      std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_display_rotation_default()) {
    const em::DisplayRotationDefaultProto& container(
        policy.display_rotation_default());
    if (container.has_display_rotation_default()) {
      if (auto value =
              DecodeIntegerValue(container.display_rotation_default())) {
        policies->Set(key::kDisplayRotationDefault, POLICY_LEVEL_MANDATORY,
                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                      std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_device_display_resolution()) {
    const em::DeviceDisplayResolutionProto& container(
        policy.device_display_resolution());
    if (container.has_device_display_resolution()) {
      SetJsonDevicePolicy(key::kDeviceDisplayResolution,
                          container.device_display_resolution(), policies);
    }
  }

  if (policy.has_usb_detachable_allowlist()) {
    const em::UsbDetachableAllowlistProto& container(
        policy.usb_detachable_allowlist());
    base::Value::List allowlist;
    for (const auto& entry : container.id()) {
      base::Value::Dict ids;
      if (entry.has_vendor_id()) {
        ids.Set("vid", base::StringPrintf("%04X", entry.vendor_id()));
      }
      if (entry.has_product_id()) {
        ids.Set("pid", base::StringPrintf("%04X", entry.product_id()));
      }
      allowlist.Append(std::move(ids));
    }
    policies->Set(key::kUsbDetachableAllowlist, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(allowlist)), nullptr);
  }

  if (policy.has_quirks_download_enabled()) {
    const em::DeviceQuirksDownloadEnabledProto& container(
        policy.quirks_download_enabled());
    if (container.has_quirks_download_enabled()) {
      policies->Set(key::kDeviceQuirksDownloadEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.quirks_download_enabled()), nullptr);
    }
  }

  if (policy.has_device_second_factor_authentication()) {
    const em::DeviceSecondFactorAuthenticationProto& container(
        policy.device_second_factor_authentication());
    if (auto value = DecodeIntegerValue(container.mode())) {
      policies->Set(key::kDeviceSecondFactorAuthentication,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
    }
  }

  if (policy.has_device_off_hours()) {
    auto off_hours_policy =
        off_hours::ConvertOffHoursProtoToValue(policy.device_off_hours());
    if (off_hours_policy) {
      policies->Set(key::kDeviceOffHours, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(std::move(*off_hours_policy)), nullptr);
    }
  }

  if (policy.has_cast_receiver_name()) {
    const em::CastReceiverNameProto& container(policy.cast_receiver_name());
    if (container.has_name()) {
      policies->Set(key::kCastReceiverName, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.name()), nullptr);
    }
  }

  if (policy.has_device_printers_access_mode()) {
    const em::DevicePrintersAccessModeProto& container(
        policy.device_printers_access_mode());
    if (container.has_access_mode()) {
      if (auto value = DecodeIntegerValue(container.access_mode())) {
        policies->Set(key::kDevicePrintersAccessMode, POLICY_LEVEL_MANDATORY,
                      POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                      std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_device_printers_blocklist()) {
    const em::DevicePrintersBlocklistProto& container(
        policy.device_printers_blocklist());
    base::Value::List blocklist;
    for (const auto& entry : container.blocklist()) {
      blocklist.Append(entry);
    }

    policies->Set(key::kDevicePrintersBlocklist, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(blocklist)), nullptr);
  }

  if (policy.has_device_printers_allowlist()) {
    const em::DevicePrintersAllowlistProto& container(
        policy.device_printers_allowlist());
    base::Value::List allowlist;
    for (const auto& entry : container.allowlist()) {
      allowlist.Append(entry);
    }

    policies->Set(key::kDevicePrintersAllowlist, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(allowlist)), nullptr);
  }

  if (policy.has_external_print_servers_allowlist()) {
    const em::DeviceExternalPrintServersAllowlistProto& container(
        policy.external_print_servers_allowlist());
    base::Value::List allowlist;
    for (const auto& entry : container.allowlist()) {
      allowlist.Append(entry);
    }

    policies->Set(key::kDeviceExternalPrintServersAllowlist,
                  POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                  POLICY_SOURCE_CLOUD, base::Value(std::move(allowlist)),
                  nullptr);
  }

  if (policy.has_tpm_firmware_update_settings()) {
    policies->Set(key::kTPMFirmwareUpdateSettings, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  ash::tpm_firmware_update::DecodeSettingsProto(
                      policy.tpm_firmware_update_settings()),
                  nullptr);
  }

  if (policy.has_device_minimum_version()) {
    const em::StringPolicyProto& container(policy.device_minimum_version());
    if (container.has_value()) {
      SetJsonDevicePolicy(key::kDeviceMinimumVersion, container.value(),
                          policies);
    }
  }

  if (policy.has_device_minimum_version_aue_message()) {
    const em::StringPolicyProto& container(
        policy.device_minimum_version_aue_message());
    if (container.has_value()) {
      policies->Set(key::kDeviceMinimumVersionAueMessage,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_unaffiliated_arc_allowed()) {
    const em::UnaffiliatedArcAllowedProto& container(
        policy.unaffiliated_arc_allowed());
    if (container.has_unaffiliated_arc_allowed()) {
      policies->Set(key::kUnaffiliatedArcAllowed, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.unaffiliated_arc_allowed()), nullptr);
    }
  }

  if (policy.has_virtual_machines_allowed()) {
    const em::VirtualMachinesAllowedProto& container(
        policy.virtual_machines_allowed());
    if (container.has_virtual_machines_allowed()) {
      policies->Set(key::kVirtualMachinesAllowed, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.virtual_machines_allowed()), nullptr);
    }
  }

  if (policy.has_device_unaffiliated_crostini_allowed()) {
    const em::DeviceUnaffiliatedCrostiniAllowedProto& container(
        policy.device_unaffiliated_crostini_allowed());
    if (container.has_device_unaffiliated_crostini_allowed()) {
      policies->Set(
          key::kDeviceUnaffiliatedCrostiniAllowed, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.device_unaffiliated_crostini_allowed()),
          nullptr);
    }
  }

  if (policy.has_plugin_vm_allowed()) {
    const em::PluginVmAllowedProto& container(policy.plugin_vm_allowed());
    if (container.has_plugin_vm_allowed()) {
      policies->Set(key::kPluginVmAllowed, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.plugin_vm_allowed()), nullptr);
    }
  }

  if (policy.has_device_wifi_allowed()) {
    const em::DeviceWiFiAllowedProto& container(policy.device_wifi_allowed());
    if (container.has_device_wifi_allowed()) {
      policies->Set(key::kDeviceWiFiAllowed, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.device_wifi_allowed()), nullptr);
    }
  }

  if (policy.has_device_power_peak_shift()) {
    const em::DevicePowerPeakShiftProto& container(
        policy.device_power_peak_shift());
    if (container.has_enabled()) {
      policies->Set(key::kDevicePowerPeakShiftEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.enabled()), nullptr);
    }
    if (container.has_battery_threshold()) {
      policies->Set(key::kDevicePowerPeakShiftBatteryThreshold,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD,
                    base::Value(container.battery_threshold()), nullptr);
    }
    if (container.has_day_configs()) {
      SetJsonDevicePolicy(key::kDevicePowerPeakShiftDayConfig,
                          container.day_configs(), policies);
    }
  }

  if (policy.has_device_boot_on_ac()) {
    const em::DeviceBootOnAcProto& container(policy.device_boot_on_ac());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceBootOnAcEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.enabled()), nullptr);
    }
  }

  if (policy.has_device_dock_mac_address_source() &&
      policy.device_dock_mac_address_source().has_source()) {
    VLOG(2) << "Set dock MAC address source to "
            << policy.device_dock_mac_address_source().source();
    policies->Set(key::kDeviceDockMacAddressSource, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(policy.device_dock_mac_address_source().source()),
                  nullptr);
  } else {
    VLOG(2) << "No dock MAC address source policy: "
            << policy.has_device_dock_mac_address_source() << " "
            << policy.device_dock_mac_address_source().has_source();
  }

  if (policy.has_device_advanced_battery_charge_mode()) {
    const em::DeviceAdvancedBatteryChargeModeProto& container(
        policy.device_advanced_battery_charge_mode());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceAdvancedBatteryChargeModeEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
    if (container.has_day_configs()) {
      SetJsonDevicePolicy(key::kDeviceAdvancedBatteryChargeModeDayConfig,
                          container.day_configs(), policies);
    }
  }

  if (policy.has_device_battery_charge_mode()) {
    const em::DeviceBatteryChargeModeProto& container(
        policy.device_battery_charge_mode());
    if (container.has_battery_charge_mode()) {
      policies->Set(key::kDeviceBatteryChargeMode, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.battery_charge_mode()), nullptr);
    }
    if (container.has_custom_charge_start()) {
      policies->Set(key::kDeviceBatteryChargeCustomStartCharging,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD,
                    base::Value(container.custom_charge_start()), nullptr);
    }
    if (container.has_custom_charge_stop()) {
      policies->Set(key::kDeviceBatteryChargeCustomStopCharging,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD,
                    base::Value(container.custom_charge_stop()), nullptr);
    }
  }

  if (policy.has_device_usb_power_share()) {
    const em::DeviceUsbPowerShareProto& container(
        policy.device_usb_power_share());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceUsbPowerShareEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.enabled()), nullptr);
    }
  }

  if (policy.has_device_login_screen_privacy_screen_enabled()) {
    const em::DeviceLoginScreenPrivacyScreenEnabledProto& container(
        policy.device_login_screen_privacy_screen_enabled());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceLoginScreenPrivacyScreenEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_device_crostini_arc_adb_sideloading_allowed()) {
    const em::DeviceCrostiniArcAdbSideloadingAllowedProto& container(
        policy.device_crostini_arc_adb_sideloading_allowed());
    if (container.has_mode()) {
      if (auto value = DecodeIntegerValue(container.mode())) {
        policies->Set(key::kDeviceCrostiniArcAdbSideloadingAllowed,
                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                      POLICY_SOURCE_CLOUD, std::move(*value), nullptr);
      }
    }
  }

  if (policy.has_device_show_low_disk_space_notification()) {
    const em::DeviceShowLowDiskSpaceNotificationProto& container(
        policy.device_show_low_disk_space_notification());
    if (container.has_device_show_low_disk_space_notification()) {
      policies->Set(
          key::kDeviceShowLowDiskSpaceNotification, POLICY_LEVEL_MANDATORY,
          POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
          base::Value(container.device_show_low_disk_space_notification()),
          nullptr);
    }
  }

  if (policy.has_device_allow_mgs_to_store_display_properties()) {
    const em::BooleanPolicyProto& container(
        policy.device_allow_mgs_to_store_display_properties());
    if (container.has_value()) {
      policies->Set(key::kDeviceAllowMGSToStoreDisplayProperties,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_device_system_wide_tracing_enabled() &&
      policy.device_system_wide_tracing_enabled().has_enabled()) {
    bool enabled = policy.device_system_wide_tracing_enabled().enabled();
    policies->Set(key::kDeviceSystemWideTracingEnabled, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(enabled), nullptr);
  } else {
    // Set policy default to false if the policy is unset.
    policies->Set(key::kDeviceSystemWideTracingEnabled, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_ENTERPRISE_DEFAULT,
                  base::Value(false), nullptr);
  }

  if (policy.has_device_pci_peripheral_data_access_enabled_v2()) {
    const em::DevicePciPeripheralDataAccessEnabledProtoV2& container(
        policy.device_pci_peripheral_data_access_enabled_v2());
    if (container.has_enabled()) {
      policies->Set(key::kDevicePciPeripheralDataAccessEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_device_i18n_shortcuts_enabled()) {
    const em::DeviceI18nShortcutsEnabledProto& container(
        policy.device_i18n_shortcuts_enabled());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceI18nShortcutsEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.enabled()), nullptr);
    }
  }

  if (policy.has_device_allowed_bluetooth_services()) {
    const em::DeviceAllowedBluetoothServicesProto& container(
        policy.device_allowed_bluetooth_services());
    base::Value::List allowlist;
    for (const auto& entry : container.allowlist()) {
      allowlist.Append(entry);
    }
    policies->Set(key::kDeviceAllowedBluetoothServices, POLICY_LEVEL_MANDATORY,
                  POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                  base::Value(std::move(allowlist)), nullptr);
  }

  if (policy.has_device_scheduled_reboot()) {
    const em::DeviceScheduledRebootProto& container(
        policy.device_scheduled_reboot());
    if (container.has_device_scheduled_reboot_settings()) {
      SetJsonDevicePolicy(key::kDeviceScheduledReboot,
                          container.device_scheduled_reboot_settings(),
                          policies);
    }
  }

  if (policy.has_device_restricted_managed_guest_session_enabled()) {
    const em::DeviceRestrictedManagedGuestSessionEnabledProto& container(
        policy.device_restricted_managed_guest_session_enabled());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceRestrictedManagedGuestSessionEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }
  if (policy.has_login_web_ui_lazy_loading()) {
    const em::DeviceLoginScreenWebUILazyLoadingProto& container(
        policy.login_web_ui_lazy_loading());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceLoginScreenWebUILazyLoading,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_keylocker_for_storage_encryption_enabled()) {
    const em::DeviceKeylockerForStorageEncryptionEnabledProto& container(
        policy.keylocker_for_storage_encryption_enabled());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceKeylockerForStorageEncryptionEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_device_run_automatic_cleanup_on_login()) {
    const em::BooleanPolicyProto& container(
        policy.device_run_automatic_cleanup_on_login());
    if (container.has_value()) {
      policies->Set(key::kDeviceRunAutomaticCleanupOnLogin,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_device_encrypted_reporting_pipeline_enabled()) {
    const em::EncryptedReportingPipelineConfigurationProto& container(
        policy.device_encrypted_reporting_pipeline_enabled());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceEncryptedReportingPipelineEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_device_printing_client_name_template()) {
    const em::StringPolicyProto& container(
        policy.device_printing_client_name_template());
    if (container.has_value() && !container.value().empty()) {
      policies->Set(key::kDevicePrintingClientNameTemplate,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_device_report_xdr_events()) {
    const em::DeviceReportXDREventsProto& container(
        policy.device_report_xdr_events());
    if (container.has_enabled()) {
      policies->Set(policy::key::kDeviceReportXDREvents, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.enabled()), nullptr);
    }
  }

  if (policy.has_device_low_battery_sound()) {
    const em::DeviceLowBatterySoundProto& container(
        policy.device_low_battery_sound());
    if (container.has_enabled()) {
      policies->Set(policy::key::kDeviceLowBatterySoundEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_device_charging_sounds()) {
    const em::DeviceChargingSoundsProto& container(
        policy.device_charging_sounds());
    if (container.has_enabled()) {
      policies->Set(policy::key::kDeviceChargingSoundsEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_device_switch_function_keys_behavior_enabled()) {
    const em::DeviceSwitchFunctionKeysBehaviorEnabledProto& container(
        policy.device_switch_function_keys_behavior_enabled());
    if (container.has_enabled()) {
      policies->Set(policy::key::kDeviceSwitchFunctionKeysBehaviorEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_device_dlc_predownload_list()) {
    SetDeviceDlcPredownloadListPolicy(
        policy.device_dlc_predownload_list().value().entries(), policies);
  }

  if (policy.has_device_flex_hw_data_for_product_improvement_enabled()) {
    const em::DeviceFlexHwDataForProductImprovementEnabledProto& container(
        policy.device_flex_hw_data_for_product_improvement_enabled());
    if (container.has_enabled()) {
      policies->Set(key::kDeviceFlexHwDataForProductImprovementEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.enabled()),
                    nullptr);
    }
  }

  if (policy.has_devicehardwarevideodecodingenabled()) {
    const em::BooleanPolicyProto& container(
        policy.devicehardwarevideodecodingenabled());
    if (container.has_value()) {
      policies->Set(key::kDeviceHardwareVideoDecodingEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_deviceloginscreentouchvirtualkeyboardenabled()) {
    const em::BooleanPolicyProto& container(
        policy.deviceloginscreentouchvirtualkeyboardenabled());
    if (container.has_value()) {
      policies->Set(key::kTouchVirtualKeyboardEnabled, POLICY_LEVEL_MANDATORY,
                    POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
                    base::Value(container.value()), nullptr);
    }
  }

  if (policy.has_deviceextensionssystemlogenabled()) {
    const em::BooleanPolicyProto& container(
        policy.deviceextensionssystemlogenabled());
    if (container.has_value()) {
      policies->Set(key::kDeviceExtensionsSystemLogEnabled,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_deviceallowenterpriseremoteaccessconnections()) {
    const em::BooleanPolicyProto& container(
        policy.deviceallowenterpriseremoteaccessconnections());
    if (container.has_value()) {
      policies->Set(key::kDeviceAllowEnterpriseRemoteAccessConnections,
                    POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                    POLICY_SOURCE_CLOUD, base::Value(container.value()),
                    nullptr);
    }
  }

  if (policy.has_devicerestrictionschedule()) {
    const em::StringPolicyProto& container(policy.devicerestrictionschedule());
    if (container.has_value()) {
      SetJsonDevicePolicy(key::kDeviceRestrictionSchedule, container.value(),
                          policies);
    }
  }
}

// TODO(b/324221325): Move other Kiosk-related policies to this function.
void DecodeKioskPolicies(const em::ChromeDeviceSettingsProto& policy,
                         PolicyMap* policies) {
  if (policy.has_deviceweeklyscheduledsuspend()) {
    const em::StringPolicyProto& container(
        policy.deviceweeklyscheduledsuspend());
    if (container.has_value()) {
      SetJsonDevicePolicy(key::kDeviceWeeklyScheduledSuspend, container.value(),
                          policies);
    }
  }
}

}  // namespace

DecodeJsonResult::DecodeJsonResult(base::Value decoded_json,
                                   std::optional<std::string> non_fatal_errors)
    : decoded_json(std::move(decoded_json)),
      non_fatal_errors(std::move(non_fatal_errors)) {}

DecodeJsonResult::DecodeJsonResult(DecodeJsonResult&& other) = default;
DecodeJsonResult& DecodeJsonResult::operator=(DecodeJsonResult&& other) =
    default;

DecodeJsonResult::~DecodeJsonResult() = default;

base::expected<DecodeJsonResult, DecodeJsonError> DecodeJsonStringAndNormalize(
    const std::string& json_string,
    const std::string& policy_name) {
  ASSIGN_OR_RETURN(auto parsed_json,
                   base::JSONReader::ReadAndReturnValueWithError(
                       json_string, base::JSON_ALLOW_TRAILING_COMMAS),
                   [](base::JSONReader::Error error) {
                     return "Invalid JSON string: " + std::move(error).message;
                   });

  const Schema& schema = GetChromeSchema().GetKnownProperty(policy_name);
  CHECK(schema.valid());

  std::string schema_error;
  PolicyErrorPath error_path;
  bool changed = false;
  if (!schema.Normalize(&parsed_json, SCHEMA_ALLOW_UNKNOWN, &error_path,
                        &schema_error, &changed)) {
    std::ostringstream msg;
    msg << "Invalid policy value: " << schema_error << " (at "
        << (error_path.empty()
                ? policy_name
                : policy::ErrorPathToString(policy_name, error_path))
        << ")";
    return base::unexpected(msg.str());
  }

  if (changed) {
    std::ostringstream msg;
    msg << "Dropped unknown properties: " << schema_error << " (at "
        << (error_path.empty()
                ? policy_name
                : policy::ErrorPathToString(policy_name, error_path))
        << ")";
    return base::ok(DecodeJsonResult(/*decoded_json=*/std::move(parsed_json),
                                     /*non_fatal_errors=*/msg.str()));
  }

  return base::ok(DecodeJsonResult(/*decoded_json=*/std::move(parsed_json),
                                   /*non_fatal_errors=*/std::nullopt));
}

void DecodeDevicePolicy(
    const em::ChromeDeviceSettingsProto& policy,
    base::WeakPtr<ExternalDataManager> external_data_manager,
    PolicyMap* policies) {
  // Decode the various groups of policies.
  DecodeLoginPolicies(policy, policies);
  DecodeDeviceLocalAccountsPolicy(policy, policies);
  DecodeNetworkPolicies(policy, policies);
  DecodeReportingPolicies(policy, policies);
  DecodeAutoUpdatePolicies(policy, policies);
  DecodeAccessibilityPolicies(policy, policies);
  DecodeExternalDataPolicies(policy, external_data_manager, policies);
  DecodeKioskPolicies(policy, policies);
  DecodeGenericPolicies(policy, policies);
}

}  // namespace policy