blob: 89fd7c08d4c5bba7d46327652b6908a191ce4083 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/update_client/protocol_serializer_json.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/json/json_writer.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/update_client/updater_state.h"
namespace update_client {
using Value = base::Value;
std::string ProtocolSerializerJSON::Serialize(
const protocol_request::Request& request) const {
Value root_node(Value::Type::DICTIONARY);
auto* request_node =
root_node.SetKey("request", Value(Value::Type::DICTIONARY));
request_node->SetKey("protocol", Value(request.protocol_version));
request_node->SetKey("dedup", Value("cr"));
request_node->SetKey("acceptformat", Value("crx2,crx3"));
if (!request.additional_attributes.empty()) {
for (const auto& attr : request.additional_attributes)
request_node->SetKey(attr.first, Value(attr.second));
}
request_node->SetKey("sessionid", Value(request.session_id));
request_node->SetKey("requestid", Value(request.request_id));
request_node->SetKey("@updater", Value(request.updatername));
request_node->SetKey("prodversion", Value(request.updaterversion));
request_node->SetKey("updaterversion", Value(request.prodversion));
request_node->SetKey("lang", Value(request.lang));
request_node->SetKey("@os", Value(request.operating_system));
request_node->SetKey("arch", Value(request.arch));
request_node->SetKey("nacl_arch", Value(request.nacl_arch));
#if defined(OS_WIN)
if (request.is_wow64)
request_node->SetKey("wow64", Value(request.is_wow64));
#endif // OS_WIN
if (!request.updaterchannel.empty())
request_node->SetKey("updaterchannel", Value(request.updaterchannel));
if (!request.prodchannel.empty())
request_node->SetKey("prodchannel", Value(request.prodchannel));
if (!request.dlpref.empty())
request_node->SetKey("dlpref", Value(request.dlpref));
if (request.domain_joined) {
request_node->SetKey(UpdaterState::kIsEnterpriseManaged,
Value(*request.domain_joined));
}
// HW platform information.
auto* hw_node = request_node->SetKey("hw", Value(Value::Type::DICTIONARY));
hw_node->SetKey("physmemory", Value(static_cast<int>(request.hw.physmemory)));
// OS version and platform information.
auto* os_node = request_node->SetKey("os", Value(Value::Type::DICTIONARY));
os_node->SetKey("platform", Value(request.os.platform));
os_node->SetKey("arch", Value(request.os.arch));
if (!request.os.version.empty())
os_node->SetKey("version", Value(request.os.version));
if (!request.os.service_pack.empty())
os_node->SetKey("sp", Value(request.os.service_pack));
#if defined(GOOGLE_CHROME_BUILD)
if (request.updater) {
const auto& updater = *request.updater;
auto* updater_node =
request_node->SetKey("updater", Value(Value::Type::DICTIONARY));
updater_node->SetKey("name", Value(updater.name));
updater_node->SetKey("ismachine", Value(updater.is_machine));
updater_node->SetKey("autoupdatecheckenabled",
Value(updater.autoupdate_check_enabled));
updater_node->SetKey("updatepolicy", Value(updater.update_policy));
if (!updater.version.empty())
updater_node->SetKey("version", Value(updater.version));
if (updater.last_checked)
updater_node->SetKey("lastchecked", Value(*updater.last_checked));
if (updater.last_started)
updater_node->SetKey("laststarted", Value(*updater.last_started));
}
#endif
std::vector<Value> app_nodes;
for (const auto& app : request.apps) {
Value app_node(Value::Type::DICTIONARY);
app_node.SetKey("appid", Value(app.app_id));
app_node.SetKey("version", Value(app.version));
if (!app.brand_code.empty())
app_node.SetKey("brand", Value(app.brand_code));
if (!app.install_source.empty())
app_node.SetKey("installsource", Value(app.install_source));
if (!app.install_location.empty())
app_node.SetKey("installedby", Value(app.install_location));
if (!app.cohort.empty())
app_node.SetKey("cohort", Value(app.cohort));
if (!app.cohort_name.empty())
app_node.SetKey("cohortname", Value(app.cohort_name));
if (!app.cohort_hint.empty())
app_node.SetKey("cohorthint", Value(app.cohort_hint));
if (app.enabled)
app_node.SetKey("enabled", Value(*app.enabled));
if (app.disabled_reasons && !app.disabled_reasons->empty()) {
std::vector<Value> disabled_nodes;
for (const int disabled_reason : *app.disabled_reasons) {
Value disabled_node(Value::Type::DICTIONARY);
disabled_node.SetKey("reason", Value(disabled_reason));
disabled_nodes.push_back(std::move(disabled_node));
}
app_node.SetKey("disabled", Value(disabled_nodes));
}
for (const auto& attr : app.installer_attributes)
app_node.SetKey(attr.first, Value(attr.second));
if (app.update_check) {
auto* update_check_node =
app_node.SetKey("updatecheck", Value(Value::Type::DICTIONARY));
if (app.update_check->is_update_disabled)
update_check_node->SetKey("updatedisabled", Value(true));
}
if (app.ping) {
const auto& ping = *app.ping;
auto* ping_node = app_node.SetKey("ping", Value(Value::Type::DICTIONARY));
if (!ping.ping_freshness.empty())
ping_node->SetKey("ping_freshness", Value(ping.ping_freshness));
// Output "ad" or "a" only if the this app has been seen 'active'.
if (ping.date_last_active) {
ping_node->SetKey("ad", Value(*ping.date_last_active));
} else if (ping.days_since_last_active_ping) {
ping_node->SetKey("a", Value(*ping.days_since_last_active_ping));
}
// Output "rd" if valid or "r" as a last resort roll call metric.
if (ping.date_last_roll_call)
ping_node->SetKey("rd", Value(*ping.date_last_roll_call));
else
ping_node->SetKey("r", Value(ping.days_since_last_roll_call));
}
if (!app.fingerprint.empty()) {
std::vector<Value> package_nodes;
Value package(Value::Type::DICTIONARY);
package.SetKey("fp", Value(app.fingerprint));
package_nodes.push_back(std::move(package));
auto* packages_node =
app_node.SetKey("packages", Value(Value::Type::DICTIONARY));
packages_node->SetKey("package", Value(package_nodes));
}
if (app.events) {
std::vector<Value> event_nodes;
for (const auto& event : *app.events) {
DCHECK(event.is_dict());
DCHECK(!event.DictEmpty());
event_nodes.push_back(event.Clone());
}
app_node.SetKey("event", Value(event_nodes));
}
app_nodes.push_back(std::move(app_node));
}
if (!app_nodes.empty())
request_node->SetKey("app", Value(std::move(app_nodes)));
std::string msg;
return base::JSONWriter::WriteWithOptions(
root_node, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
&msg)
? msg
: std::string();
}
} // namespace update_client