1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/update_client/protocol_serializer_json.h"
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
11 #include "base/json/json_writer.h"
12 #include "base/values.h"
13 #include "build/branding_buildflags.h"
14 #include "build/build_config.h"
15 #include "components/update_client/updater_state.h"
16
17 namespace update_client {
18
19 using Value = base::Value;
20
Serialize(const protocol_request::Request & request) const21 std::string ProtocolSerializerJSON::Serialize(
22 const protocol_request::Request& request) const {
23 Value root_node(Value::Type::DICTIONARY);
24 auto* request_node =
25 root_node.SetKey("request", Value(Value::Type::DICTIONARY));
26 request_node->SetKey("protocol", Value(request.protocol_version));
27 request_node->SetKey("dedup", Value("cr"));
28 request_node->SetKey("acceptformat", Value("crx2,crx3"));
29 if (!request.additional_attributes.empty()) {
30 for (const auto& attr : request.additional_attributes)
31 request_node->SetKey(attr.first, Value(attr.second));
32 }
33 request_node->SetKey("sessionid", Value(request.session_id));
34 request_node->SetKey("requestid", Value(request.request_id));
35 request_node->SetKey("@updater", Value(request.updatername));
36 request_node->SetKey("prodversion", Value(request.updaterversion));
37 request_node->SetKey("updaterversion", Value(request.prodversion));
38 request_node->SetKey("lang", Value(request.lang));
39 request_node->SetKey("@os", Value(request.operating_system));
40 request_node->SetKey("arch", Value(request.arch));
41 request_node->SetKey("nacl_arch", Value(request.nacl_arch));
42 #if defined(OS_WIN)
43 if (request.is_wow64)
44 request_node->SetKey("wow64", Value(request.is_wow64));
45 #endif // OS_WIN
46 if (!request.updaterchannel.empty())
47 request_node->SetKey("updaterchannel", Value(request.updaterchannel));
48 if (!request.prodchannel.empty())
49 request_node->SetKey("prodchannel", Value(request.prodchannel));
50 if (!request.dlpref.empty())
51 request_node->SetKey("dlpref", Value(request.dlpref));
52 if (request.domain_joined) {
53 request_node->SetKey(UpdaterState::kIsEnterpriseManaged,
54 Value(*request.domain_joined));
55 }
56
57 // HW platform information.
58 auto* hw_node = request_node->SetKey("hw", Value(Value::Type::DICTIONARY));
59 hw_node->SetKey("physmemory", Value(static_cast<int>(request.hw.physmemory)));
60
61 // OS version and platform information.
62 auto* os_node = request_node->SetKey("os", Value(Value::Type::DICTIONARY));
63 os_node->SetKey("platform", Value(request.os.platform));
64 os_node->SetKey("arch", Value(request.os.arch));
65 if (!request.os.version.empty())
66 os_node->SetKey("version", Value(request.os.version));
67 if (!request.os.service_pack.empty())
68 os_node->SetKey("sp", Value(request.os.service_pack));
69
70 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
71 if (request.updater) {
72 const auto& updater = *request.updater;
73 auto* updater_node =
74 request_node->SetKey("updater", Value(Value::Type::DICTIONARY));
75 updater_node->SetKey("name", Value(updater.name));
76 updater_node->SetKey("ismachine", Value(updater.is_machine));
77 updater_node->SetKey("autoupdatecheckenabled",
78 Value(updater.autoupdate_check_enabled));
79 updater_node->SetKey("updatepolicy", Value(updater.update_policy));
80 if (!updater.version.empty())
81 updater_node->SetKey("version", Value(updater.version));
82 if (updater.last_checked)
83 updater_node->SetKey("lastchecked", Value(*updater.last_checked));
84 if (updater.last_started)
85 updater_node->SetKey("laststarted", Value(*updater.last_started));
86 }
87 #endif
88
89 std::vector<Value> app_nodes;
90 for (const auto& app : request.apps) {
91 Value app_node(Value::Type::DICTIONARY);
92 app_node.SetKey("appid", Value(app.app_id));
93 app_node.SetKey("version", Value(app.version));
94 if (!app.brand_code.empty())
95 app_node.SetKey("brand", Value(app.brand_code));
96 if (!app.install_source.empty())
97 app_node.SetKey("installsource", Value(app.install_source));
98 if (!app.install_location.empty())
99 app_node.SetKey("installedby", Value(app.install_location));
100 if (!app.cohort.empty())
101 app_node.SetKey("cohort", Value(app.cohort));
102 if (!app.cohort_name.empty())
103 app_node.SetKey("cohortname", Value(app.cohort_name));
104 if (!app.cohort_hint.empty())
105 app_node.SetKey("cohorthint", Value(app.cohort_hint));
106 if (app.enabled)
107 app_node.SetKey("enabled", Value(*app.enabled));
108
109 if (app.disabled_reasons && !app.disabled_reasons->empty()) {
110 std::vector<Value> disabled_nodes;
111 for (const int disabled_reason : *app.disabled_reasons) {
112 Value disabled_node(Value::Type::DICTIONARY);
113 disabled_node.SetKey("reason", Value(disabled_reason));
114 disabled_nodes.push_back(std::move(disabled_node));
115 }
116 app_node.SetKey("disabled", Value(disabled_nodes));
117 }
118
119 for (const auto& attr : app.installer_attributes)
120 app_node.SetKey(attr.first, Value(attr.second));
121
122 if (app.update_check) {
123 auto* update_check_node =
124 app_node.SetKey("updatecheck", Value(Value::Type::DICTIONARY));
125 if (app.update_check->is_update_disabled)
126 update_check_node->SetKey("updatedisabled", Value(true));
127 }
128
129 if (app.ping) {
130 const auto& ping = *app.ping;
131 auto* ping_node = app_node.SetKey("ping", Value(Value::Type::DICTIONARY));
132 if (!ping.ping_freshness.empty())
133 ping_node->SetKey("ping_freshness", Value(ping.ping_freshness));
134
135 // Output "ad" or "a" only if the this app has been seen 'active'.
136 if (ping.date_last_active) {
137 ping_node->SetKey("ad", Value(*ping.date_last_active));
138 } else if (ping.days_since_last_active_ping) {
139 ping_node->SetKey("a", Value(*ping.days_since_last_active_ping));
140 }
141
142 // Output "rd" if valid or "r" as a last resort roll call metric.
143 if (ping.date_last_roll_call)
144 ping_node->SetKey("rd", Value(*ping.date_last_roll_call));
145 else
146 ping_node->SetKey("r", Value(ping.days_since_last_roll_call));
147 }
148
149 if (!app.fingerprint.empty()) {
150 std::vector<Value> package_nodes;
151 Value package(Value::Type::DICTIONARY);
152 package.SetKey("fp", Value(app.fingerprint));
153 package_nodes.push_back(std::move(package));
154 auto* packages_node =
155 app_node.SetKey("packages", Value(Value::Type::DICTIONARY));
156 packages_node->SetKey("package", Value(package_nodes));
157 }
158
159 if (app.events) {
160 std::vector<Value> event_nodes;
161 for (const auto& event : *app.events) {
162 DCHECK(event.is_dict());
163 DCHECK(!event.DictEmpty());
164 event_nodes.push_back(event.Clone());
165 }
166 app_node.SetKey("event", Value(event_nodes));
167 }
168
169 app_nodes.push_back(std::move(app_node));
170 }
171
172 if (!app_nodes.empty())
173 request_node->SetKey("app", Value(std::move(app_nodes)));
174
175 std::string msg;
176 return base::JSONWriter::WriteWithOptions(
177 root_node, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
178 &msg)
179 ? msg
180 : std::string();
181 }
182
183 } // namespace update_client
184